2016-02-14 4 views
0

Я пытаюсь динамически импортировать модули Python, которые соответствуют шаблону во время выполнения. Модули расположены внутри пакета Python.Проблемы с pkgutil.iter_modules() в Windows

Функция я использую, чтобы найти модули является:

def load_modules_from_dir(dirname, pattern=""): 
    modules = [] 
    for importer, package_name, _ in pkgutil.iter_modules([dirname]): 
     if re.search(pattern, package_name): 
      full_package_name = '%s.%s' % (dirname, package_name) 
      if full_package_name not in sys.modules: 
       module = importer.find_module(package_name).load_module(full_package_name) 
       modules.append(module) 
    return modules 

Я называю это следующим образом:

module_dir = os.path.join(os.path.dirname(__file__)) 
modules = utils.load_modules_from_dir(module_dir, "jscal$") 

В Linux находит все модули, но на Windows, он не находит ни одного модулей вообще. Если я напечатаю dirname в функции load_modules_from_dir, я получаю: H:\temp\linx\dist\calibrate\dcljscal

Я воспроизвел его в оболочке Python на Windows и прибил его к разделителю пути. Следующие ничего не находит:

>>> for x in pkgutil.iter_modules(['H:\temp\linx\dist\calibrate\dcljscal']):print x 
... 
>>> 

Если я заменить разделитель пути для Windows с Linux один, он работает:

>>> for x in pkgutil.iter_modules(['H:/temp/linx/dist/calibrate/dcljscal']):print x 
... 
(<pkgutil.ImpImporter instance at 0x00AD9C60>, 'demojscal', True) 
(<pkgutil.ImpImporter instance at 0x00AD9C60>, 'dx2cremjscal', True) 
(<pkgutil.ImpImporter instance at 0x00AD9C60>, 'linxjscal', True) 
>>> 

Это также работает, если я заменю \ с \\, в основном спасаясь разделитель пути для Windows :

>>> for x in pkgutil.iter_modules(['H:\\temp\\linx\\dist\\calibrate\\dcljscal']):print x 
... 
(<pkgutil.ImpImporter instance at 0x00AD9E68>, 'demojscal', True) 
(<pkgutil.ImpImporter instance at 0x00AD9E68>, 'dx2cremjscal', True) 
(<pkgutil.ImpImporter instance at 0x00AD9E68>, 'linxjscal', True) 
>>> 

кажется, что путь, порожденный os.path.join(os.path.dirname(__file__)) не является портативным.
Я бы ожидал, что os.path.join() дал бы мне правильный путь, который я могу использовать без изменений в pkgutil.iter_modules(). Что я здесь делаю неправильно?

Я использую Python 2.7.11 для Windows XP.

+0

Не смотря на '' \ t'', вы не поднимаете никаких тревог для вас? – eryksun

+0

@eryksun Да, вы правы.Если я заменю '\ t' на' \\ t', он также будет работать в оболочке Python. Но вы заставили меня задуматься. Путь, возвращаемый 'os.path.join()', должен уже содержать экранированную версию пути. Когда я печатаю параметр 'dirname' в функции' load_modules_from_dir', я получаю: 'H: \ temp \ linx \ dist \ calibrate \ dcljscal', а не' H: emp \ linx \ dist \ calibrate \ dcljscal'. Теперь вопрос в том, почему он не работает в 'pkgutil.iter_modules()'? – NZD

+0

'os.path.join (os.path.dirname (__ file __))' не имеет смысла. Используйте 'os.path.abspath (os.path.dirname (__ file __))'. – eryksun

ответ

0

Короткий ответ: ответа на эту проблему нет. Строки, представляющие имена путей, всегда могут содержать специальные символы, которые могут вас укусить в любое время.

Существует много сообщений SE, которые пытаются дать решение. Большинство из них фиксируют специальный случай и вообще не работают. Консенсуса относительно наилучшего подхода нет. См:
- Unpredictable results from os.path.join in windows
- Python windows path slash
- Path Separator in Python 3
- Windows path in python
- mixed slashes with os.path.join on windows
- Why not os.path.join use os.path.sep or os.sep?

Этот блог также стоит упомянуть, потому что автор использует несколько иной подход, чтобы принести его через точку : backslashes-in-windows-filenames

Прагматичным способом обработки имен путей является замена Разделитель путей Windows с одним Linux: path_name = path_name.replace('\\', '/')
У Python на Windows XP и более поздних версиях Windows нет проблем с C:/tab/newline/return/012/x012.

Только при печати или записи пути вы можете использовать os.path.normpath() для преобразования пути к представлению ОС или платформы, на которой запущен Python.

+0

Было бы очень плохой ошибкой, если 'os.path.abspath (os.path.dirname (__ file __))' дал путь к файлу, который каким-то образом интерпретировал '\ t' как вкладку. Как правило, только * компилятор * делает это для * строковых литералов *. – eryksun

+0

Вы не всегда можете использовать косую черту вместо обратной косой черты. Расширенный путь с префиксом '' \\? \ '' Требует обратной косой черты. Этот префикс обходит обычную обработку пути, чтобы превысить предел 260 символов. Все Windows делает замену '' \\? \ '' Префиксом устройств NT DOS '' \ ?? \ '' перед выполнением системного вызова, а в пространстве имен ядра NT - только обратная косая черта * - это разделитель путей. Кроме того, если вы создаете командную строку для запуска другой программы с подпроцессом, программа может обрабатывать косые черты в качестве переключателей параметров. – eryksun

 Смежные вопросы

  • Нет связанных вопросов^_^