pytest-dev / pytest-dev/pytest

`monkeypatch.setattr` started failing in Pytest 8.1.2 (setuptools CI)

Open
#12,254 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

plugin: monkeypatch type: bug
Dominant language
Python
Stars
14.5k
Forks
3.4k
Avg merge
2d 9h
Merged PRs (30d)
35

Description

  • a detailed description of the bug or problem you are having

Prior to 8.1.2 the following statement executed without raising an exception (8.0.2) in the setuptools CI, but now it started failing (8.1.2):

    def test_get_output_mapping_with_stub(self, tmpdir_cwd, monkeypatch):
        monkeypatch.setenv('SETUPTOOLS_EXT_SUFFIX', '.mp3')  # make test OS-independent
>       monkeypatch.setattr('setuptools.command.build_ext.use_stubs', True)

/home/runner/work/setuptools/setuptools/setuptools/tests/test_build_ext.py:141

The error message does not make much sense to me:

obj = <module 'setuptools.command' from '/home/runner/work/setuptools/setuptools/setuptools/command/__init__.py'>
name = 'build_ext', ann = 'setuptools.command.build_ext'

    def annotated_getattr(obj: object, name: str, ann: str) -> object:
        try:
>           obj = getattr(obj, name)
E           AttributeError: module 'setuptools.command' has no attribute 'build_ext'

/home/runner/work/setuptools/setuptools/.tox/py/lib/python3.11/site-packages/_pytest/monkeypatch.py:91: AttributeError

The above exception was the direct cause of the following exception:

self = <setuptools.tests.test_build_ext.TestBuildExt object at 0x7f41b3f86a50>
tmpdir_cwd = local('/home/runner/work/setuptools/setuptools')
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f41b1dfe5d0>

    def test_get_outputs(self, tmpdir_cwd, monkeypatch):
        monkeypatch.setenv('SETUPTOOLS_EXT_SUFFIX', '.mp3')  # make test OS-independent
>       monkeypatch.setattr('setuptools.command.build_ext.use_stubs', False)

/home/runner/work/setuptools/setuptools/setuptools/tests/test_build_ext.py:109: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/home/runner/work/setuptools/setuptools/.tox/py/lib/python3.11/site-packages/_pytest/monkeypatch.py:103: in derive_importpath
    target = resolve(module)
