monkeypatch.setattr fails to undo on objects with a custom __setattr__ (regression from #14969)

Ouverte Adaptée aux débutants
#15,099 7 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

@hardikkaurani y travaille déjà.

Depuis le 24/9/2026.

  • #15100 par @hardikkaurani — ouverte
  • #15104 par @Maurenz2530 — ouverte
  • #15106 par @chen-maker999 — fermée sans fusion
  • #15118 par @Tejas5405 — ouverte
  • #15136 par @RonnyPfannschmidt — ouverte

Évaluation

Difficulté
2/5
Temps estimé
1-3 heures
Accessibilité débutants
78/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
python
Domaine
testing-qa

Piste de recherche

Commencez par la nouvelle branche dans MonkeyPatch.setattr et comparez-la au comportement précédent décrit dans l’issue. Ajoutez un cas de régression à test_proxy.py en utilisant l’objet personnalisé setattr/getattr, puis exécutez ce test pour vérifier que undo restaure la valeur d’origine et que la valeur patchée ne se transmet pas aux tests suivants.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

Since #14969 (0c601d510, not released yet), monkeypatch.setattr doesn't restore attributes on objects that store them somewhere other than __dict__ through a custom __setattr__/__getattr__. Undo raises AttributeError, and the patched value leaks into later tests.

class Config:
    """Stores attributes in a private dict instead of __dict__."""
    def __init__(self):
        object.__setattr__(self, "_data", {"debug": False})
    def __getattr__(self, name):
        try:
            return self._data[name]
        except KeyError:
            raise AttributeError(name) from None
    def __setattr__(self, name, value):
        self._data[name] = value

cfg = Config()

def test_patch(monkeypatch):
    monkeypatch.setattr(cfg, "debug", True)
    assert cfg.debug is True

def test_restored():
    assert cfg.debug is False

On main:

ERROR test_proxy.py::test_patch - AttributeError: 'Config' object has no attribute 'debug'
FAILED test_proxy.py::test_restored - assert True is False
1 failed, 1 passed, 1 error

Just before 0c601d510, the same file passes (2 passed).

The new branch in MonkeyPatch.setattr takes the old value from target.__dict__.get(name, NOTSET) whenever target has a __dict__. It assumes that a plain setattr() writes into that dict. With a custom __setattr__ it doesn't, so the old value is recorded as NOTSET. undo() then calls delattr(cfg, "debug") instead of setting it back to False. That delattr fails, and the value stays patched.

@Shriprasad-P pointed out this exact case in a review on #14969, but it wasn't addressed before the merge. I'm opening this issue so it gets fixed before the next release.

One possible direction: only use the __dict__ lookup when name is actually present in the instance __dict__, or when the type uses object.__setattr__. Otherwise fall back to the value from getattr(), as before.

pytest 9.2.0.dev345+g872117358, Python 3.13.5, Windows 11.

Langage dominant
Python
Étoiles
14.7k
Forks
3.6k
Merge moyen
2 j 2 h
PR mergées (30 j)
37

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de pytest-dev/pytest

Toutes les issues de pytest-dev/pytest

Issues similaires

Plus d'issues Python

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.