import functools import warnings from pathlib import Path from typing import Optional from ..compat import LEGACY_PATH from ..compat import legacy_path from ..deprecated import HOOK_LEGACY_PATH_ARG from _pytest.nodes import _check_path # hookname: (Path, LEGACY_PATH) imply_paths_hooks = { "pytest_ignore_collect": ("collection_path", "path"), "pytest_collect_file": ("file_path", "path"), "pytest_pycollect_makemodule": ("module_path", "path"), "pytest_report_header": ("start_path", "startdir"), "pytest_report_collectionfinish": ("start_path", "startdir"), } class PathAwareHookProxy: """ this helper wraps around hook callers until pluggy supports fixingcalls, this one will do it currently doesn't return full hook caller proxies for fixed hooks, this may have to be changed later depending on bugs """ def __init__(self, hook_caller): self.__hook_caller = hook_caller def __dir__(self): return dir(self.__hook_caller) def __getattr__(self, key, _wraps=functools.wraps): hook = getattr(self.__hook_caller, key) if key not in imply_paths_hooks: self.__dict__[key] = hook return hook else: path_var, fspath_var = imply_paths_hooks[key] @_wraps(hook) def fixed_hook(**kw): path_value: Optional[Path] = kw.pop(path_var, None) fspath_value: Optional[LEGACY_PATH] = kw.pop(fspath_var, None) if fspath_value is not None: warnings.warn( HOOK_LEGACY_PATH_ARG.format( pylib_path_arg=fspath_var, pathlib_path_arg=path_var ), stacklevel=2, ) if path_value is not None: if fspath_value is not None: _check_path(path_value, fspath_value) else: fspath_value = legacy_path(path_value) else: assert fspath_value is not None path_value = Path(fspath_value) kw[path_var] = path_value kw[fspath_var] = fspath_value return hook(**kw) fixed_hook.__name__ = key self.__dict__[key] = fixed_hook return fixed_hook