Информация об источнике отсутствует в классах Python, загруженных с помощью module_from_spec
Я пытаюсь использовать модуль самоанализа Python inspect
получить исходный код для живых объектов, которые были загружены в область видимости, используя module_from_spec
функция importlib.util
, Попытки использовать inspect.getsource()
либо в самом файле spec_file, либо в любой функции в файле spec успешно возвращен желаемый исходный код. Однако тот же метод, который используется для получения исходного кода для типов классов в файле спецификации, выдает TypeError: None is a built-in class
,
from importlib.util import spec_from_file_location, module_from_spec
spec_file = spec_from_file_location("file_module", 'test_file.py')
spec_module = module_from_spec(spec_file)
spec_file.loader.exec_module(spec_module)
# spec module
import inspect
assert isinstance(inspect.getsource(spec_module), str)
# function in spec module
func_obj = getattr(spec_module, 'test_function')
assert isinstance(inspect.getsource(func_obj), str)
# class in spec module
class_obj = getattr(spec_module, 'testClass')
try:
inspect.getsource(class_obj)
except TypeError:
print('where did the source code data go?')
Виновником, кажется, является inspect.getfile()
вызов в цепочке трассировки, где объекты функции возвращают объект.__code__
в то время как объекты класса пытаются загрузить свой модуль, чтобы извлечь модуль.__file__
, Почему функции имеют __code__
метод, а занятия нет? Является ли это побочным эффектом того, как Python обрабатывает типы, что непреднамеренно нарушает самоанализ для динамически загружаемых классов?
1 ответ
Похоже, что загруженный модуль должен быть добавлен в sys.modules
для того, чтобы путь источника и модуля был правильно отражен в классах (хотя я не могу найти ссылку на это в документации). Итак, если вы импортируете sys
и добавьте свой модуль в sys.modules
, ваш пример должен работать (я тестировал похожий пример с Python 3.5):
import sys
from importlib.util import spec_from_file_location, module_from_spec
spec_file = spec_from_file_location("file_module", 'test_file.py')
spec_module = module_from_spec(spec_file)
spec_file.loader.exec_module(spec_module)
sys.modules['file_module'] = spec_module
# spec module
import inspect
assert isinstance(inspect.getsource(spec_module), str)
# function in spec module
func_obj = getattr(spec_module, 'test_function')
assert isinstance(inspect.getsource(func_obj), str)
# class in spec module
class_obj = getattr(spec_module, 'testClass')
try:
inspect.getsource(class_obj) # This should work now
except TypeError:
print('where did the source code data go?')