monkeypatch.py


Overview

The [monkeypatch.py](/projects/286/67458) file provides functionality for **monkeypatching**—a technique widely used in testing to dynamically modify or replace attributes, dictionary items, environment variables, or system paths during test execution. This enables tests to isolate behavior by mocking dependencies, altering environment conditions, or temporarily changing the runtime state without permanent side effects.

The core offering is the `MonkeyPatch` class, which tracks all modifications and supports automatic rollback (undo) of changes after test completion. This functionality is exposed as a pytest fixture named `monkeypatch` and can also be used as a standalone helper class.


Main Entities and Their Functionality

1. monkeypatch Fixture

**Example:**

def test_os_getcwd(monkeypatch):
    monkeypatch.setattr("os.getcwd", lambda: "/tmp")
    assert os.getcwd() == "/tmp"
# After test, original os.getcwd is restored automatically

2. Utility Functions

resolve(name: str) -> object

**Usage:**

obj = resolve("os.path.join")
result = obj("a", "b")  # Calls os.path.join("a", "b")

annotated_getattr(obj: object, name: str, ann: str) -> object


derive_importpath(import_path: str, raising: bool) -> tuple[str, object]


3. Sentinel Class: Notset

notset = Notset()

4. Class: MonkeyPatch

A `final` class that provides methods to monkeypatch:

It tracks all changes and can undo them reliably.

Constructor: __init__(self)


Context Manager: MonkeyPatch.context()

**Example:**

import functools

with MonkeyPatch.context() as m:
    m.setattr(functools, "partial", lambda x: x)
    # patches active here
# patches undone here

Method: setattr

setattr(
    target: str | object,
    name: object | str,
    value: object = notset,
    raising: bool = True,
) -> None

**Example:**

monkeypatch.setattr(os, "getcwd", lambda: "/tmp")
# or equivalently
monkeypatch.setattr("os.getcwd", lambda: "/tmp")

Method: delattr

delattr(
    target: object | str,
    name: str | Notset = notset,
    raising: bool = True,
) -> None

Method: setitem

setitem(self, dic: Mapping[K, V], name: K, value: V) -> None

Method: delitem

delitem(self, dic: Mapping[K, V], name: K, raising: bool = True) -> None

Method: setenv

setenv(self, name: str, value: str, prepend: str | None = None) -> None

Method: delenv

delenv(self, name: str, raising: bool = True) -> None

Method: syspath_prepend

syspath_prepend(self, path) -> None

Method: chdir

chdir(self, path: str | os.PathLike[str]) -> None

Method: undo

undo(self) -> None

Important Implementation Details


Interaction with Other System Components


Usage Summary

def test_example(monkeypatch):
    # Patch an attribute on an object
    monkeypatch.setattr("os.getcwd", lambda: "/tmp")
    
    # Patch a dict item
    monkeypatch.setitem(os.environ, "MY_ENV", "value")
    
    # Delete an attribute
    monkeypatch.delattr(os.path, "join")
    
    # Change environment variable with prepending
    monkeypatch.setenv("PATH", "/my/path", prepend=":")
    
    # Prepend a directory to sys.path
    monkeypatch.syspath_prepend("/my/project")
    
    # Change current working directory
    monkeypatch.chdir("/tmp")

    # Undo all changes manually (optional)
    # monkeypatch.undo()

Mermaid Class Diagram

classDiagram
    class MonkeyPatch {
        -_setattr: list[tuple[object, str, object]]
        -_setitem: list[tuple[Mapping, object, object]]
        -_cwd: str | None
        -_savesyspath: list[str] | None
        +__init__()
        +setattr(target: str|object, name: object|str, value: object=notset, raising: bool=True) void
        +delattr(target: object|str, name: str|Notset=notset, raising: bool=True) void
        +setitem(dic: Mapping, name: object, value: object) void
        +delitem(dic: Mapping, name: object, raising: bool=True) void
        +setenv(name: str, value: str, prepend: str | None=None) void
        +delenv(name: str, raising: bool=True) void
        +syspath_prepend(path: object) void
        +chdir(path: str | os.PathLike) void
        +undo() void
        +context() contextmanager[MonkeyPatch]
    }

    class Notset {
        +__repr__() str
    }

    MonkeyPatch --> Notset : uses

Summary

This file is a core utility in pytest's ecosystem enabling safe, reversible monkeypatching for testing. It abstracts complex patching logic, import resolution, and rollback management behind a straightforward API. By supporting patching for attributes, dictionary entries, environment variables, and system paths, it provides comprehensive control over the test environment, improving test isolation and reliability.


End of Documentation for monkeypatch.py