Skip to content
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

conftest.py in root directory should not add root directory to sys.path #2269

Closed
ostrokach opened this issue Feb 21, 2017 · 17 comments
Closed
Labels
topic: collection related to the collection phase

Comments

@ostrokach
Copy link

ostrokach commented Feb 21, 2017

I started putting conftest.py in the root directory of my packages, instead of the tests/ directory, because I wanted to modify my doctest namespace.

However, it turns out that putting conftest.py in the root directory causes py.test to use the local rather than the installed version of my package to do the tests, which breaks some of my tests which depend on compiled modules.

Is this the intended behaviour? Some people seem to use this as a feature (e.g. see this stackoverflow answer). However, in my case this was a bug that was relatively difficult to track down.

I fixed this by putting the following lines in the root conftest.py file:

import os.path as op
import sys
sys.path.remove(op.dirname(op.abspath(__file__)))

Anaconda python running on CentOS 6

$ py.test --version
This is pytest version 3.0.6, imported from /opt/conda/lib/python3.5/site-packages/pytest.py
setuptools registered plugins:
  pytest-logging-2015.11.4 at /opt/conda/lib/python3.5/site-packages/pytest_logging/plugin.py
  pytest-cov-2.4.0 at /opt/conda/lib/python3.5/site-packages/pytest_cov/plugin.py
  hypothesis-3.6.1 at /opt/conda/lib/python3.5/site-packages/hypothesis/extra/pytestplugin.py
@RonnyPfannschmidt
Copy link
Member

this is expected behaviour with conftests, and indeed tricky to gauge
a common solution is to switch from the fragile root layout to the more robust src layout

in the root layout you have your python packages in the root folder directly, thus easily causing trouble with sys.path behaviour

in the src layout you have your python packages inside a src folder separating them from common importability

@flub
Copy link
Member

flub commented Feb 24, 2017

FWIW I would not be against trying to fix this (and I wrote that SO answer...), it is rather bad that pytest modifies sys.path so much just because of loading conftest files.

This would probably cause major breakage though so may be trick to introduce and need a major version etc.

@RonnyPfannschmidt
Copy link
Member

a pytest.ini option wrt early conftest processing as well as expected sys.path changes can be done as a non-intrusive opt-in

if we give people a way to specify the expectation, it safes us and them a lot of pain and the need for a major release

@nicoddemus
Copy link
Member

nicoddemus commented Feb 25, 2017

From a glance at the code it seems pytest adds the conftest's directory to sys.path and leaves it there. Would improve things if we removed the contest's path after importing it?

@nicoddemus nicoddemus added the topic: collection related to the collection phase label Feb 25, 2017
@RonnyPfannschmidt
Copy link
Member

It would break the world in various cases, like deferred imports

@nicoddemus
Copy link
Member

Hmm thanks. But adding an option like you propose help in this case?

@nicoddemus
Copy link
Member

I mean, adding an option that removes from sys.path

@RonnyPfannschmidt
Copy link
Member

@nicoddemus on bit we need to control is leading of conftests only in pythonpath (so disallow adding them to sys.path)
the other bit we need to control is if and which early conftests to load

@mkleehammer
Copy link

I'm actually interested in the opposite - I would like to include the top-level directory (current directory when running pytest) in the Python path. ("src", I know - not gonna happen)

This seems like something a couple of simple command line options could fix:

  • An option to never modify path
  • The default to work as it does today
  • An option to add current directory

I get there is a "right" way that people want to force everyone to use, but there are a lot of projects out there that don't use src. Auto-discovery really loses its shine when it doesn't actually work. Using a blank conftest.py to accomplish the same thing seems like real hack.

@nicoddemus
Copy link
Member

Hmmm adding an option indeed might be a good idea here in this case (although I don't think An option to never modify path is possible given we have to do that to import conftest.py files).

It might be better even as a pytest.ini option, which would make it "official" how to run pytest for a given project.

What do others think?

@gaborbernat
Copy link
Contributor

I've ran into this today:

root _
     |_ a
         |_ tests 
                |_ conftest.py

(root) $ cd a
(a)    $ pytest  tests 

So this is very confusing behavior here:

  • note that when my current working directory is a (not root)
  • a contains my tests
  • tests contain conftest.py

the root will be added to the sys.path, in a persistent way. One could argue that okay, the tests folder needs to be on path to import conftest.py, but why root?

A manifestation of this is that coverage report breaks, as imports no longer use the site package, but the local files.

@nicoddemus
Copy link
Member

Hi @gaborbernat!

That's strange, I can't reproduce your problem:

============================= test session starts =============================
platform win32 -- Python 3.6.3, pytest-3.3.0, py-1.5.2, pluggy-0.6.0
rootdir: X:\temp\conftest-issue\root\a, inifile:
collected 1 item

tests\test_a.py F                                                        [100%]

================================== FAILURES ===================================
____________________________________ test _____________________________________

    def test():
        for x in sys.path: print(x)
>       assert 0
E       assert 0

tests\test_a.py:5: AssertionError
---------------------------- Captured stdout call -----------------------------
X:\temp\conftest-issue\root\a\tests
X:\temp\conftest-issue\.env36\Scripts\pytest.exe
x:\temp\conftest-issue\.env36\scripts\python36.zip
C:\Users\Bruno\AppData\Local\Programs\Python\Python36\DLLs
C:\Users\Bruno\AppData\Local\Programs\Python\Python36\lib
C:\Users\Bruno\AppData\Local\Programs\Python\Python36
x:\temp\conftest-issue\.env36
x:\temp\conftest-issue\.env36\lib\site-packages
========================== 1 failed in 0.03 seconds ===========================

As can be seen, only root\a\tests is added to sys.path. Do you have perhaps another conftest.py somewhere? Do you have a pytest.ini?

@nicoddemus
Copy link
Member

#5352 was a step in this direction, but was closed without explanation (?).

@The-Compiler
Copy link
Member

#5352 was a step in this direction, but was closed without explanation (?).

Maybe @blueyed can explain why?

@blueyed
Copy link
Contributor

blueyed commented Aug 26, 2019

Because you did not want to take it as a hidden option only mostly - at least that was my impression.

@bluetech
Copy link
Member

@nicoddemus I think --import-mode=importlib fixes this, right?

@nicoddemus
Copy link
Member

Indeed, good catch, thanks!

--import-mode=importlib will prevent pytest from messing with sys.path at all. 👍

(This will be released in 6.0.0, but 6.0.0rc1 can be used to test this already).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: collection related to the collection phase
Projects
None yet
Development

No branches or pull requests

9 participants