-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Discussion: fixing test module name collisions in namespace packages #6966
Comments
Hi! Code stuctureThere is a code repository I work on where all components of a library and their tests are inside PEP420 (implicit) namespaces. They are like little projects but we manage them in a single repository for convenience. Simplified example:
Each component root directory in the above structure is added to PYTHONPATH so importing everything can be done so:
Where pytest failsIf I call pytest like Conflict exampleLet's say the My fixMy issue is pytest not respecting PEP420 namespaces. As such I debugged the whole way down where the importing of the test modules takes place. I found a convenient place to insert some changes.
|
@Traktormaster Yes, you've implemented more or less the solution I discussed in a comment on #5147, originally proposed by heofling on Stack Overflow. For your own use, you might find it more convenient to use his technique of monekypatching In my comment I also proposed an API change to I'd suggest at least dropping a comment in that issue pointing to your comment here, so that the maintainers know that there's further interest in this. |
In #5147 I addressed the issues with pytest when using namespace packages (i.e., directories without a
__init__.py
file).¹ The problems discussed here are related to that and stem from the same source:foo
andbar
, you cannot currently havefoo/util_test.py
andbar/util_test.py
because these will both cause creation of a module with a fully-qualified name ofutil_test
and insert it (unnecessarily) intosys.modules
. (Pytest does catch this collision, for test files anyway, and generates an error during collection.)sys.path
has an extra entry added to it for each namespace module, which can cause unexpected changes in what modules get imported as compared to running outside pytest.A solution for this (for Python ≥3.5, anyway) is already available in the
py
package: useimportlib
instead of the older import routines so you can avoid both adding the module tosys.modules
and changingsys.path
. (This is done by passingensuresyspath='importlib'
toLocalPath.pyimport()
; the support for this was added in commit 055bcb1a in 2018.) However, pytest does not currently provide any way to do this, and the best way to enable this is not clear at the moment, at least to me. (One of my worries is issues with backwards compatibility.)To solve this issue for my projects, I've created this plugin. (Depending on when you're reading this, a more recent version may be available on the master branch.)²
This uses essentially the same technique as
py
'sLocalPath.pyimport()
above: use the Python 3.5importlib
API to load a spec, create the module and execute its code, all directly from the file without usingsys.path
, and without inserting the newly-created module intosys.modules
. My version is slightly more complex because I do this only for files matching*.pt
(and need to use a couple of tricks to get the interpreter to load files not ending in.py
); this preserves backward compatibility for*_test.py
andtest_*.py
files.³So that's a proof-of-concept. I'd love to have feedback on any of the particulars of how I'm doing that, whether related to the collision/path problem or just the ability to use files not ending in
.py
.I'm also hoping we can discuss further how we might move forward with a real fix for the issues raised by namespace packages (for both test modules, as discussed here, and code-under-test modules, as discussed in #5147): the collisions and the
sys.path
changes. Having done this, it seems to have opened up the possibility of being fixed with a plug-in instead of by changing pytest itself, which I suppose has its advantages and disadvantages.Thoughts?
¹ Namespace package problems have also been discussed in other issues: #2371, I think #1028, and #221. I suspect that what fixed that last one is the source of our current problems.
² If you are a bit confused about what you see under the
src/
subdirectory of that repo, yes, I am indeed using pytest to test my 6502 assembler code. :-) You can see some more "normal" testing of Python code under thelib/
directory.³ Actually, the main reason I did this was so I can use
foo.*
on the command line to reference all files related to modulefoo
, rather thanfoo{.md,_test.py,.py}
, especially when there arefoobar*
files kicking around, too, but the ability to separate the files with the new behaviour and maintain backward-compatibility is a nice bonus.The text was updated successfully, but these errors were encountered: