2015-03-10 1 views
4

imp.find_module() не находит модули из застегнутых на молнию яиц.imp.find_module(), который поддерживает застежки-молнии

Как можно найти модулей, которые могут исходить из обоих мест: каталогов или яиц? В моем случае важно, чтобы я мог предоставить аргумент path, например imp.find_module().

фон

Как-то пакеты получить установлен дважды в нашей среде. Как застежка-молния и как обычные файлы. Я хочу написать чек, который говорит мне, если модуль установлен дважды. См. https://stackoverflow.com/a/23990989/633961

+0

Что делать, если ваш модуль находится глубоко внутри иерархии пакетов внутри архивного яйца? Какой путь вы хотите в этом случае? Там * * * файл, не эквивалентный тому, который вы запросили. – Kevin

+0

@Kevin imp.find_module() только находит модули «toplevel». Например, вы можете найти «os», но вы не можете найти «путь» (например, «os.path»). Я просто хочу, чтобы find_module() работал так же, как и оператор import интерпретатора python. Переводчик загружает застрявшие яйца. – guettli

+0

Механизм импорта в 2.x не полностью открыт. Под 3.x вы можете получить то, что хотите, с помощью 'importlib'; 'imp' устарел. К сожалению, это также означает, что все это существенно сложнее, чем когда-либо. – Kevin

ответ

5

Предполагая, что Python 2, информация, которая, как мне кажется, вам нужна, находится в PEP 302 - New Import Hooks (PEP устарел для Python 3, что совершенно другое в этом отношении).

Поиск и импорт модулей из архивов ZIP осуществляется в zipimport, который «подключен» к механизму импорта, как описано PEP. Когда PEP 302 и импорт из ZIPs были добавлены в Python, модули imp не были адаптированы, то есть imp полностью не знает крючки PEP 302.

А «общий» find_module функция, которая находит модули, как imp делает и уважает PEP 302 крючков, будет примерно выглядеть следующим образом:

import imp 
import sys 

def find_module(fullname, path=None): 
    try: 
     # 1. Try imp.find_module(), which searches sys.path, but does 
     # not respect PEP 302 import hooks. 
     result = imp.find_module(fullname, path) 
     if result: 
      return result 
    except ImportError: 
     pass 
    if path is None: 
     path = sys.path 
    for item in path: 
     # 2. Scan path for import hooks. sys.path_importer_cache maps 
     # path items to optional "importer" objects, that implement 
     # find_module() etc. Note that path must be a subset of 
     # sys.path for this to work. 
     importer = sys.path_importer_cache.get(item) 
     if importer: 
      try: 
       result = importer.find_module(fullname, [item]) 
       if result: 
        return result 
      except ImportError: 
       pass 
    raise ImportError("%s not found" % fullname) 

if __name__ == "__main__": 
    # Provide a simple CLI for `find_module` above. 
    import argparse 
    parser = argparse.ArgumentParser() 
    parser.add_argument("-p", "--path", action="append") 
    parser.add_argument("modname", nargs='+') 
    args = parser.parse_args() 
    for name in args.modname: 
     print find_module(name, args.path) 

Примечание, однако, что результат от нахождения модуля в ZIP-архив выглядит совсем не так, как возвращается imp.find_module: вы получите объект zipimport.zipimporter для конкретного ZIP. Литт программа выше печатает следующее, когда его спросили, чтобы найти правильный модуль, встроенный в модуль и модуль из архивированного яйца:

$ python find_module.py grin os sys 
<zipimporter object "<my venv>/lib/python2.7/site-packages/grin-1.2.1-py2.7.egg"> 
(<open file '<my venv>/lib/python2.7/os.py', mode 'U' at 0x10a0bbf60>, '<my venv>/lib/python2.7/os.py', ('.py', 'U', 1)) 
(None, 'sys', ('', '', 6)) 
+0

Вызов importer.find_module (fullname) не передает аргумент 'path'. Это приводит к возврату ложных результатов, если путь не sys.path – guettli

+0

Я использую это сейчас: http://stackoverflow.com/questions/23697497/pip-installs-package-twice – guettli

+0

Я обновил код. Теперь он будет правильно чтить «путь». Я хотел объяснить, что происходит. – fpbhb