How Can I Create Imports That Always Work?
Solution 1:
Unfortunately relative imports and direct running of submodules don't mix.
Add the parent directory of mypackage
to your PYTHONPATH
or always cd
into the parent directory when you want to run a submodule.
Then you have two possibilities:
Use absolute (from mypackage import utils
) instead of relative imports (from . import utils
) and run them directly as before. The drawback with that solution is that you'll always need to write the fully qualified path, making it more work to rename mypackage
later, among other things.
or
Run python3 -m mypackage.utils
etc. to run your submodules instead of running python3 mypackage/utils.py
.
This may take some time to adapt to, but it's the more correct way (a module in a package isn't the same as a standalone script) and you can continue to use relative imports.
There are more "magical" solutions involving __package__
and sys.path
but they all require extra code at the top of every file with relative imports you want to run directly. I wouldn't recommend these.
Solution 2:
You should create a structure like this:
flammi88
├── flammi88
│ ├── __init__.py
│ ├── code.py
│ └── mypackage
│ ├── __init__.py
│ ├── utils.py
│ └── work.py
└── setup.py
then put at least this in the setup.py:
import setuptools
from distutils.core import setup
setup(
name='flammi88',
packages=['flammi88'],
)
now, from the directory containing setup.py, run
pip install -e .
This will make the flammi88 package available in development mode. Now you can say:
from flammi88.mypackageimport utils
everywhere. This is the normal way to develop packages in Python, and it solves all of your relative import problems. That being said, Guido frowns upon standalone scripts in sub-packages. With this structure I would move the tests inside flammi88/tests/...
(and run them with e.g. py.test
), but some people like to keep the tests next to the code.
Update:
an extended setup.py that describes external requirements and creates executables of the sub-packages you want to run can look like:
import setuptools
from distutils.core import setup
setup(
name='flammi88',
packages=['flammi88'],
install_requires=[
'markdown',
],
entry_points={
'console_scripts': [
'work = flammi88.mypackage.work:someMethod',
]
}
)
now, after pip installing your package, you can just type work
at the command line.
Solution 3:
Import utils
inside the work.py
as follows:
import mypackage.utils
or if you want to use shorter name:
from mypackage import utils
EDIT: If you need to run work.py
outside of the package, then try:
try:
from mypackage import utils
except ImportError:
import utils
Solution 4:
Use:
from . import utils
as suggested by Peter
In your code.py you should use:
from mypackage import work
Post a Comment for "How Can I Create Imports That Always Work?"