Skip to content

MockPlugin

MockPlugin

MockPlugin(verifier)

Bases: BasePlugin

Core mock plugin: intercepts method calls on named proxy objects.

Source code in src/tripwire/_mock_plugin.py
def __init__(self, verifier: "StrictVerifier") -> None:
    super().__init__(verifier)
    self._proxies: dict[str, MockProxy] = {}
    self._mocks: list[_BaseMock] = []
    self._active_patches: dict[tuple[int, str], _BaseMock] = {}

create_import_site_mock

create_import_site_mock(path, *, spy=False)

Create an ImportSiteMock. Registration happens in _BaseMock.init.

Source code in src/tripwire/_mock_plugin.py
def create_import_site_mock(
    self, path: str, *, spy: bool = False
) -> ImportSiteMock:
    """Create an ImportSiteMock. Registration happens in _BaseMock.__init__."""
    return ImportSiteMock(path=path, plugin=self, spy=spy)

create_object_mock

create_object_mock(target, attr, *, spy=False)

Create an ObjectMock. Registration happens in _BaseMock.init.

Source code in src/tripwire/_mock_plugin.py
def create_object_mock(
    self, target: object, attr: str, *, spy: bool = False
) -> ObjectMock:
    """Create an ObjectMock. Registration happens in _BaseMock.__init__."""
    return ObjectMock(target=target, attr=attr, plugin=self, spy=spy)

get_or_create_proxy

get_or_create_proxy(name, wraps=None)

Return an existing MockProxy for name, or create a new one.

If wraps is provided and a proxy already exists, update its wraps attribute (e.g., spy() called after mock()). If no proxy exists, create a new one with wraps set.

Source code in src/tripwire/_mock_plugin.py
def get_or_create_proxy(self, name: str, wraps: object = None) -> MockProxy:
    """Return an existing MockProxy for name, or create a new one.

    If wraps is provided and a proxy already exists, update its wraps
    attribute (e.g., spy() called after mock()). If no proxy exists,
    create a new one with wraps set.
    """
    if name not in self._proxies:
        self._proxies[name] = MockProxy(name=name, plugin=self, wraps=wraps)
    elif wraps is not None:
        # Allow updating wraps on a pre-existing proxy (e.g., spy() called after mock())
        object.__setattr__(self._proxies[name], "_wraps", wraps)
    return self._proxies[name]

matches

matches(interaction, expected)

Return True if all expected fields match the interaction's details.

Source code in src/tripwire/_mock_plugin.py
def matches(self, interaction: Interaction, expected: dict[str, Any]) -> bool:
    """Return True if all expected fields match the interaction's details."""
    try:
        for key, expected_val in expected.items():
            actual_val = interaction.details.get(key)
            if expected_val != actual_val:
                return False
        return True
    except Exception:
        return False

format_interaction

format_interaction(interaction)

One-line description: '[MockPlugin] MockName.method_name(first_arg_preview)'.

Source code in src/tripwire/_mock_plugin.py
def format_interaction(self, interaction: Interaction) -> str:
    """One-line description: '[MockPlugin] MockName.method_name(first_arg_preview)'."""
    # source_id is "mock:MockName.method_name"
    readable = interaction.source_id.replace("mock:", "[MockPlugin] ", 1)
    args = interaction.details.get("args", ())
    if args:
        first_repr = repr(args[0])
        if len(first_repr) > 60:
            first_repr = first_repr[:60] + "..."
        return f"{readable}({first_repr})"
    return f"{readable}()"

format_mock_hint

format_mock_hint(interaction)

Copy-pasteable code to configure a mock for this interaction.

Source code in src/tripwire/_mock_plugin.py
def format_mock_hint(self, interaction: Interaction) -> str:
    """Copy-pasteable code to configure a mock for this interaction."""
    mock_name = interaction.details.get("mock_name", "?")
    method_name = interaction.details.get("method_name", "?")
    if "raised" in interaction.details:
        raised = interaction.details["raised"]
        return f'tripwire.mock("{mock_name}").{method_name}.raises({raised!r})'
    return f'tripwire.mock("{mock_name}").{method_name}.returns(<value>)'

format_unmocked_hint

format_unmocked_hint(source_id, args, kwargs)

Copy-pasteable code snippet for mocking a call that had no side effect.

