Контекст
Я работаю над проектом Python, разделенным на два пакета foo
и spam
. foo
реализует высокоуровневый API; spam
- это сложная часть программного обеспечения (поддерживаемая как отдельный проект), объединяющая различные Python модули и расширения. Ожидается, что пользователи будут использовать только foo
, spam
как внутренний механизм.
Цель
Я хотел бы сделать spam
видимым для пользователей как foo.bar
, сохраняя при этом строгий тип эквивалентность. Пользователь должен получить доступ к spam.eggs.Eggs
, импортировав foo.bar.eggs.Eggs
. В то же время я хотел бы, чтобы значение foo.bar.eggs.Eggs is spam.eggs.Eggs
было истинным, чтобы не было риска непреднамеренного поведения при выполнении проверок типов (например, при проверке типов с помощью isinstance
).
Иллюстративный пример
Этот пример сделан из следующего дерева файлов:
.
├── foo
│ ├── __init__.py
│ └── bar.py
└── spam
├── __init__.py
└── eggs
├── __init__.py
└── rice.py
[File foo/__init__.py
]
print("Importing foo")
def hello():
print("Hello from foo")
[File foo/bar.py
(содержит основной импорт код)]
import importlib
import sys
sys.modules["foo.bar"] = importlib.import_module("spam")
del importlib, sys
[Файл spam/__init__.py
]
print("Importing spam")
def hello():
print("Hello from spam")
[Файл spam/eggs/__init__.py
]
print("Importing spam.eggs")
def hello():
print("Hello from spam.eggs")
class Eggs:
pass
[Файл spam/eggs/rice.py
]
from . import Eggs
print("Importing spam.eggs.rice")
def hello():
print("Hello from spam.eggs.rice")
class Rice(Eggs):
pass
Я для удобства собрал пример на GitHub (со скриптами pytest). По какой-то причине скрипт test_module_import.py
ведет себя так, как задумано, а test_class_import.py
завершается ошибкой. Кажется, что экземпляры classe имеют свой родительский модуль (в соответствии с вызовом import) в своем имени типа. Что я могу сделать, чтобы это изменить?