Система импорта модулей интерпретатора CPython написана на самом Python и инициализирована в importlib._bootstrap
. Его источник можно увидеть в importlib/_bootstrap.py
, но он не загружается оттуда. Вместо этого он загружается из так называемого замороженного модуля, байт-код которого запечен в библиотеку интерпретатора (python37.dll
).
Интерпретатор инициализирует себя путем импорта _frozen_importlib
(это имя для importlib._bootstrap
запеченного в интерпретаторе) и , вызывающего определенную там функцию _install
, передавая sys
и _imp
модули в качестве аргументов . _install
вызывает _setup
, который инициализирует время выполнения, необходимое для этого модуля, а затем добавляет 2 импортера, реализующих PEP 451 .
При разработке пользовательского импортера я столкнулся с несколькими ошибками либо в _bootstrap.py
, либо в моем импортере, поэтому мне нужно добавить отладочный вывод в _bootstrap.py
.
Поэтому я пытаюсь заставить интерпретатор загружать _bootstrap.py
с диска, а не из запеченного байт-кода.
Анализ исходного кода cpython показал, что для импорта встроенных модулей мне не нужна большая часть спецификационного класса. Таким образом, встроенные модули можно импортировать, используя _create_builtin
class UltraSimpleSpec:
__slots__=("name",)
def __init__(self, name):
self.name = name
def _install(sys, _imp):
io = _imp.create_builtin(UltraSimpleSpec("_io"))
_bi = _imp.create_builtin(UltraSimpleSpec("builtins"))
fd = io.open("path/to/_bootstrap.py", "rt") # exits the _install function without any exception, how can it do it?
raise _bi.Exception("Never called") # _bi.print doesn't work, because sys.stdout is not initialized, so I have to use exceptions for debug output
...
К сожалению, происходит что-то странное, и вызов io.open приводит к выходу _install
, поток управления никогда не достигает следующего оператора. И, похоже, исключение не возникает, когда интерпретатор печатает его, вместо этого возникает исключение в другом месте из-за отсутствия побочного эффекта _install
.
Еще одна неприятность заключается в том, что sys.stdout
не инициализируется, поэтому мы не можем print
и вынуждены полагаться на исключения для вывода отладки.
So
Как мне заставить open
работать?
Как мне инициализировать sys.stdout
?