Определение, является ли данный модуль Python встроенным модулем - PullRequest
17 голосов
/ 07 февраля 2011

Я занимаюсь разбором и анализом различных модулей, но не хочу разбирать встроенные модули. Теперь нет специального типа для встроенных модулей, как types.BuiltinFunctionType, так как мне это сделать?

>>> import CornedBeef
>>> CornedBeef
<module 'CornedBeef' from '/meatish/CornedBeef.pyc'>
>>> CornedBeef.__file__
'/meatish/CornedBeef.pyc'
>>> del CornedBeef.__file__
>>> CornedBeef
<module 'CornedBeef' (built-in)>

Согласно Python, модуль, очевидно, является встроенным, если у него нет атрибута __file__. Значит ли это, что hasattr(SomeModule, '__file__') - это способ проверить, встроен ли модуль? Конечно, это не совсем обычный del SomeModule.__file__, но есть ли более надежный способ определить, является ли модуль встроенным?

Ответы [ 4 ]

7 голосов
/ 08 февраля 2011

sys.builtin_module_names

Кортеж строк, содержащих имена всех модулей, которые скомпилированы в этот интерпретатор Python.(Эта информация недоступна для других целей - modules.keys () отображает только импортированные модули.)

3 голосов
/ 07 февраля 2011

Вы можете использовать imp.is_builtin, чтобы увидеть, совпадает ли имя модуля со встроенным модулем, но я не могу придумать, как реально надежно исследовать объект модуля.

Вы также можете попробовать следующее:

>>> import imp
>>> f, path, desc = imp.find_module("sys")
>>> desc
('', '', 6)
>>> desc[2] == imp.C_BUILTIN
True
2 голосов
/ 15 мая 2016

Если вы считаете это просто вопросом builtins, то принятый ответ, очевидно, является правильным.

В моем случае я также искал стандартную библиотеку, под которой я имею в виду список всех импортируемых модулей, поставляемых с данным дистрибутивом Python. Вопросы об этом задавались несколько раз, но я не мог найти ответ, который включал бы все, что я искал.

Мой вариант использования заключался в произвольном x в выражении Python import x как:

  • входит в состав Python stdlib + встроенные модули
  • установлен как сторонний модуль
  • ни

Это будет работать для virtualenvs или глобальной установки. Он запрашивает распределение любого двоичного файла Python, в котором выполняется скрипт. Последний кусок действительно выходит за пределы виртуальности, но я считаю, что желаемое поведение.

# You may need to use setuptools.distutils depending on Python distribution.
import distutils
import glob
import os
import pkgutil
import sys    

def get_python_library():

    # Get list of the loaded source modules on sys.path.
    modules = { 
        module
        for _, module, package in list(pkgutil.iter_modules())
        if package is False
    }

    # Glob all the 'top_level.txt' files installed under site-packages.
    site_packages = glob.iglob(os.path.join(os.path.dirname(os.__file__) 
                    + '/site-packages', '*-info', 'top_level.txt'))

    # Read the files for the import names and remove them from the modules list.
    modules -= {open(txt).read().strip() for txt in site_packages}

    # Get the system packages.
    system_modules = set(sys.builtin_module_names)

    # Get the just the top-level packages from the python install.
    python_root = distutils.sysconfig.get_python_lib(standard_lib=True)
      _, top_level_libs, _ = list(os.walk(python_root))[0]

    return sorted(top_level_libs + list(modules | system_modules))

Возвращает

Сортированный список импорта: [..., 'imaplib', 'imghdr', 'imp', 'importlib', 'imputil', 'inspect', 'io', ...]

Объяснение

Я разбил его на куски, так что причина, по которой нужна каждая группа, может быть понятна.

  • modules

    • Вызов pkgutil.iter_modules сканирует все загруженные модули на sys.path и возвращает генератор (module_loader, name, ispkg) кортежей.
    • Я превращаю его в набор и отфильтровываю пакеты, так как здесь мы заботимся только об исходных модулях.
  • site_packages

    • Получить список всех установленных пакетов в обычном каталоге site-packages и удалить их из списка modules. Это примерно соответствует сторонним разработчикам.
    • Это была самая трудная часть, чтобы получить право. Многие вещи почти работали, как pip.get_installed_distributions или site. Но pip возвращает имена модулей как они есть в PyPi, а не как при импорте в исходный файл. Некоторые патологические пакеты будут проскальзывать через трещины, например:
      • requests-futures, который импортируется как requests_futures.
      • colors, который на самом деле ansicolors на PyPi и, таким образом, смешивает любую разумную эвристику.
    • Я уверен, что есть определенные мало используемые модули, которые не включают top_level.txt в свой пакет. Но это покрывает 100% моих случаев использования, кажется, работает на всем, что правильно настроено.
  • system_modules

    • Если вы явно не попросите их, вы не получите эти системные модули, такие как sys, gc, errno и некоторые другие дополнительные модули .
  • top_level_libs

    • Вызов distutils.sysconfig.get_python_lib(standard_lib=True) возвращает каталог верхнего уровня независимой от платформы стандартной библиотеки.
    • Их легко пропустить, потому что они могут не жить по тому же пути Python, что и другие модули. Если вы используете OSX и используете virtualenv, эти модули будут фактически импортированы из системной установки. Эти модули включают в себя email, logging, xml и еще несколько.

Заключение

Для моего MacBookPro 2013 года я нашел 403 модуля для установки python2.7.

   >>> print(sys.version)
   2.7.10 (default, Jul 13 2015, 12:05:58)
   [GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)]
   >>> print(sys.hexversion)
   34015984
   >>> python_stdlib = get_python_libirary()
   >>> len(python_stdlib)
   403

Я выложил суть кода и вывел . Если вы считаете, что я пропускаю урок или включил фиктивный модуль, я хотел бы услышать об этом.

* Альтернативы

  • При написании этого поста я копался в API pip и setuptools. Вполне возможно, что эта информация через один модуль, но вам действительно нужно знать, как обойти этот API.

  • Перед тем, как я начал это, мне сказали, что six имеет функцию специально для этой проблемы. Есть смысл, что он может существовать, но я сам не смог его найти.

2 голосов
/ 07 февраля 2011

Когда вы говорите «встроенный», вы имеете в виду, написанный на С или часть стандартной библиотеки? Если вы имеете в виду первое, то поиск __file__ является правильным решением. Как видите, даже интерпретатор Python использует наличие __file__ в качестве индикатора встроенного состояния.

Если вы имеете в виду «часть стандартной библиотеки», то это очень трудно определить.

...