pytest: Package scoped fixture will not execute teardown

I am experiencing a weird issue: ‘package’ scoped fixture will not execute teardown after last test in package is completed if afformentioned fixture is defined outside of package

Environment

~ python --version
Python 3.8.5

~ pip freeze
allure-pytest==2.8.24
allure-python-commons==2.8.24
assertpy==1.1
attrdict==2.0.1
attrs==20.3.0
bcrypt==3.2.0
cffi==1.14.4
cryptography==3.2.1
cycler==0.10.0
future==0.18.2
iniconfig==1.1.1
kiwisolver==1.3.1
matplotlib==3.3.3
mininet==2.3.0.dev6
more-itertools==8.6.0
numpy==1.19.4
packaging==20.7
paramiko==2.7.2
pexpect==4.8.0
pexpect-serial==0.1.0
Pillow==8.0.1
pluggy==0.13.1
ptyprocess==0.6.0
py==1.9.0
pycparser==2.20
PyNaCl==1.4.0
pyparsing==2.4.7
Pypubsub==4.0.3
pyserial==3.5
pytest==6.2.1
pytest-dependency==0.5.1
pytest-logger==0.5.1
pytest-sugar==0.9.4
python-dateutil==2.8.1
PyYAML==5.3.1
singleton-decorator==1.0.0
six==1.15.0
termcolor==1.1.0
toml==0.10.2
wcwidth==0.2.5

~ uname -a 
5.4.0-58-generic #64-Ubuntu SMP Wed Dec 9 08:16:25 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux

Example to reproduce

~ tree test
test
├── __init__.py
├── conftest.py
├── sub1
│   └── __init__.py
│   └── test_foo.py
└── sub2
    └── __init__.py
    └── test_bar.py
2 directories, 3 files

~ cat test/conftest.py
import pytest

@pytest.fixture(scope='package')
def package_scoped():
    print('setup')
    yield
    print('teardown')

~ cat test/sub1/test_foo.py
def test_foo(package_scoped): pass

~ cat test/sub2/test_bar.py
def test_foo(package_scoped): pass

Result

~ pytest test --setup-plan -p no:sugar
=============== test session starts ===============
platform linux -- Python 3.8.5, pytest-6.2.1, py-1.9.0, pluggy-0.13.1
rootdir: /home/hdemchenko/git/uns
plugins: dependency-0.5.1, logger-0.5.1, allure-pytest-2.8.24
collected 2 items

test/sub1/test_foo.py
  SETUP    P package_scoped
        test/sub1/test_foo.py::test_foo (fixtures used: package_scoped)
test/sub2/test_bar.py
        test/sub2/test_bar.py::test_foo (fixtures used: package_scoped)
  TEARDOWN P package_scoped

=============== no tests ran in 0.01s ===============

If I create two conftest files in each package with the package scoped fixture I intend to use then I can see it behaving as I was expecting. Example:

~ mv test/conftest.py test/sub1/
~ cp test/sub1/conftest.py test/sub2/
~ pytest test --setup-plan -p no:sugar
=============== test session starts ===============
platform linux -- Python 3.8.5, pytest-6.2.1, py-1.9.0, pluggy-0.13.1
rootdir: /home/hdemchenko/git/uns
plugins: dependency-0.5.1, logger-0.5.1, allure-pytest-2.8.24
collected 2 items

test/sub1/test_foo.py
  SETUP    P package_scoped
        test/sub1/test_foo.py::test_foo (fixtures used: package_scoped)
  TEARDOWN P package_scoped
test/sub2/test_bar.py
  SETUP    P package_scoped
        test/sub2/test_bar.py::test_foo (fixtures used: package_scoped)
  TEARDOWN P package_scoped

=============== no tests ran in 0.01s ===============

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 1
  • Comments: 18 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Ok, I think I finally get where the confusion comes from.

Consider following:

  • there’s a package “papa”
  • there’s two sub-packages in it: “alpha” and “bravo”
  • there’s a fixture “foxtrot” inside a contest file in the directory of package “papa”

My assumptions are:

  • when I declare only two tests inside of the “alpha” package, both of which are using fixture “foxtrot”
    • there will be setup just before the first “alpha” test
    • there will be teardown just after the second “alpha” test
    • the “foxtrot” fixture doesn’t have to be explicitly declared anywhere inside of the “alpha” package
  • when I also declare three tests inside of the “bravo” package, where the fixture “foxtrot” is used only in the second test
    • there will be setup just before the second “bravo” test
    • there will be teardown just after the second “bravo” test
    • the “foxtrot” fixture doesn’t have to be explicitly declared anywhere inside of the “bravo” package

What I think is happening: the pytest finds the declaration of the “foxtrot” fixture and assumes it applies to the boundaries of the “papa” package but not to the sub-packages (“alpha” and “bravo”)

Marking as fixed in pytest 8.0.0 (#11646), let me know if not.

@bluetech, thanks I’ll keep an eye on the progress.

Here’s a quick tip on workaround for other people who might stumble upon this issue (it is easy although not very beatiful) All you need to do is:

  • create conftest file in each package you want to use the fixture
  • just import the fixture function in conftest file

Thanks for the details @hennadii-demchenko. I agree with your intuition here. I think the package scope and/or conftest handling is quite buggy. There’s also some related discussion in #7777 (in the sense that it affects the behavior here).

I’m marking this as a bug. Personally I do plan to dig into this more soon.

And to proove my point further - another way to get expected (at least by me) behavior is:

  • have test directory structure
~ tree test
test
├── __init__.py
├── conftest.py
├── sub1
│   └── __init__.py
│   └── conftest.py
│   └── test_foo.py
└── sub2
    └── __init__.py
    └── conftest.py
    └── test_bar.py
  • leave test/conftest.py the same as in report
  • have test/sub1/conftest.py and test/sub2/conftest.py simply import fixture and nothing else