compat.py

Overview

The `compat.py` file serves as a compatibility layer to facilitate smooth interaction with the `pluggy` plugin system, particularly when dealing with path-related hooks that historically accepted legacy path arguments. It provides a wrapper class, `PathAwareHookProxy`, that transparently manages the coexistence of modern `pathlib.Path` objects and legacy path representations (`LEGACY_PATH`), ensuring backward compatibility while encouraging usage of modern APIs.

This module addresses the problem where certain plugin hooks accept two arguments representing the same filesystem location: one as a `pathlib.Path` object and another as a legacy string/path representation. The compatibility logic enforces consistency between these arguments and provides warnings when legacy arguments are used, helping plugin authors migrate to the new style.

Detailed Documentation


Constants and Mappings

imply_paths_hooks: Mapping[str, tuple[str, str]]


Functions

_check_path(path: Path, fspath: LEGACY_PATH) -> None


Classes

PathAwareHookProxy

A proxy wrapper around `pluggy.HookRelay` to support legacy and modern path argument compatibility in plugin hooks.

Purpose

`PathAwareHookProxy` intercepts calls to plugin hooks that accept both legacy and modern path arguments, enforcing consistency and issuing deprecation warnings when legacy arguments are used. It allows existing plugins that use legacy path arguments to continue functioning while new plugins can use modern `pathlib.Path` arguments.

Initialization
PathAwareHookProxy(hook_relay: pluggy.HookRelay) -> None
Methods
import pluggy
from compat import PathAwareHookProxy

hook_relay = pluggy.HookRelay("pytest")
proxy = PathAwareHookProxy(hook_relay)

# Accessing a wrapped hook
result = proxy.pytest_ignore_collect(collection_path=Path("/tmp"), path="/tmp")
# This will check and warn if legacy 'path' is used, ensure consistency, and call the original hook.
Important Implementation Details

Implementation Details and Algorithms


Interactions with Other System Components


Visual Diagram

classDiagram
    class PathAwareHookProxy {
        - _hook_relay: pluggy.HookRelay
        + __init__(hook_relay)
        + __dir__() list~str~
        + __getattr__(key) pluggy.HookCaller
    }

    class pluggy.HookRelay {
        + __getattr__(key) pluggy.HookCaller
    }

    class pluggy.HookCaller {
        + __call__(**kwargs) Any
    }

    PathAwareHookProxy --> pluggy.HookRelay : wraps
    PathAwareHookProxy --> pluggy.HookCaller : returns wrapped or original

Summary

The `compat.py` file provides a crucial compatibility layer that bridges old and new path argument conventions in plugin hooks managed by pluggy. Its `PathAwareHookProxy` enables smooth coexistence of legacy plugins with modern Python path APIs, maintaining system stability during API evolution. This module is key in easing migration while enforcing argument correctness and encouraging adoption of `pathlib.Path`.


Example Usage Snippet

import pluggy
from compat import PathAwareHookProxy
from pathlib import Path

# Assume hook_relay is obtained from pluggy PluginManager or similar
hook_relay = pluggy.HookRelay("pytest")

# Wrap with compatibility proxy
hook_proxy = PathAwareHookProxy(hook_relay)

# Call a hook that expects path arguments
results = hook_proxy.pytest_collect_file(
    file_path=Path("/path/to/file"),
    path="/path/to/file"  # legacy argument, will emit warning
)

This will check that both paths are equivalent, warn about the deprecated legacy argument, and call the underlying hook with consistent arguments.