I have a project with an overarching namespace, with packages inside it. Here's the folder structure:
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
Pretty simple. If I want to import it I use:
from pypackage.core import pypackage
and it works great because my setup.py looks like this:
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',
]
},
...
)
However, I have legacy code that imports this pypackage
when it used to just be a stand alone python file. like this:
import pypackage
So how do I make it so I can keep the same structure with namespaces and subpackages but still import it the old way? How do I turn this:
from pypackage.core import pypackage
into this:
import pypackage
In other words, how do I alias the pypackage.core.pypackage
module to be pypackage
for when I'm importing pypackage
into an external project?
You would add the 'old' names inside your new package by importing into the top-level package.
Names imported as globals in
pypackage/__init__.py
are attributes on thepypackage
package. Make use of that to give access to 'legacy' locations:Now any code that uses
import pypackage
can usepypackage.foo
andpypackage.bar
if in reality these objects were defined inpypackage.core.pypackage
instead.Now, because
pypackage
is a setuptools namespace package you have a different problem; namespace packages are there for multiple separate distributions to install into so that top-level package must either be empty or only contain a minimum__init__.py
file (namespace packages created with empty directories require Python 3.3).If you are the only publisher of distributions that use this namespace, you can cheat a little here and use a single
__init__.py
file in yourcore
package that could use pkg-util-style__init__.py
file with the additional import I used above, but then you must not use any__init__.py
files in other distribution packages or require that they all use the exact same__init__.py
content. Coordination is key here.Or you would have to use a different approach. Leave
pypackage
as a legacy wrapper module, and rename the new package format to use a new, different top-level name that can live next to the old module. At this point you can then just include the legacy package in your project, directly, as an extra top-level module.