Skip to main content

Patch Target: A tiny library for creating valid unittest.mock.patch target arguments

The ability to monkey patch modules, functions, classes, and class instances is a powerful part of testing Python code; however, the unittest.mock.patch function depends on the developer providing a precise module path AS A STRING to the object to be patched. If you refactor where your modules live or make other changes, you will find the annoying and hard-to-decipher-at-first errors pointing to an invalid module path string.

This small library, consisting of a single exported function, attempts to make using this function a more straightforward, reliably correct experience.

the patch_target function takes 2 arguments:

  • a host_module of type ModuleType
  • and an object_to_be_patched, which can be of type Any, but note that the only Patchable types are Named | str, where Named is a protocol describing any object with a __name__ attr
  • see note* on passing str types below

Since you're dealing with python objects instead of strings, you get more guarantees out of the box. E.g. since you have to pass in a module instead of a string, that means you have to have successfully imported the module into your test to begin with

example:

Given a src code file like this:

# myapp.mymodule.mysubmodule

import datetime
from uuid import uuid4

my_module_level_attribute = "some_value"

def get_current_time():
    return datetime.datetime.now()

def generate_new_id():
    return uuid4()

You can patch the non-deterministic pieces (current time and uuid generation) like so:

from unittest.mock import patch, Mock
from myapp.my_module import my_submodule  # noqa
import datetime

import uuid

from patch_target import patch_target


# using the patch decorator to override a module imported into the host_module
@patch(patch_target(my_submodule, datetime))   # Using string paths the patch arg would be  "myapp.mymodule.my_submodule.datetime"
def test_get_current_time(mock_datetime: Mock) -> None:
    the_beginning_of_time = datetime.datetime(1970, 1, 1)
    mock_datetime.datetime.now.return_value = the_beginning_of_time
    
    actual = my_submodule.get_current_time()
    expected = the_beginning_of_time

    assert actual == expected


# using the patch context manager override a function imported into the host_module
def test_generate_new_id() -> None:
    fake_id = "my-super-cool-id"
    with patch(patch_target(my_submodule, uuid.uuid4)) as mock_uuid4: # Using string paths the patch arg would be  "myapp.mymodule.my_submodule.uuid.uuid4"
        mock_uuid4.return_value = fake_id
        
        actual = my_submodule.generate_new_id()
        expected = fake_id
        
        assert actual == expected


# using the patch context manager override a module_attribute defined in the host_module
def test_get_module_level_attribute() -> None:
    with patch(patch_target(my_submodule, "my_module_level_attribute"), "some_other_value"): # Using string paths the patch arg would be  "myapp.mymodule.my_submodule.my_module_level_attribute"        
        actual = my_submodule.my_module_level_attribute
        expected = "some_other_value"
        
        assert actual == expected

* Note that though patching module-level attributes using the string name of the variable is supported, you can just use unittest.mock.patch.object the same way. So you don't need this lib to accomplish it.

# using unittest.mock.patch.object
from unittest.mock import patch

from myapp.my_module import my_submodule  # noqa

def test_get_module_level_attribute() -> None:
    with patch.object(my_submodule, "my_module_level_attribute", "some_other_value"): # Using string paths the patch arg would be  "myapp.mymodule.my_submodule.my_module_level_attribute"        
        actual = my_submodule.my_module_level_attribute
        expected = "some_other_value"
        
        assert actual == expected

Metadata

Release files for patch-target 0.1.10

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for patch-target 0.1.10
File Size Uploaded Provenance Actions
patch_target-0.1.10.tar.gz 3.0 kB Without provenance Details for patch_target-0.1.10.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for patch-target 0.1.10
File Interpreter ABI Platform Actions
patch_target-0.1.10-py3-none-any.whl Python 3 none any Details for patch_target-0.1.10-py3-none-any.whl

Total release size: 6.4 kB

Release files / patch_target-0.1.10.tar.gz

Download URL patch_target-0.1.10.tar.gz
Size 3.0 kB
Tags Source
SHA-256 checksum
How to use checksums
166d93c521f1511962728b98b7a3bde42fecefcd742b74034d1e65c3246e6c15
BLAKE2b-256 checksum
How to use checksums
a09916260fc3dc331666ae83bbc699f05cd74554029c1d3ec9eb5560965f967e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.6.1 CPython/3.10.13 Darwin/21.6.0

Release files / patch_target-0.1.10-py3-none-any.whl

Download URL patch_target-0.1.10-py3-none-any.whl
Size 3.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ccfcaf73de7701c02ff66cff412d867bf06e18a66d27f6fcabbb04cd61f91458
BLAKE2b-256 checksum
How to use checksums
0fde079b237ed1f700250abff87d536847a368e243af7c3f5a13c5a07d642670
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via poetry/1.6.1 CPython/3.10.13 Darwin/21.6.0

Security for patch-target 0.1.10

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page