From 0da33858256bcdc77a28064ec902a554b7829d79 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Sat, 15 Aug 2020 11:35:54 +0300 Subject: [PATCH] Only define gethookproxy, isinitpath on Session This fixes an issue where pylint complains about missing implementations of abstract methods in subclasses of `File` which only override `collect()` (as they should). It is also cleaner and makes sense, these methods really don't need to be overridden. See commits e2934c3f8c03c83469f4c6670c207773a6e02df4 and f10ab021e21a44e2f0fa2be66660c4a6d4b7a61a for reference. --- changelog/7591.bugfix.rst | 1 + src/_pytest/main.py | 27 ++++++++++++++++++++++++- src/_pytest/nodes.py | 42 ++++----------------------------------- src/_pytest/python.py | 6 ------ 4 files changed, 31 insertions(+), 45 deletions(-) create mode 100644 changelog/7591.bugfix.rst diff --git a/changelog/7591.bugfix.rst b/changelog/7591.bugfix.rst new file mode 100644 index 00000000000..10de43a96a5 --- /dev/null +++ b/changelog/7591.bugfix.rst @@ -0,0 +1 @@ +pylint shouldn't complain anymore about unimplemented abstract methods when inheriting from :ref:`File `. diff --git a/src/_pytest/main.py b/src/_pytest/main.py index 0baa22a6aaf..58d45ebd196 100644 --- a/src/_pytest/main.py +++ b/src/_pytest/main.py @@ -27,6 +27,7 @@ from _pytest.config import directory_arg from _pytest.config import ExitCode from _pytest.config import hookimpl +from _pytest.config import PytestPluginManager from _pytest.config import UsageError from _pytest.config.argparsing import Parser from _pytest.fixtures import FixtureManager @@ -389,6 +390,17 @@ def pytest_collection_modifyitems(items: List[nodes.Item], config: Config) -> No items[:] = remaining +class FSHookProxy: + def __init__(self, pm: PytestPluginManager, remove_mods) -> None: + self.pm = pm + self.remove_mods = remove_mods + + def __getattr__(self, name: str): + x = self.pm.subset_hook_caller(name, remove_plugins=self.remove_mods) + self.__dict__[name] = x + return x + + class NoMatch(Exception): """Matching cannot locate matching names.""" @@ -495,7 +507,20 @@ def isinitpath(self, path: py.path.local) -> bool: return path in self._initialpaths def gethookproxy(self, fspath: py.path.local): - return super()._gethookproxy(fspath) + # Check if we have the common case of running + # hooks with all conftest.py files. + pm = self.config.pluginmanager + my_conftestmodules = pm._getconftestmodules( + fspath, self.config.getoption("importmode") + ) + remove_mods = pm._conftest_plugins.difference(my_conftestmodules) + if remove_mods: + # One or more conftests are not in use at this fspath. + proxy = FSHookProxy(pm, remove_mods) + else: + # All plugins are active for this fspath. + proxy = self.config.hook + return proxy @overload def perform_collect( diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 9d2365c4d5e..a143f82a066 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -25,7 +25,6 @@ from _pytest.compat import TYPE_CHECKING from _pytest.config import Config from _pytest.config import ConftestImportFailure -from _pytest.config import PytestPluginManager from _pytest.deprecated import NODE_USE_FROM_PARENT from _pytest.fixtures import FixtureDef from _pytest.fixtures import FixtureLookupError @@ -495,17 +494,6 @@ def _check_initialpaths_for_relpath(session, fspath): return fspath.relto(initial_path) -class FSHookProxy: - def __init__(self, pm: PytestPluginManager, remove_mods) -> None: - self.pm = pm - self.remove_mods = remove_mods - - def __getattr__(self, name: str): - x = self.pm.subset_hook_caller(name, remove_plugins=self.remove_mods) - self.__dict__[name] = x - return x - - class FSCollector(Collector): def __init__( self, @@ -542,42 +530,20 @@ def from_parent(cls, parent, *, fspath, **kw): """The public constructor.""" return super().from_parent(parent=parent, fspath=fspath, **kw) - def _gethookproxy(self, fspath: py.path.local): - # Check if we have the common case of running - # hooks with all conftest.py files. - pm = self.config.pluginmanager - my_conftestmodules = pm._getconftestmodules( - fspath, self.config.getoption("importmode") - ) - remove_mods = pm._conftest_plugins.difference(my_conftestmodules) - if remove_mods: - # One or more conftests are not in use at this fspath. - proxy = FSHookProxy(pm, remove_mods) - else: - # All plugins are active for this fspath. - proxy = self.config.hook - return proxy - - def gethookproxy(self, fspath: py.path.local): - raise NotImplementedError() - def _recurse(self, direntry: "os.DirEntry[str]") -> bool: if direntry.name == "__pycache__": return False path = py.path.local(direntry.path) - ihook = self._gethookproxy(path.dirpath()) + ihook = self.session.gethookproxy(path.dirpath()) if ihook.pytest_ignore_collect(path=path, config=self.config): return False for pat in self._norecursepatterns: if path.check(fnmatch=pat): return False - ihook = self._gethookproxy(path) + ihook = self.session.gethookproxy(path) ihook.pytest_collect_directory(path=path, parent=self) return True - def isinitpath(self, path: py.path.local) -> bool: - raise NotImplementedError() - def _collectfile( self, path: py.path.local, handle_dupes: bool = True ) -> Sequence[Collector]: @@ -586,8 +552,8 @@ def _collectfile( ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( path, path.isdir(), path.exists(), path.islink() ) - ihook = self.gethookproxy(path) - if not self.isinitpath(path): + ihook = self.session.gethookproxy(path) + if not self.session.isinitpath(path): if ihook.pytest_ignore_collect(path=path, config=self.config): return () diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 0661f340209..41fe58ebdea 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -626,12 +626,6 @@ def setup(self) -> None: func = partial(_call_with_optional_argument, teardown_module, self.obj) self.addfinalizer(func) - def gethookproxy(self, fspath: py.path.local): - return super()._gethookproxy(fspath) - - def isinitpath(self, path: py.path.local) -> bool: - return path in self.session._initialpaths - def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: this_path = self.fspath.dirpath() init_module = this_path.join("__init__.py")