1 import functools

2 import warnings

3 from pathlib import Path

4 from typing import Optional

5

6 from ..compat import LEGACY_PATH

7 from ..compat import legacy_path

8 from ..deprecated import HOOK_LEGACY_PATH_ARG

9 from _pytest.nodes import _check_path

10

11# hookname: (Path, LEGACY_PATH)

12 imply_paths_hooks = {

13 "pytest_ignore_collect": ("collection_path", "path"),

14 "pytest_collect_file": ("file_path", "path"),

15 "pytest_pycollect_makemodule": ("module_path", "path"),

16 "pytest_report_header": ("start_path", "startdir"),

17 "pytest_report_collectionfinish": ("start_path", "startdir"),

18}

19

20

21 class PathAwareHookProxy:

22 """

23 this helper wraps around hook callers

24 until pluggy supports fixingcalls, this one will do

25

26 it currently doesn't return full hook caller proxies for fixed hooks,

27 this may have to be changed later depending on bugs

28 """

29

30 def __init__(self, hook_caller):

31 self.__hook_caller = hook_caller

32

33 def __dir__(self):

34 return dir(self.__hook_caller)

35

36 def __getattr__(self, key, _wraps=functools.wraps):

37 hook = getattr(self.__hook_caller, key)

38 if key not in imply_paths_hooks:

39 self.__dict__[key] = hook

40 return hook

41 else:

42 path_var, fspath_var = imply_paths_hooks[key]

43

44 @_wraps(hook)

45 def fixed_hook(**kw):

46

47 path_value: Optional[Path] = kw.pop(path_var, None)

48 fspath_value: Optional[LEGACY_PATH] = kw.pop(fspath_var, None)

49 if fspath_value is not None:

50 warnings.warn(

51 HOOK_LEGACY_PATH_ARG.format(

52 pylib_path_arg=fspath_var, pathlib_path_arg=path_var

53 ),

54 stacklevel=2,

55 )

56 if path_value is not None:

57 if fspath_value is not None:

58 _check_path(path_value, fspath_value)

59 else:

60 fspath_value = legacy_path(path_value)

61 else:

62 assert fspath_value is not None

63 path_value = Path(fspath_value)

64

65 kw[path_var] = path_value

66 kw[fspath_var] = fspath_value

67 return hook(**kw)

68

69 fixed_hook.__name__ = key

70 self.__dict__[key] = fixed_hook

71 return fixed_hook