问题描述
我正在尝试使自己熟悉 importlib
挂钩.我想实现一种功能,以直接导入用其他语言编写的非pythonic文件并维护源映射,因此使用行号引发 SyntaxError
仍然会提供有意义的堆栈跟踪.
I'm trying to get myself familiar with importlib
hooks. I want to implement an ability to directly import non-pythonic files written in other language, and maintain source maps, so raising SyntaxError
s with line numbers will still give meaningful stacktraces.
我加载外部文件的方法是组装Pythonic源代码,然后对其进行编译并在所需的上下文中执行它.
My approach to loading foreign files is assembling Pythonic source, then compiling it and executing it in the desired context.
我在文档中已经读到,实现 importlib.abc.SourceLoader
似乎是我的选择-但是,唯一被调用的方法是 exec_module
.据我所知,在那个阶段,模块对象已经准备就绪.那么为什么没有调用 get_source
, get_data
, get_code
和其他代码?
I've read in the documentation that implementing importlib.abc.SourceLoader
seems to be my choice — however, the only method that is being called is exec_module
. At that stage, to my understanding, module object is fully ready. So why are get_source
, get_data
, get_code
and others are not called?
我的存根实现:
import sys
import os
import importlib.abc
import importlib.machinery
class MyFinder(importlib.abc.MetaPathFinder):
def __init__(self):
pass
def find_spec(self, fullname, path, target=None):
print('find_spec', fullname, path, target)
# filename = '{}.npy'.format(fullname)
# if not os.path.exists(filename):
# return
if fullname != 'foobar':
return
filename = 'foobar://ponyworld/foo.py'
spec = importlib.machinery.ModuleSpec(
name = fullname,
loader = MyLoader(fullname, path, target),
origin = filename,
loader_state = 1234,
is_package = False,
)
return spec
class MyLoader(importlib.abc.SourceLoader):
def __init__(self, fullname, path, target):
pass
def get_data(self, path):
print('get_data', path)
def get_filename(self, fullname):
print('get_filename', fullname)
def path_stats(self, path):
print('path_stats', path)
def set_data(self, path, data):
print('set_data', path, data)
def get_code(self, fullname):
print('get_code', fullname)
def exec_module(self, module):
print('exec_module', module)
print(dir(module))
def get_source(self, fullname):
print('get_source', fullname)
def is_package(self, fullname):
print('is_package', fullname)
sys.meta_path.append(MyFinder())
# import fake module to see if it works
import foobar
推荐答案
我误解了文档,却忽略了 importlib.abc.SourceLoader
已经为 get_code
, exec_module
, load_module
, get_source
和 is_package
.这些仅在需要时被覆盖,并且仅 get_data
和 get_filename
是必需的最小值.
I misunderstood documentation and overlooked that importlib.abc.SourceLoader
already provides implementations for get_code
, exec_module
, load_module
, get_source
and is_package
. Those are to be overridden only in need, and only get_data
and get_filename
are the required minimum.
这篇关于动态组装Python模块,动态导入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!