Source code in src/tripwire/_mock_plugin.py
def format_unmocked_hint(
    self,
    source_id: str,
    args: tuple[Any, ...],
    kwargs: dict[str, Any],
) -> str:
    """Copy-pasteable code snippet for mocking a call that had no side effect."""
    # source_id = "mock:Name.method"
    without_prefix = source_id.replace("mock:", "", 1)
    parts = without_prefix.split(".", 1)
    mock_name = parts[0] if len(parts) > 0 else "?"
    method_name = parts[1] if len(parts) > 1 else "?"
    return (
        f"Unexpected call to {mock_name}.{method_name}\n\n"
        f"  Called with: args={args!r}, kwargs={kwargs!r}\n\n"
        f"  To mock this interaction, add before your sandbox:\n"
        f'    tripwire.mock("{mock_name}").{method_name}.returns(<value>)\n\n'
        f"  Or to mark it optional:\n"
        f'    tripwire.mock("{mock_name}").{method_name}.required(False).returns(<value>)'
    )

format_assert_hint

format_assert_hint(interaction)

Copy-pasteable code to assert this interaction.

Source code in src/tripwire/_mock_plugin.py
def format_assert_hint(self, interaction: Interaction) -> str:
    """Copy-pasteable code to assert this interaction."""
    mock_name = interaction.details.get("mock_name", "?")
    method_name = interaction.details.get("method_name", "?")
    args = interaction.details.get("args", ())
    kwargs = interaction.details.get("kwargs", {})
    lines = [
        f'tripwire.mock("{mock_name}").{method_name}.assert_call(',
        f"    args={args!r},",
        f"    kwargs={kwargs!r},",
    ]
    if "raised" in interaction.details:
        lines.append(f"    raised={interaction.details['raised']!r},")
    if "returned" in interaction.details:
        lines.append(f"    returned={interaction.details['returned']!r},")
    lines.append(")")
    return "\n".join(lines)

assertable_fields

assertable_fields(interaction)

Return the field names required in **expected when asserting a mock interaction.

Adapts based on interaction content: - Standard mock calls: {args, kwargs} - .raises() side effects: {args, kwargs, raised} - Spy returned: {args, kwargs, returned} - Spy raised: {args, kwargs, raised}

Source code in src/tripwire/_mock_plugin.py
def assertable_fields(self, interaction: Interaction) -> frozenset[str]:
    """Return the field names required in **expected when asserting a mock interaction.

    Adapts based on interaction content:
    - Standard mock calls: {args, kwargs}
    - .raises() side effects: {args, kwargs, raised}
    - Spy returned: {args, kwargs, returned}
    - Spy raised: {args, kwargs, raised}
    """
    base = {"args", "kwargs"}
    if "raised" in interaction.details:
        base.add("raised")
    if "returned" in interaction.details:
        base.add("returned")
    return frozenset(base)

get_unused_mocks

get_unused_mocks()

Return MockConfig objects that are required=True and still in the queue (never consumed).

Source code in src/tripwire/_mock_plugin.py
def get_unused_mocks(self) -> list[MockConfig]:
    """Return MockConfig objects that are required=True and still in the queue (never
    consumed)."""
    unused: list[MockConfig] = []
    # Legacy MockProxy path
    for proxy in self._proxies.values():
        methods = object.__getattribute__(proxy, "_methods")
        for method_proxy in methods.values():
            for config in method_proxy._config_queue:
                if config.required:
                    unused.append(config)
    # New _BaseMock path
    for mock in self._mocks:
        for method_proxy in mock._methods.values():
            for config in method_proxy._config_queue:
                if config.required:
                    unused.append(config)
    return unused

format_unused_mock_hint

format_unused_mock_hint(mock_config)

Hint for an unused mock: show registration traceback and how to suppress.

Source code in src/tripwire/_mock_plugin.py
def format_unused_mock_hint(self, mock_config: object) -> str:
    """Hint for an unused mock: show registration traceback and how to suppress."""
    assert isinstance(mock_config, MockConfig)
    return (
        f"mock:{mock_config.mock_name}.{mock_config.method_name}\n"
        f"    Mock registered at:\n"
        f"{mock_config.registration_traceback}\n"
        f"    Options:\n"
        f"      - Remove this mock if it's not needed\n"
        f'      - Mark it optional: tripwire.mock("{mock_config.mock_name}")'
        f".{mock_config.method_name}.required(False).returns(...)"
    )