Пространства имен python против пакетов: сделать пакет пространством имен по умолчанию
У меня есть проект с всеобъемлющим пространством имен, с пакетами внутри. Вот структура папок:
pypackage
├── pypackage <-- Source code for use in this project.
| |
│ ├── bin <-- Module: Cli entry point into pyproject.
| | ├── __init__.py
| | └── pypackage.py
| |
| └── core <-- Module: Core functionality.
| ├── __init__.py
| └── pypackage.py
|
├── tests
├── README.md
└── setup.py
Довольно просто Если я хочу импортировать это, я использую:
from pypackage.core import pypackage
и это прекрасно работает, потому что мой setup.py выглядит так:
from setuptools import setup, find_packages
...
NAME = 'pypackage'
setup(
name=NAME,
namespace_packages=[NAME],
packages=[f'{NAME}.{p}' for p in find_packages(where=NAME)],
entry_points={
"console_scripts": [
f'{NAME} = {NAME}.bin.{NAME}:cli',
]
},
...
)
Тем не менее, у меня есть устаревший код, который импортирует этот pypackage
когда-то это был просто отдельный файл Python. как это:
import pypackage
Итак, как мне сделать так, чтобы я мог сохранять ту же структуру с пространствами имен и подпакетами, но все же импортировать ее старым способом? Как мне включить это:
from pypackage.core import pypackage
в это:
import pypackage
Другими словами, как мне псевдоним pypackage.core.pypackage
модуль должен быть pypackage
когда я импортирую pypackage
во внешний проект?
2 ответа
Вы бы добавили "старые" имена в ваш новый пакет, импортировав его в пакет верхнего уровня.
Имена, импортированные как глобальные pypackage/__init__.py
атрибуты на pypackage
пакет. Воспользуйтесь этим, чтобы получить доступ к "устаревшим" местам:
# add all public names from pypackage.core.pypackage to the top level for
# legacy package use
from .core.pypackage import *
Теперь любой код, который использует import pypackage
можешь использовать pypackage.foo
а также pypackage.bar
если в действительности эти объекты были определены в pypackage.core.pypackage
вместо.
Теперь, потому что pypackage
это пакет пространства имен setuptools, у вас другая проблема; Пакеты пространства имен предназначены для установки нескольких отдельных дистрибутивов, поэтому пакет верхнего уровня должен быть либо пустым, либо содержать только минимум __init__.py
файл (пакеты пространства имен, созданные с пустыми каталогами, требуют Python 3.3).
Если вы являетесь единственным издателем дистрибутивов, которые используют это пространство имен, вы можете немного обмануть здесь и использовать один __init__.py
файл в вашем core
пакет, который может использовать pkg-util-style __init__.py
файл с дополнительным импортом, который я использовал выше, но тогда вы не должны использовать какие-либо __init__.py
файлы в других дистрибутивах или требуют, чтобы все они использовали одно и то же __init__.py
содержание. Координация является ключевой здесь.
Или вам придется использовать другой подход. Покидать pypackage
как устаревший модуль-обертка, и переименуйте новый формат пакета, чтобы использовать новое, другое имя верхнего уровня, которое может находиться рядом со старым модулем. На этом этапе вы можете просто включить устаревший пакет в свой проект напрямую, как дополнительный модуль верхнего уровня.
Мартин Питерс имеет правильную идею, если бы я использовал пакеты, но пакет пространства имен - это вещь setuptools.
Так что это не сработало. после дополнительных исследований я узнал, что нет способа сделать то, что я пытаюсь сделать. Поэтому, если я действительно хочу это сделать, я должен преобразовать все в обычную иерархию пакетов вместо пакета пространств имен, а затем использовать решение Мартина.
Я решил изменить устаревший код, чтобы импортировать его по-новому.