/home/runner/work/setuptools/setuptools/.tox/py/lib/python3.11/site-packages/_pytest/monkeypatch.py:[85](https://github.com/pypa/setuptools/actions/runs/8853717171/job/24315188999#step:9:86): in resolve
    found = annotated_getattr(found, part, used)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

obj = <module 'setuptools.command' from '/home/runner/work/setuptools/setuptools/setuptools/command/__init__.py'>
name = 'build_ext', ann = 'setuptools.command.build_ext'

    def annotated_getattr(obj: object, name: str, ann: str) -> object:
        try:
            obj = getattr(obj, name)
        except AttributeError as e:
>           raise AttributeError(
                f"{type(obj).__name__!r} object at {ann} has no attribute {name!r}"
            ) from e
E           AttributeError: 'module' object at setuptools.command.build_ext has no attribute 'build_ext'

/home/runner/work/setuptools/setuptools/.tox/py/lib/python3.11/site-packages/_pytest/monkeypatch.py:[93](https://github.com/pypa/setuptools/actions/runs/8853717171/job/24315188999#step:9:94): AttributeError

Because:

  1. setuptools.command.build_ext is defined as a module, not an attribute of setuptools.command
  2. setuptools.command.build_ext module does define a build_ext class. But also setuptools.command.build_ext.build_ext should have nothing to do with monkeypatching setuptools.command.build_ext.use_stubs...

In the same workflow run, we also have other similar errors (e.g. AttributeError: module 'setuptools.command' has no attribute 'build_clib')


- [x] output of `pip list` from the virtual environment you are using

For the tox output:

alabaster==0.7.16
attrs==23.2.0
autocommand==2.2.2
Babel==2.14.0
backports.tarfile==1.1.1
build==1.2.1
cachetools==5.3.3
certifi==2024.2.2
cffi==1.16.0
chardet==5.2.0
charset-normalizer==3.3.2
colorama==0.4.6
ConfigUpdater==3.2
coverage==7.5.0
cryptography==42.0.5
distlib==0.3.8
docutils==0.21.2
domdf-python-tools==3.8.0.post2
execnet==2.1.1
filelock==3.13.4
idna==3.7
imagesize==1.4.1
importlib_metadata==7.1.0
importlib_resources==6.4.0
inflect==7.2.1
ini2toml==0.14
iniconfig==2.0.0
jaraco.classes==3.4.0
jaraco.context==5.3.0
jaraco.develop==8.13.0
jaraco.env==1.0.0
jaraco.envs==2.6.0
jaraco.functools==4.0.1
jaraco.packaging==10.1.0
jaraco.path==3.7.0
jaraco.text==3.12.0
jaraco.ui==2.3.0
jaraco.vcs==2.2.0
jaraco.versioning==1.1.0
jeepney==0.8.0
Jinja2==3.1.3
keyring==25.2.0
MarkupSafe==2.1.5
more-itertools==10.2.0
mypy==1.9.0
mypy-extensions==1.0.0
natsort==8.4.0
packaging==24.0
path==16.14.0
pip==24.0
pip-run==12.6.1
platformdirs==4.2.1
pluggy==1.5.0
pycparser==2.22
Pygments==2.17.2
PyNaCl==1.5.0
pyproject-api==1.6.1
pyproject_hooks==1.0.0
pytest==8.1.2
pytest-checkdocs==2.12.0
pytest-cov==5.0.0
pytest-enabler==3.1.1
pytest-home==0.5.1
pytest-mypy==0.10.3
pytest-perf==0.14.0
pytest-ruff==0.3.1
pytest-timeout==2.3.1
pytest-xdist==3.5.0
python-dateutil==2.9.0.post0
pytz==2024.1
requests==2.31.0
requests-file==2.0.0
requests-toolbelt==1.0.0
ruff==0.4.2
SecretStorage==3.3.3
setuptools @ file:///home/runner/work/setuptools/setuptools/.tox/.tmp/package/1/setuptools-69.5.1.post20240426-0.editable-py3-none-any.whl#sha256=c45586b1cbdcef78ac5a07ff798e095fc4a634e8f28286d1144ed343e1f94bd2
six==1.16.0
snowballstemmer==2.2.0
Sphinx==7.3.7
sphinxcontrib-applehelp==1.0.8
sphinxcontrib-devhelp==1.0.6
sphinxcontrib-htmlhelp==2.0.5
sphinxcontrib-jsmath==1.0.1
sphinxcontrib-qthelp==1.0.7
sphinxcontrib-serializinghtml==1.1.10
subprocess-tee==0.4.1
tempora==5.5.1
toml==0.10.2
tomli==2.0.1
tomli_w==1.0.0
tomlkit==0.12.4
tox==4.15.0
typeguard==4.2.1
typing_extensions==4.11.0
urllib3==2.2.1
virtualenv==20.26.0
wheel==0.43.0
zipp==3.18.1

  • pytest and operating system versions
ubuntu-latest (Github Actions) - Ubuntu 22.04 LTS
CPython 3.11.9

pytest==8.1.2
pytest-checkdocs==2.12.0
pytest-cov==5.0.0
pytest-enabler==3.1.1
pytest-home==0.5.1
pytest-mypy==0.10.3
pytest-perf==0.14.0
pytest-ruff==0.3.1
pytest-timeout==2.3.1
pytest-xdist==3.5.0

  • minimal example if possible

Unfortunately I was not able to simplify the reproducer.
I tried to create a minimal example with monkeypatch and nested modules but all works fine:

docker run --rm -it python:3.11-bookworm /bin/bash

cd /tmp
python3 -m venv .venv
.venv/bin/python -m pip install 'pytest==8.1.2'

mkdir -p pkg/a/b
cat <<EOF > pkg/a/b/__init__.py
def f():
    from . import c
    return c.y()
EOF
cat <<EOF > pkg/a/b/c.py
x = 37

def y(): return x
EOF


cat <<EOF > test_monkeypatch.py
from pkg.a import b

def test_monkeypatch(monkeypatch):
    monkeypatch.setattr('pkg.a.b.c.x', 42)

    assert b.f() == 42
EOF

.venv/bin/pytest test_monkeypatch.py  # ==> this works fine...

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the failure using setuptools/tests/test_build_ext.py with pytest 8.1.2, then inspect _pytest/monkeypatch.py around resolve and annotated_getattr (lines 85-103). Compare against pytest 8.0.2 and the supplied nested-module example; done means the setuptools monkeypatch calls no longer fail while the existing behavior remains correct.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.