-
-
Notifications
You must be signed in to change notification settings - Fork 539
Description
I hate to be prescriptive in the subject because maybe there's a better way to handle this, but I found adding changedir={envtmpdir}
to be an easy solution to the problem. Feel free to re-title this bug as needed.
This may be related to #430 but let me explain what's happening. I've been looking at build failures for the lazr.config package, which also depends on lazr.delegates. Both packages are compatible with Python 2 and Python 3 and the upstream repo is a single bilingual source. Under Python 3, lazr
is a proper namespace package, but of course, not under Python 2. The source tree has a file lazr/__init__.py
which contains:
# This is a namespace package.
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
import pkgutil
__path__ = pkgutil.extend_path(__path__, __name__)
which I believe is still current best practice. Now, if you pip install lazr.config
into a venv, your venv Python can import everything just fine. In fact, if you tox -e py35 --notest -r
and then activate the .tox/py35
venv, both packages import just fine. This is true for Python 2 also.
However, when you run tox -e py35
the tests fail because lazr.delegates
cannot be imported. This confused me a lot because outside of tox, i.e. using the venvs as described above, everything works fine.
What I think is happening is that because tox by defaults runs out of the {toxinidir}
it ends up importing lazr.config
from the source tree, which at the top level looks roughly like:
lazr/
lazr/__init__.py
tox.ini
I.e. the package directory lives at the top level (but note that the bug does not go away if you put that inside say a src/
directory).
So now, because the source tree has a lazr/__init__.py
file, in Python 3 it ends up not being a namespace package, and thus when it tries to import lazr.delegates
from the tox venv, it can't find it. Liberally sprinkling pdb's around shows that indeed tox ends up failing with an ImportError
on lazr.delegates, and that sys.modules['lazr']
is not a namespace package. Looking at sys.path
at the point of failure, you can see that the cwd appears earlier than say .tox/py35/lib/python3.5/site-packages
so the import of lazr.config
finds the source tree one instead of the venv one.
Adding
[testenv]
changedir = {envtmpdir}
solves the problem, because when tox runs it will not try to import lazr.config
from the source tree, but instead from the venv and of course there, lazr
is properly a namespace package.
This kind of explains some failures I've seen in other bilingual packages, but for which I've solved in worse ways (e.g. making them Python 3 only and removing the under-Python-2-needed-namespace-__init__.py-file). By eliminating everything else, I'm interpreting this as a tox bug.
So then the question is, how should tox support bilingual source trees of namespace packages? If the source tree has a concrete <namespace>/__init__.py
file to support the Python 2 case, then importing from cwd first will always fail under Python 3. So maybe changedir={envtmpdir}
is a better default?