Информация об источнике отсутствует в классах 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?')
Другие вопросы по тегам