8

私の質問は、フルパスを指定してモジュールをインポートする方法に似ていますか? ただし、.py ソース ファイルをインポートしているのではなく、.pyd を含むパッケージをインポートしています。

実行時に、動的に生成された C コードから新しいパッケージ モジュールを作成しています。__init__.pyファイルとmod.pyd:を使用してパッケージ Foo を正常に生成します。

/a/temp/dir/foo/
    __init__.py
    bar.pyd

私が取り組んでいるサンプルコードは

import importlib.util
spec = importlib.util.spec_from_file_location("foo.bar", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
foo.bar()

pyd からspec_from_file_location('foo.bar', '/a/temp/dir/foo/__init__.py')モジュールを使用しようとすると、ロードに失敗します。bar

使用しようとするとspec_from_file_location('foo.bar', '/a/temp/dir/foo/')spec_from_file_locationが返されますNone

使用しようとするspec_from_file_location('foo.bar', '/a/temp/dir/foo/bar.pyd')と、次のエラー スタックが表示されます。

File "<frozen importlib._bootstrap>", line 577, in module_from_spec
File "<frozen importlib._bootstrap_external>", line 903, in create_module
File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed
ImportError: DLL load failed: A dynamic link library (DLL) initialization routine failed.

推奨される 4 行の importlib ソリューションの代わりに、MetaPathFinderとの具象クラスを作成することもできますSourceLoader。私のフォローMetaPathFinderはうまくいきますが、Loader正しく実装する方法がわかりません。get_data戻り値は、Python コードの Unicode 表現を想定しています。ローダーのパッケージ構造または pyd コンテンツを返すにはどうすればよいですか?

class MyLoader(importlib.abc.SourceLoader):
    def __init__(self, fullname, path, pyd):
        self.path = path
        self.fullname = fullname
        self.pyd = pyd

    def get_data(self, path):
        print('*** get_data', path)
        with open(os.path.join(self.path, self.pyd), 'r') as f:
            return f.read()

    def get_filename(self, fullname):
        print('*** get_filename', fullname)
        return os.path.join(self.path, '__init__.py')

    def is_package(self):
        return True

class MyFinder(MetaPathFinder):
    def __init__(self, this_module, workdir, pyd):
        self._this_module = this_module
        self._workdir = workdir
        self._pyd = pyd

    def find_spec(self, fullname, path, target=None):
        print('find_spec', fullname, path, target, self._this_module)

        if fullname != self._this_module:
            return

        filename = os.path.join(self._workdir, self._this_module)

        spec = ModuleSpec(
            name = fullname,
            loader = MyLoader(fullname, filename, self._pyd),
            origin = filename,
            loader_state = 1234,
            is_package = True,
        )
        return spec

    def is_package(self):
        return True
4

0 に答える 0