pytest_test_categories.adapters.process

Production process blocker adapter using patching.

This module provides the production implementation of ProcessBlockerPort that actually intercepts process spawning by patching subprocess and os modules.

The SubprocessPatchingBlocker follows hexagonal architecture principles: - Implements the ProcessBlockerPort interface (port) - Patches subprocess and os functions to intercept spawn attempts - Raises SubprocessViolationError on unauthorized spawns - Restores original functions on deactivation

Intercepted Entry Points: - subprocess.Popen (and all subprocess convenience functions) - subprocess.run - subprocess.call - subprocess.check_call - subprocess.check_output - os.system - os.popen - multiprocessing.Process

Note: The os.spawn* and os.exec* families are not currently intercepted as they are rarely used in modern Python code. They can be added based on user feedback.

Example

>>> blocker = SubprocessPatchingBlocker()
>>> try:
...     blocker.activate(TestSize.SMALL, EnforcementMode.STRICT)
...     subprocess.run(['echo', 'hello'])  # Raises SubprocessViolationError
... finally:
...     blocker.deactivate()  # Restore original subprocess behavior

See also

  • ProcessBlockerPort: The abstract interface in ports/process.py

  • FakeProcessBlocker: Test adapter in adapters/fake_process.py

  • SocketPatchingNetworkBlocker: Similar production adapter pattern for network

Classes

SubprocessPatchingBlocker

Production adapter that patches subprocess/os to block process spawning.

Module Contents

class pytest_test_categories.adapters.process.SubprocessPatchingBlocker(/, **data)[source]

Bases: pytest_test_categories.ports.process.ProcessBlockerPort

Production adapter that patches subprocess/os to block process spawning.

This adapter intercepts process spawning by patching: - subprocess.Popen (base class for all subprocess operations) - subprocess.run, call, check_call, check_output - os.system, os.popen - os.spawn* family - os.exec* family - multiprocessing.Process

The patching is reversible - deactivate() restores the original functions.

Parameters:

data (Any)

state[source]

Current blocker state (inherited from ProcessBlockerPort).

current_test_size[source]

The test size set during activation.

current_enforcement_mode[source]

The enforcement mode set during activation.

current_test_nodeid[source]

The pytest node ID of the current test.

Warning

This adapter modifies global state (subprocess, os modules). Always use in a try/finally block or context manager to ensure cleanup.

Example

>>> blocker = SubprocessPatchingBlocker()
>>> try:
...     blocker.activate(TestSize.SMALL, EnforcementMode.STRICT)
...     subprocess.run(['ls'])  # Raises SubprocessViolationError
... finally:
...     blocker.deactivate()

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

model_post_init(context, /)[source]

Initialize post-Pydantic setup, storing references to original functions.

Parameters:

context (object)

Return type:

None

reset()[source]

Reset blocker to initial state, restoring original functions.

This is safe to call regardless of current state.

Return type:

None

current_enforcement_mode: pytest_test_categories.ports.network.EnforcementMode | None = None[source]
current_test_nodeid: str = None[source]
current_test_size: pytest_test_categories.types.TestSize | None = None[source]