Say that I'm writing a custom PIP package which is structured like so:
.
| setup.py
│
└─── src
| | __init__.py
| | useful_functions_i.py
| | useful_functions_ii.py
| | useful_strings.py
|
└─── tests
| unit_tests.py
Say that useful_strings
looks something like this:
USEFUL_STRING_A = "useful-string-a"
USEFUL_STRING_B = "useful-string-b"
...
And useful_functions_i
and useful_functions_ii
contain functions which do things like:
def a_useful_function(a_string):
if a_string == useful_strings.USEFUL_STRING_XYZ:
return True
return False
How should I import useful_strings
into useful_functions_i
and useful_functions_ii
? (This isn't quite as straightforward a question as it might appear.)
If I use:
import useful_strings
That will work well if I try to run some of the code in src
locally; it will raise an exception if I run pip install .
and try to use the codebase as a PIP package.
The next alternative is:
from . import useful_strings
This works well if I try to use the codebase as a PIP package. The problem comes when I run the unit tests. I use PyTest; my pytest.ini
starts with:
[pytest]
pythonpath = src
testpaths = tests
...
And, if I were writing a unit test for a_useful_function()
as defined above, the corresponding test script would contain the following import syntax:
from src.useful_functions_i import a_useful_function
When running a unit test under these conditions, the from . import useful_strings
syntax raises an exception.
I came across a workaround on another answer on this site. (I forget which one.) It looks like this:
if __package__:
from . import useful_strings
else:
import useful_strings
This does work, and it's a solution that's peppered throughout the repos I'm currently working on. But it feels hacky, repetitive and unpythonic. Is there a better way of doing this? (It also makes PyLint complain about import orders, and, while I can live with that, it's becoming an irritation.)
pip install ...
what would Iimport
to accessa_useful_function
– Overdevelopfrom my_package.useful_functions import a_useful_function
, or (B) I put anfrom .useful_functions import a_useful_function
in__init__.py
and callfrom my_package import a_useful_function
in the external code. – Jarodjarosite