From 4ddf6c647c7fdc94efb55e64a01ee4e2c0b696e9 Mon Sep 17 00:00:00 2001 From: Ronny Pfannschmidt Date: Sat, 20 Mar 2021 23:39:38 +0100 Subject: [PATCH] test warnings and fix invocation bugs --- .pre-commit-config.yaml | 2 +- src/_pytest/config/compat.py | 14 ++++++++++++-- src/_pytest/deprecated.py | 4 ++++ testing/deprecated_test.py | 21 +++++++++++++++++++++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b96fdccf1..132204309 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -89,7 +89,7 @@ repos: types: [python] - id: py-path-deprecated name: py.path usage is deprecated + exclude: docs|src/_pytest/deprecated.py|testing/deprecated_test.py language: pygrep entry: \bpy\.path\.local - exclude: docs types: [python] diff --git a/src/_pytest/config/compat.py b/src/_pytest/config/compat.py index 28b0b524a..82572a970 100644 --- a/src/_pytest/config/compat.py +++ b/src/_pytest/config/compat.py @@ -1,8 +1,9 @@ -import functools +import warnings from pathlib import Path from typing import Optional from ..compat import LEGACY_PATH +from ..deprecated import HOOK_LEGACY_PATH_ARG from _pytest.nodes import _imply_path # hookname: (Path, LEGACY_PATH) @@ -19,6 +20,9 @@ class PathAwareHookProxy: def __init__(self, hook_caller): self.__hook_caller = hook_caller + def __dir__(self): + return dir(self.__hook_caller) + def __getattr__(self, key): if key not in imply_paths_hooks: return getattr(self.__hook_caller, key) @@ -26,13 +30,19 @@ class PathAwareHookProxy: hook = getattr(self.__hook_caller, key) path_var, fspath_var = imply_paths_hooks[key] - @functools.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 + ) + ) path_value, fspath_value = _imply_path(path_value, fspath_value) kw[path_var] = path_value kw[fspath_var] = fspath_value return hook(**kw) + fixed_hook.__name__ = key return fixed_hook diff --git a/src/_pytest/deprecated.py b/src/_pytest/deprecated.py index 596574877..9ac4d81b4 100644 --- a/src/_pytest/deprecated.py +++ b/src/_pytest/deprecated.py @@ -95,6 +95,10 @@ NODE_FSPATH = UnformattedWarning( "see https://docs.pytest.org/en/latest/deprecations.html#node-fspath-in-favor-of-pathlib-and-node-path", ) +HOOK_LEGACY_PATH_ARG = UnformattedWarning( + PytestDeprecationWarning, + "{pylib_path_arg} : py.path.local is deprecated, please use {pathlib_path_arg} : pathlib.Path", +) # You want to make some `__init__` or function "private". # # def my_private_function(some, args): diff --git a/testing/deprecated_test.py b/testing/deprecated_test.py index 18300f62a..41db42427 100644 --- a/testing/deprecated_test.py +++ b/testing/deprecated_test.py @@ -4,7 +4,9 @@ from unittest import mock import pytest from _pytest import deprecated +from _pytest.compat import legacy_path from _pytest.pytester import Pytester +from pytest import PytestDeprecationWarning @pytest.mark.parametrize("attribute", pytest.collect.__all__) # type: ignore @@ -153,3 +155,22 @@ def test_raising_unittest_skiptest_during_collection_is_deprecated( "*PytestDeprecationWarning: Raising unittest.SkipTest*", ] ) + + +def test_hookproxy_warnings_for_fspath(pytestconfig, tmp_path, request): + path = legacy_path(tmp_path) + + with pytest.warns( + PytestDeprecationWarning, + match="path : py.path.local is deprecated, please use fspath : pathlib.Path", + ): + pytestconfig.hook.pytest_ignore_collect( + config=pytestconfig, path=path, fspath=tmp_path + ) + with pytest.warns( + PytestDeprecationWarning, + match="path : py.path.local is deprecated, please use fspath : pathlib.Path", + ): + request.node.ihook.pytest_ignore_collect( + config=pytestconfig, path=path, fspath=tmp_path + )