Skip to content

Commit 77f7f59

Browse files
committed
Fixes for typed pluggy
Since version 1.3 pluggy added typing, which requires some fixes to please mypy.
1 parent 7500fe4 commit 77f7f59

File tree

8 files changed

+33
-15
lines changed

8 files changed

+33
-15
lines changed

changelog/11353.trivial.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pluggy>=1.3.0 is now required. This adds typing to :class:`~pytest.PytestPluginManager`.

doc/en/reference/reference.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -980,10 +980,10 @@ TestShortLogReport
980980
.. autoclass:: pytest.TestShortLogReport()
981981
:members:
982982

983-
_Result
983+
Result
984984
~~~~~~~
985985

986-
Result object used within :ref:`hook wrappers <hookwrapper>`, see :py:class:`_Result in the pluggy documentation <pluggy._callers._Result>` for more information.
986+
Result object used within :ref:`hook wrappers <hookwrapper>`, see :py:class:`Result in the pluggy documentation <pluggy.Result>` for more information.
987987

988988
Stash
989989
~~~~~

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ py_modules = py
4646
install_requires =
4747
iniconfig
4848
packaging
49-
pluggy>=1.2.0,<2.0
49+
pluggy>=1.3.0,<2.0
5050
colorama;sys_platform=="win32"
5151
exceptiongroup>=1.0.0rc8;python_version<"3.11"
5252
tomli>=1.0.0;python_version<"3.11"

src/_pytest/config/__init__.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@
3838
from typing import Union
3939

4040
from pluggy import HookimplMarker
41+
from pluggy import HookimplOpts
4142
from pluggy import HookspecMarker
43+
from pluggy import HookspecOpts
4244
from pluggy import PluginManager
4345

4446
import _pytest._code
@@ -440,15 +442,17 @@ def __init__(self) -> None:
440442
# Used to know when we are importing conftests after the pytest_configure stage.
441443
self._configured = False
442444

443-
def parse_hookimpl_opts(self, plugin: _PluggyPlugin, name: str):
445+
def parse_hookimpl_opts(
446+
self, plugin: _PluggyPlugin, name: str
447+
) -> Optional[HookimplOpts]:
444448
# pytest hooks are always prefixed with "pytest_",
445449
# so we avoid accessing possibly non-readable attributes
446450
# (see issue #1073).
447451
if not name.startswith("pytest_"):
448-
return
452+
return None
449453
# Ignore names which can not be hooks.
450454
if name == "pytest_plugins":
451-
return
455+
return None
452456

