Как загрузить dylib-файл с расширением CPython? - PullRequest
1 голос
/ 30 января 2020

Это спрашивалось ранее (например, здесь ), но данное решение (например, переименование файла в *.so) неприемлемо. У меня есть расширение CPython с именем name.dylib, которое невозможно импортировать. Если имя файла изменено на name.so, оно импортируется правильно. Изменение имени файла не является опцией **, и в этом нет необходимости.

Python имеет множество хуков для поиска модулей, поэтому должен быть способ заставить его распознавать dylib-файл. Может кто-нибудь показать, как это сделать? Использование низкоуровневого импорта, в котором прописано все имя файла, нехорошо, но является приемлемым решением.

**, потому что код сборки вызывает dylib, и другие контексты, которые я предполагал. Модуль расширения имеет двойное назначение и может использоваться как в качестве обычной разделяемой библиотеки, так и в качестве расширения Python. Использование символической ссылки работает, но является последним средством, поскольку требует ручного вмешательства в автоматизированный процесс.

1 Ответ

0 голосов
/ 31 января 2020

Вы можете манипулировать sys.path_hooks и заменить FileFinder -как на тот, который будет принимать .dylib -расширения. Но см. Также более простую, но менее удобную альтернативу, которая импортировала бы, учитывая полное имя файла расширения.

Более подробную информацию о том, как .so, .py и .pyc импортируются файлы, можно найти, например, в этом моем ответе .

Эта манипуляция может выглядеть следующим образом:

import sys
import importlib
from importlib.machinery import FileFinder, ExtensionFileLoader

# pick right loader for .dylib-files:
dylib_extension = ExtensionFileLoader, ['.dylib']

# add dylib-support to file-extension supported per default
all_supported_loaders = [dylib_extension]+ importlib._bootstrap_external._get_supported_file_loaders()


# replace the last hook (i.e. FileFinder) with one recognizing `.dylib` as well:
sys.path_hooks.pop()
sys.path_hooks.append(FileFinder.path_hook(*all_supported_loaders))

#and now import name.dylib via
import name

Этот должен быть первым выполненным кодом, когда начинает выполняться скрипт python. Другие модули могут не ожидать манипуляции sys.path_hooks где-то во время выполнения программы, поэтому могут быть некоторые проблемы с другими модулями (например, pdb, traceback и т. Д.). Например:

import pdb

#above code

import name

потерпит неудачу, в то время как

#above code

import pdb

import name

будет работать, поскольку pdb, похоже, манипулирует механизмом импорта.


Обычно , FileFinder -hook является последним в sys.path_hooks, поскольку это последнее средство, как только для пути вызывается path_hook_for_FileFinder, возвращается искатель (ImportError следует вызвать, если PathFinder следует посмотреть на другие крючки):

def path_hook_for_FileFinder(path):
        """Path hook for importlib.machinery.FileFinder."""
        if not _path_isdir(path):
            raise ImportError('only directories are supported', path=path)
        return cls(path, *loader_details) # HERE Finder is returned!

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


Более простой альтернативой было бы использование imp.load_dynamic (игнорируя на момент исключения imp):

import imp
imp.load_dynamic('name', 'name.dylib') # or what ever path is used

Это может быть более надежным, чем первое решение (никаких проблем с * 1055) * например) но менее удобно для больших проектов.

...