How can I write import foo.bar
in __init__.py
so it will load the system-wide version of foo/bar.py
when run from most places, but will load the local version of bar.py
when run from within foo
‘s source directory?
# foo/__init__.py
from foo.bar import baz
baz()
# foo/bar.py
def baz:
print('Hello")
This will always load the site-wide version of foo/bar.py
, and never the local version.
From examples of other packages I have installed on-site, imports should be done with import foo.bar
. (examples numba
, pandas
, scipy
), but I’m not sure how they manage to develop these libraries (perhaps they always use virtual environments).
I also tried:
# foo/__init__.py
try:
from bar import baz
except ModuleNotFoundError:
from foo.bar import baz
baz()
This does work, but it is pretty verbose to repeat everywhere in the library, and it seems prone to name-clashes.
>Solution :
but I’m not sure how they manage to develop these libraries (perhaps they always use virtual environments)
Yes, I think 99% or so of python dev work uses virtualenvs. They’re really not too hard—you might want to have a look at something like poetry to manage them. There’s also the pep582 approach, but that hasn’t yet made it. However you can spin up a venv really easily these days:
cd path/to/project
python3 -m venv .venv
source .venv/bin/activate
# and then something like
pip install -e . # installs in editable mode
If you don’t want to do this, you can still have an __init__
which loads the right files, by using relative paths:
# foo/__init__.py
from .bar import baz
…at the cost of not being able to evaluate the __init__
in an editor. But you can still run it locally without installing! Just use:
python -m foo
from the dir above foo. Likewise you can use
python -m foo.bar
To load and execute foo/bar.py
(assuming it does anything).
Note that if you take the usual approach of installing your package in editable mode inside a virtualenv and then working there, there’s no reason not to use the foo.bar
approach—and you can evaluate stuff without worrying about what .
means. Lots of people don’t like relative paths for exactly that reason.
If you do need to evaluate bits of foo/__init__.py
, first do the imports manually in your repl and then send only the lines you care about.