453457
opts = super().parse_hookimpl_opts(plugin, name)
454458
if opts is not None:
@@ -457,18 +461,18 @@ def parse_hookimpl_opts(self, plugin: _PluggyPlugin, name: str):
457461
method = getattr(plugin, name)
458462
# Consider only actual functions for hooks (#3775).
459463
if not inspect.isroutine(method):
460-
return
464+
return None
461465
# Collect unmarked hooks as long as they have the `pytest_' prefix.
462-
return _get_legacy_hook_marks(
466+
return _get_legacy_hook_marks( # type: ignore[return-value]
463467
method, "impl", ("tryfirst", "trylast", "optionalhook", "hookwrapper")
464468
)
465469

466-
def parse_hookspec_opts(self, module_or_class, name: str):
470+
def parse_hookspec_opts(self, module_or_class, name: str) -> Optional[HookspecOpts]:
467471
opts = super().parse_hookspec_opts(module_or_class, name)
468472
if opts is None:
469473
method = getattr(module_or_class, name)
470474
if name.startswith("pytest_"):
471-
opts = _get_legacy_hook_marks(
475+
opts = _get_legacy_hook_marks( # type: ignore[assignment]
472476
method,
473477
"spec",
474478
("firstresult", "historic"),
@@ -1067,9 +1071,10 @@ def _ensure_unconfigure(self) -> None:
10671071
fin()
10681072

10691073
def get_terminal_writer(self) -> TerminalWriter:
1070-
terminalreporter: TerminalReporter = self.pluginmanager.get_plugin(
1074+
terminalreporter: Optional[TerminalReporter] = self.pluginmanager.get_plugin(
10711075
"terminalreporter"
10721076
)
1077+
assert terminalreporter is not None
10731078
return terminalreporter._tw
10741079

10751080
def pytest_cmdline_parse(

src/_pytest/helpconfig.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from _pytest.config import ExitCode
1313
from _pytest.config import PrintHelp
1414
from _pytest.config.argparsing import Parser
15+
from _pytest.terminal import TerminalReporter
1516

1617

1718
class HelpAction(Action):
@@ -161,7 +162,10 @@ def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]:
161162
def showhelp(config: Config) -> None:
162163
import textwrap
163164

164-
reporter = config.pluginmanager.get_plugin("terminalreporter")
165+
reporter: Optional[TerminalReporter] = config.pluginmanager.get_plugin(
166+
"terminalreporter"
167+
)
168+
assert reporter is not None
165169
tw = reporter._tw
166170
tw.write(config._parser.optparser.format_help())
167171
tw.line()

src/_pytest/logging.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,8 @@ def __init__(self, config: Config) -> None:
659659
)
660660
if self._log_cli_enabled():
661661
terminal_reporter = config.pluginmanager.get_plugin("terminalreporter")
662+
# Guaranteed by `_log_cli_enabled()`.
663+
assert terminal_reporter is not None
662664
capture_manager = config.pluginmanager.get_plugin("capturemanager")
663665
# if capturemanager plugin is disabled, live logging still works.
664666
self.log_cli_handler: Union[

src/_pytest/pytester.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ def preserve_module(name):
751751

752752
def make_hook_recorder(self, pluginmanager: PytestPluginManager) -> HookRecorder:
753753
"""Create a new :class:`HookRecorder` for a :class:`PytestPluginManager`."""
754-
pluginmanager.reprec = reprec = HookRecorder(pluginmanager, _ispytest=True)
754+
pluginmanager.reprec = reprec = HookRecorder(pluginmanager, _ispytest=True) # type: ignore[attr-defined]
755755
self._request.addfinalizer(reprec.finish_recording)
756756
return reprec
757757

testing/test_pluginmanager.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,12 @@ def test_consider_module(
242242
mod = types.ModuleType("temp")
243243
mod.__dict__["pytest_plugins"] = ["pytest_p1", "pytest_p2"]
244244
pytestpm.consider_module(mod)
245-
assert pytestpm.get_plugin("pytest_p1").__name__ == "pytest_p1"
246-
assert pytestpm.get_plugin("pytest_p2").__name__ == "pytest_p2"
245+
p1 = pytestpm.get_plugin("pytest_p1")
246+
assert p1 is not None
247+
assert p1.__name__ == "pytest_p1"
248+
p2 = pytestpm.get_plugin("pytest_p2")
249+
assert p2 is not None
250+
assert p2.__name__ == "pytest_p2"
247251

248252
def test_consider_module_import_module(
249253
self, pytester: Pytester, _config_for_test: Config
@@ -336,6 +340,7 @@ def test_import_plugin_importname(
336340
len2 = len(pytestpm.get_plugins())
337341
assert len1 == len2
338342
plugin1 = pytestpm.get_plugin("pytest_hello")
343+
assert plugin1 is not None
339344
assert plugin1.__name__.endswith("pytest_hello")
340345
plugin2 = pytestpm.get_plugin("pytest_hello")
341346
assert plugin2 is plugin1
@@ -351,6 +356,7 @@ def test_import_plugin_dotted_name(
351356
pluginname = "pkg.plug"
352357
pytestpm.import_plugin(pluginname)
353358
mod = pytestpm.get_plugin("pkg.plug")
359+
assert mod is not None
354360
assert mod.x == 3
355361

356362
def test_consider_conftest_deps(

0 commit comments

Comments
 (0)