From 0fb081aec6cd8ed95882d6e63ce93bd7ee4ba6ae Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Fri, 1 May 2020 14:40:15 +0300 Subject: [PATCH] Type annotate some hookspecs & impls Annotate some "easy" arguments of hooks that repeat in a lot of internal plugins. Not all of the arguments are annotated fully for now. --- src/_pytest/assertion/__init__.py | 5 ++- src/_pytest/cacheprovider.py | 14 +++++-- src/_pytest/capture.py | 3 +- src/_pytest/config/__init__.py | 6 ++- src/_pytest/debugging.py | 11 ++++-- src/_pytest/doctest.py | 5 ++- src/_pytest/faulthandler.py | 10 +++-- src/_pytest/fixtures.py | 5 ++- src/_pytest/helpconfig.py | 14 +++++-- src/_pytest/hookspec.py | 65 ++++++++++++++++++------------- src/_pytest/junitxml.py | 12 +++--- src/_pytest/logging.py | 11 +++--- src/_pytest/mark/__init__.py | 13 +++++-- src/_pytest/mark/structures.py | 2 +- src/_pytest/nodes.py | 2 +- src/_pytest/pastebin.py | 8 ++-- src/_pytest/pytester.py | 7 ++-- src/_pytest/python.py | 17 +++++--- src/_pytest/resultlog.py | 8 ++-- src/_pytest/runner.py | 9 +++-- src/_pytest/setuponly.py | 11 +++++- src/_pytest/setupplan.py | 12 +++++- src/_pytest/skipping.py | 8 ++-- src/_pytest/stepwise.py | 11 ++++-- src/_pytest/terminal.py | 13 ++++--- src/_pytest/warnings.py | 6 ++- 26 files changed, 185 insertions(+), 103 deletions(-) diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index b38c6c006..e73981677 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -13,12 +13,13 @@ from _pytest.assertion.rewrite import assertstate_key from _pytest.compat import TYPE_CHECKING from _pytest.config import Config from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser if TYPE_CHECKING: from _pytest.main import Session -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("debugconfig") group.addoption( "--assert", @@ -167,7 +168,7 @@ def pytest_runtest_protocol(item): util._reprcompare, util._assertion_pass = saved_assert_hooks -def pytest_sessionfinish(session): +def pytest_sessionfinish(session: "Session") -> None: assertstate = session.config._store.get(assertstate_key, None) if assertstate: if assertstate.hook is not None: diff --git a/src/_pytest/cacheprovider.py b/src/_pytest/cacheprovider.py index 511ee2acf..cd43c6cac 100755 --- a/src/_pytest/cacheprovider.py +++ b/src/_pytest/cacheprovider.py @@ -11,6 +11,7 @@ from typing import Generator from typing import List from typing import Optional from typing import Set +from typing import Union import attr import py @@ -24,6 +25,8 @@ from _pytest import nodes from _pytest._io import TerminalWriter from _pytest.compat import order_preserving_dict from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config.argparsing import Parser from _pytest.main import Session from _pytest.python import Module @@ -329,11 +332,12 @@ class LFPlugin: else: self._report_status += "not deselecting items." - def pytest_sessionfinish(self, session): + def pytest_sessionfinish(self, session: Session) -> None: config = self.config if config.getoption("cacheshow") or hasattr(config, "slaveinput"): return + assert config.cache is not None saved_lastfailed = config.cache.get("cache/lastfailed", {}) if saved_lastfailed != self.lastfailed: config.cache.set("cache/lastfailed", self.lastfailed) @@ -382,7 +386,7 @@ class NFPlugin: config.cache.set("cache/nodeids", sorted(self.cached_nodeids)) -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("general") group.addoption( "--lf", @@ -440,16 +444,18 @@ def pytest_addoption(parser): ) -def pytest_cmdline_main(config): +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: if config.option.cacheshow: from _pytest.main import wrap_session return wrap_session(config, cacheshow) + return None @pytest.hookimpl(tryfirst=True) def pytest_configure(config: Config) -> None: - config.cache = Cache.for_config(config) + # Type ignored: pending mechanism to store typed objects scoped to config. + config.cache = Cache.for_config(config) # type: ignore # noqa: F821 config.pluginmanager.register(LFPlugin(config), "lfplugin") config.pluginmanager.register(NFPlugin(config), "nfplugin") diff --git a/src/_pytest/capture.py b/src/_pytest/capture.py index 64f4b8b92..5a0cfff36 100644 --- a/src/_pytest/capture.py +++ b/src/_pytest/capture.py @@ -16,6 +16,7 @@ from typing import Tuple import pytest from _pytest.compat import TYPE_CHECKING from _pytest.config import Config +from _pytest.config.argparsing import Parser if TYPE_CHECKING: from typing_extensions import Literal @@ -23,7 +24,7 @@ if TYPE_CHECKING: _CaptureMethod = Literal["fd", "sys", "no", "tee-sys"] -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("general") group._addoption( "--capture", diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 2da7e33aa..d9abc17b4 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -407,7 +407,7 @@ class PytestPluginManager(PluginManager): """Return True if the plugin with the given name is registered.""" return bool(self.get_plugin(name)) - def pytest_configure(self, config): + def pytest_configure(self, config: "Config") -> None: # XXX now that the pluginmanager exposes hookimpl(tryfirst...) # we should remove tryfirst/trylast as markers config.addinivalue_line( @@ -868,7 +868,9 @@ class Config: def get_terminal_writer(self): return self.pluginmanager.get_plugin("terminalreporter")._tw - def pytest_cmdline_parse(self, pluginmanager, args): + def pytest_cmdline_parse( + self, pluginmanager: PytestPluginManager, args: List[str] + ) -> object: try: self.parse(args) except UsageError: diff --git a/src/_pytest/debugging.py b/src/_pytest/debugging.py index 26c3095dc..0085d3197 100644 --- a/src/_pytest/debugging.py +++ b/src/_pytest/debugging.py @@ -4,8 +4,11 @@ import functools import sys from _pytest import outcomes +from _pytest.config import Config from _pytest.config import ConftestImportFailure from _pytest.config import hookimpl +from _pytest.config import PytestPluginManager +from _pytest.config.argparsing import Parser from _pytest.config.exceptions import UsageError @@ -20,7 +23,7 @@ def _validate_usepdb_cls(value): return (modname, classname) -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("general") group._addoption( "--pdb", @@ -44,7 +47,7 @@ def pytest_addoption(parser): ) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: import pdb if config.getvalue("trace"): @@ -74,8 +77,8 @@ def pytest_configure(config): class pytestPDB: """ Pseudo PDB that defers to the real pdb. """ - _pluginmanager = None - _config = None + _pluginmanager = None # type: PytestPluginManager + _config = None # type: Config _saved = [] # type: list _recursive_debug = 0 _wrapped_pdb_cls = None diff --git a/src/_pytest/doctest.py b/src/_pytest/doctest.py index e1dd9691c..50f115cd1 100644 --- a/src/_pytest/doctest.py +++ b/src/_pytest/doctest.py @@ -23,6 +23,7 @@ from _pytest._code.code import TerminalRepr from _pytest._io import TerminalWriter from _pytest.compat import safe_getattr from _pytest.compat import TYPE_CHECKING +from _pytest.config.argparsing import Parser from _pytest.fixtures import FixtureRequest from _pytest.outcomes import OutcomeException from _pytest.python_api import approx @@ -52,7 +53,7 @@ RUNNER_CLASS = None CHECKER_CLASS = None # type: Optional[Type[doctest.OutputChecker]] -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: parser.addini( "doctest_optionflags", "option flags for doctests", @@ -102,7 +103,7 @@ def pytest_addoption(parser): ) -def pytest_unconfigure(): +def pytest_unconfigure() -> None: global RUNNER_CLASS RUNNER_CLASS = None diff --git a/src/_pytest/faulthandler.py b/src/_pytest/faulthandler.py index 32e3e50c9..9d777b415 100644 --- a/src/_pytest/faulthandler.py +++ b/src/_pytest/faulthandler.py @@ -4,13 +4,15 @@ import sys from typing import TextIO import pytest +from _pytest.config import Config +from _pytest.config.argparsing import Parser from _pytest.store import StoreKey fault_handler_stderr_key = StoreKey[TextIO]() -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: help = ( "Dump the traceback of all threads if a test takes " "more than TIMEOUT seconds to finish." @@ -18,7 +20,7 @@ def pytest_addoption(parser): parser.addini("faulthandler_timeout", help, default=0.0) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: import faulthandler if not faulthandler.is_enabled(): @@ -46,14 +48,14 @@ class FaultHandlerHooks: """Implements hooks that will actually install fault handler before tests execute, as well as correctly handle pdb and internal errors.""" - def pytest_configure(self, config): + def pytest_configure(self, config: Config) -> None: import faulthandler stderr_fd_copy = os.dup(self._get_stderr_fileno()) config._store[fault_handler_stderr_key] = open(stderr_fd_copy, "w") faulthandler.enable(file=config._store[fault_handler_stderr_key]) - def pytest_unconfigure(self, config): + def pytest_unconfigure(self, config: Config) -> None: import faulthandler faulthandler.disable() diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index a1574634a..4583e70f2 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -29,6 +29,7 @@ from _pytest.compat import NOTSET from _pytest.compat import order_preserving_dict from _pytest.compat import safe_getattr from _pytest.compat import TYPE_CHECKING +from _pytest.config.argparsing import Parser from _pytest.deprecated import FILLFUNCARGS from _pytest.deprecated import FIXTURE_POSITIONAL_ARGUMENTS from _pytest.deprecated import FUNCARGNAMES @@ -49,7 +50,7 @@ class PseudoFixtureDef: scope = attr.ib() -def pytest_sessionstart(session: "Session"): +def pytest_sessionstart(session: "Session") -> None: import _pytest.python import _pytest.nodes @@ -1202,7 +1203,7 @@ def pytestconfig(request): return request.config -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: parser.addini( "usefixtures", type="args", diff --git a/src/_pytest/helpconfig.py b/src/_pytest/helpconfig.py index 402ffae66..c2519c8af 100644 --- a/src/_pytest/helpconfig.py +++ b/src/_pytest/helpconfig.py @@ -2,11 +2,16 @@ import os import sys from argparse import Action +from typing import Optional +from typing import Union import py import pytest +from _pytest.config import Config +from _pytest.config import ExitCode from _pytest.config import PrintHelp +from _pytest.config.argparsing import Parser class HelpAction(Action): @@ -36,7 +41,7 @@ class HelpAction(Action): raise PrintHelp -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("debugconfig") group.addoption( "--version", @@ -109,7 +114,7 @@ def pytest_cmdline_parse(): undo_tracing = config.pluginmanager.enable_tracing() sys.stderr.write("writing pytestdebug information to %s\n" % path) - def unset_tracing(): + def unset_tracing() -> None: debugfile.close() sys.stderr.write("wrote pytestdebug information to %s\n" % debugfile.name) config.trace.root.setwriter(None) @@ -133,7 +138,7 @@ def showversion(config): sys.stderr.write("pytest {}\n".format(pytest.__version__)) -def pytest_cmdline_main(config): +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: if config.option.version > 0: showversion(config) return 0 @@ -142,9 +147,10 @@ def pytest_cmdline_main(config): showhelp(config) config._ensure_unconfigure() return 0 + return None -def showhelp(config): +def showhelp(config: Config) -> None: import textwrap reporter = config.pluginmanager.get_plugin("terminalreporter") diff --git a/src/_pytest/hookspec.py b/src/_pytest/hookspec.py index de29a40bf..8b4505691 100644 --- a/src/_pytest/hookspec.py +++ b/src/_pytest/hookspec.py @@ -1,5 +1,6 @@ """ hook specifications for pytest plugins, invoked from main.py and builtin plugins. """ from typing import Any +from typing import List from typing import Mapping from typing import Optional from typing import Tuple @@ -14,10 +15,14 @@ from _pytest.compat import TYPE_CHECKING if TYPE_CHECKING: import warnings from _pytest.config import Config + from _pytest.config import ExitCode + from _pytest.config import PytestPluginManager + from _pytest.config import _PluggyPlugin + from _pytest.config.argparsing import Parser from _pytest.main import Session + from _pytest.python import Metafunc from _pytest.reports import BaseReport - hookspec = HookspecMarker("pytest") # ------------------------------------------------------------------------- @@ -26,7 +31,7 @@ hookspec = HookspecMarker("pytest") @hookspec(historic=True) -def pytest_addhooks(pluginmanager): +def pytest_addhooks(pluginmanager: "PytestPluginManager") -> None: """called at plugin registration time to allow adding new hooks via a call to ``pluginmanager.add_hookspecs(module_or_class, prefix)``. @@ -39,7 +44,9 @@ def pytest_addhooks(pluginmanager): @hookspec(historic=True) -def pytest_plugin_registered(plugin, manager): +def pytest_plugin_registered( + plugin: "_PluggyPlugin", manager: "PytestPluginManager" +) -> None: """ a new pytest plugin got registered. :param plugin: the plugin module or instance @@ -51,7 +58,7 @@ def pytest_plugin_registered(plugin, manager): @hookspec(historic=True) -def pytest_addoption(parser, pluginmanager): +def pytest_addoption(parser: "Parser", pluginmanager: "PytestPluginManager") -> None: """register argparse-style options and ini-style config values, called once at the beginning of a test run. @@ -89,7 +96,7 @@ def pytest_addoption(parser, pluginmanager): @hookspec(historic=True) -def pytest_configure(config): +def pytest_configure(config: "Config") -> None: """ Allows plugins and conftest files to perform initial configuration. @@ -113,7 +120,9 @@ def pytest_configure(config): @hookspec(firstresult=True) -def pytest_cmdline_parse(pluginmanager, args): +def pytest_cmdline_parse( + pluginmanager: "PytestPluginManager", args: List[str] +) -> Optional[object]: """return initialized config object, parsing the specified args. Stops at first non-None result, see :ref:`firstresult` @@ -127,7 +136,7 @@ def pytest_cmdline_parse(pluginmanager, args): """ -def pytest_cmdline_preparse(config, args): +def pytest_cmdline_preparse(config: "Config", args: List[str]) -> None: """(**Deprecated**) modify command line arguments before option parsing. This hook is considered deprecated and will be removed in a future pytest version. Consider @@ -142,7 +151,7 @@ def pytest_cmdline_preparse(config, args): @hookspec(firstresult=True) -def pytest_cmdline_main(config): +def pytest_cmdline_main(config: "Config") -> "Optional[Union[ExitCode, int]]": """ called for performing the main command line action. The default implementation will invoke the configure hooks and runtest_mainloop. @@ -155,7 +164,9 @@ def pytest_cmdline_main(config): """ -def pytest_load_initial_conftests(early_config, parser, args): +def pytest_load_initial_conftests( + early_config: "Config", parser: "Parser", args: List[str] +) -> None: """ implements the loading of initial conftest files ahead of command line option parsing. @@ -198,7 +209,7 @@ def pytest_collection(session: "Session") -> Optional[Any]: """ -def pytest_collection_modifyitems(session, config, items): +def pytest_collection_modifyitems(session: "Session", config: "Config", items): """ called after collection has been performed, may filter or re-order the items in-place. @@ -208,7 +219,7 @@ def pytest_collection_modifyitems(session, config, items): """ -def pytest_collection_finish(session): +def pytest_collection_finish(session: "Session"): """ called after collection has been performed and modified. :param _pytest.main.Session session: the pytest session object @@ -216,7 +227,7 @@ def pytest_collection_finish(session): @hookspec(firstresult=True) -def pytest_ignore_collect(path, config): +def pytest_ignore_collect(path, config: "Config"): """ return True to prevent considering this path for collection. This hook is consulted for all files and directories prior to calling more specific hooks. @@ -304,12 +315,12 @@ def pytest_pyfunc_call(pyfuncitem): Stops at first non-None result, see :ref:`firstresult` """ -def pytest_generate_tests(metafunc): +def pytest_generate_tests(metafunc: "Metafunc") -> None: """ generate (multiple) parametrized calls to a test function.""" @hookspec(firstresult=True) -def pytest_make_parametrize_id(config, val, argname): +def pytest_make_parametrize_id(config: "Config", val, argname) -> Optional[str]: """Return a user-friendly string representation of the given ``val`` that will be used by @pytest.mark.parametrize calls. Return None if the hook doesn't know about ``val``. The parameter name is available as ``argname``, if required. @@ -328,7 +339,7 @@ def pytest_make_parametrize_id(config, val, argname): @hookspec(firstresult=True) -def pytest_runtestloop(session): +def pytest_runtestloop(session: "Session"): """ called for performing the main runtest loop (after collection finished). @@ -411,7 +422,7 @@ def pytest_runtest_logreport(report): @hookspec(firstresult=True) -def pytest_report_to_serializable(config, report): +def pytest_report_to_serializable(config: "Config", report): """ Serializes the given report object into a data structure suitable for sending over the wire, e.g. converted to JSON. @@ -419,7 +430,7 @@ def pytest_report_to_serializable(config, report): @hookspec(firstresult=True) -def pytest_report_from_serializable(config, data): +def pytest_report_from_serializable(config: "Config", data): """ Restores a report object previously serialized with pytest_report_to_serializable(). """ @@ -456,7 +467,7 @@ def pytest_fixture_post_finalizer(fixturedef, request): # ------------------------------------------------------------------------- -def pytest_sessionstart(session): +def pytest_sessionstart(session: "Session") -> None: """ called after the ``Session`` object has been created and before performing collection and entering the run test loop. @@ -464,7 +475,9 @@ def pytest_sessionstart(session): """ -def pytest_sessionfinish(session, exitstatus): +def pytest_sessionfinish( + session: "Session", exitstatus: "Union[int, ExitCode]" +) -> None: """ called after whole test run finished, right before returning the exit status to the system. :param _pytest.main.Session session: the pytest session object @@ -472,7 +485,7 @@ def pytest_sessionfinish(session, exitstatus): """ -def pytest_unconfigure(config): +def pytest_unconfigure(config: "Config") -> None: """ called before test process is exited. :param _pytest.config.Config config: pytest config object @@ -484,7 +497,7 @@ def pytest_unconfigure(config): # ------------------------------------------------------------------------- -def pytest_assertrepr_compare(config, op, left, right): +def pytest_assertrepr_compare(config: "Config", op, left, right): """return explanation for comparisons in failing assert expressions. Return None for no custom explanation, otherwise return a list @@ -539,7 +552,7 @@ def pytest_assertion_pass(item, lineno, orig, expl): # ------------------------------------------------------------------------- -def pytest_report_header(config, startdir): +def pytest_report_header(config: "Config", startdir): """ return a string or list of strings to be displayed as header info for terminal reporting. :param _pytest.config.Config config: pytest config object @@ -560,7 +573,7 @@ def pytest_report_header(config, startdir): """ -def pytest_report_collectionfinish(config, startdir, items): +def pytest_report_collectionfinish(config: "Config", startdir, items): """ .. versionadded:: 3.2 @@ -610,7 +623,7 @@ def pytest_report_teststatus( """ -def pytest_terminal_summary(terminalreporter, exitstatus, config): +def pytest_terminal_summary(terminalreporter, exitstatus, config: "Config"): """Add a section to terminal summary reporting. :param _pytest.terminal.TerminalReporter terminalreporter: the internal terminal reporter object @@ -723,7 +736,7 @@ def pytest_exception_interact(node, call, report): """ -def pytest_enter_pdb(config, pdb): +def pytest_enter_pdb(config: "Config", pdb): """ called upon pdb.set_trace(), can be used by plugins to take special action just before the python debugger enters in interactive mode. @@ -732,7 +745,7 @@ def pytest_enter_pdb(config, pdb): """ -def pytest_leave_pdb(config, pdb): +def pytest_leave_pdb(config: "Config", pdb): """ called when leaving pdb (e.g. with continue after pdb.set_trace()). Can be used by plugins to take special action just after the python diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index b26112ac1..b0790bc79 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -21,7 +21,9 @@ import pytest from _pytest import deprecated from _pytest import nodes from _pytest import timing +from _pytest.config import Config from _pytest.config import filename_arg +from _pytest.config.argparsing import Parser from _pytest.store import StoreKey from _pytest.warnings import _issue_warning_captured @@ -361,7 +363,7 @@ def record_testsuite_property(request): return record_func -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("terminal reporting") group.addoption( "--junitxml", @@ -406,7 +408,7 @@ def pytest_addoption(parser): ) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: xmlpath = config.option.xmlpath # prevent opening xmllog on slave nodes (xdist) if xmlpath and not hasattr(config, "slaveinput"): @@ -426,7 +428,7 @@ def pytest_configure(config): config.pluginmanager.register(config._store[xml_key]) -def pytest_unconfigure(config): +def pytest_unconfigure(config: Config) -> None: xml = config._store.get(xml_key, None) if xml: del config._store[xml_key] @@ -624,10 +626,10 @@ class LogXML: reporter.attrs.update(classname="pytest", name="internal") reporter._add_simple(Junit.error, "internal error", excrepr) - def pytest_sessionstart(self): + def pytest_sessionstart(self) -> None: self.suite_start_time = timing.time() - def pytest_sessionfinish(self): + def pytest_sessionfinish(self) -> None: dirname = os.path.dirname(os.path.abspath(self.logfile)) if not os.path.isdir(dirname): os.makedirs(dirname) diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index f6a206327..b832f6994 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -19,6 +19,7 @@ from _pytest.compat import nullcontext from _pytest.config import _strtobool from _pytest.config import Config from _pytest.config import create_terminal_writer +from _pytest.config.argparsing import Parser from _pytest.pathlib import Path from _pytest.store import StoreKey @@ -180,7 +181,7 @@ def get_option_ini(config, *names): return ret -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: """Add options to control log capturing.""" group = parser.getgroup("logging") @@ -478,7 +479,7 @@ def get_log_level_for_setting(config: Config, *setting_names: str) -> Optional[i # run after terminalreporter/capturemanager are configured @pytest.hookimpl(trylast=True) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: config.pluginmanager.register(LoggingPlugin(config), "logging-plugin") @@ -601,7 +602,7 @@ class LoggingPlugin: return True @pytest.hookimpl(hookwrapper=True, tryfirst=True) - def pytest_sessionstart(self): + def pytest_sessionstart(self) -> Generator[None, None, None]: self.log_cli_handler.set_when("sessionstart") with catching_logs(self.log_cli_handler, level=self.log_cli_level): @@ -679,7 +680,7 @@ class LoggingPlugin: self.log_cli_handler.set_when("finish") @pytest.hookimpl(hookwrapper=True, tryfirst=True) - def pytest_sessionfinish(self): + def pytest_sessionfinish(self) -> Generator[None, None, None]: self.log_cli_handler.set_when("sessionfinish") with catching_logs(self.log_cli_handler, level=self.log_cli_level): @@ -687,7 +688,7 @@ class LoggingPlugin: yield @pytest.hookimpl - def pytest_unconfigure(self): + def pytest_unconfigure(self) -> None: # Close the FileHandler explicitly. # (logging.shutdown might have lost the weakref?!) self.log_file_handler.close() diff --git a/src/_pytest/mark/__init__.py b/src/_pytest/mark/__init__.py index c23a38c76..05afb7749 100644 --- a/src/_pytest/mark/__init__.py +++ b/src/_pytest/mark/__init__.py @@ -18,8 +18,10 @@ from .structures import MarkGenerator from .structures import ParameterSet from _pytest.compat import TYPE_CHECKING from _pytest.config import Config +from _pytest.config import ExitCode from _pytest.config import hookimpl from _pytest.config import UsageError +from _pytest.config.argparsing import Parser from _pytest.deprecated import MINUS_K_COLON from _pytest.deprecated import MINUS_K_DASH from _pytest.store import StoreKey @@ -27,6 +29,7 @@ from _pytest.store import StoreKey if TYPE_CHECKING: from _pytest.nodes import Item + __all__ = ["Mark", "MarkDecorator", "MarkGenerator", "get_empty_parameterset_mark"] @@ -57,7 +60,7 @@ def param( return ParameterSet.param(*values, marks=marks, id=id) -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("general") group._addoption( "-k", @@ -100,7 +103,7 @@ def pytest_addoption(parser): @hookimpl(tryfirst=True) -def pytest_cmdline_main(config): +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: import _pytest.config if config.option.markers: @@ -116,6 +119,8 @@ def pytest_cmdline_main(config): config._ensure_unconfigure() return 0 + return None + @attr.s(slots=True) class KeywordMatcher: @@ -254,7 +259,7 @@ def pytest_collection_modifyitems(items, config: Config) -> None: deselect_by_mark(items, config) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: config._store[old_mark_config_key] = MARK_GEN._config MARK_GEN._config = config @@ -267,5 +272,5 @@ def pytest_configure(config): ) -def pytest_unconfigure(config): +def pytest_unconfigure(config: Config) -> None: MARK_GEN._config = config._store.get(old_mark_config_key, None) diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index bfefe7a25..7ae7d5d4f 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -374,7 +374,7 @@ class MarkGenerator: applies a 'slowtest' :class:`Mark` on ``test_function``. """ - _config = None + _config = None # type: Optional[Config] _markers = set() # type: Set[str] def __getattr__(self, name: str) -> MarkDecorator: diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index df1c79dac..c9b633579 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -123,7 +123,7 @@ class Node(metaclass=NodeMeta): #: the pytest config object if config: - self.config = config + self.config = config # type: Config else: if not parent: raise TypeError("config or parent must be provided") diff --git a/src/_pytest/pastebin.py b/src/_pytest/pastebin.py index cbaa9a9f5..091d3f817 100644 --- a/src/_pytest/pastebin.py +++ b/src/_pytest/pastebin.py @@ -4,13 +4,15 @@ from io import StringIO from typing import IO import pytest +from _pytest.config import Config +from _pytest.config.argparsing import Parser from _pytest.store import StoreKey pastebinfile_key = StoreKey[IO[bytes]]() -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("terminal reporting") group._addoption( "--pastebin", @@ -24,7 +26,7 @@ def pytest_addoption(parser): @pytest.hookimpl(trylast=True) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: if config.option.pastebin == "all": tr = config.pluginmanager.getplugin("terminalreporter") # if no terminal reporter plugin is present, nothing we can do here; @@ -44,7 +46,7 @@ def pytest_configure(config): tr._tw.write = tee_write -def pytest_unconfigure(config): +def pytest_unconfigure(config: Config) -> None: if pastebinfile_key in config._store: pastebinfile = config._store[pastebinfile_key] # get terminal contents and delete file diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 3c81dd759..ae7bdcec8 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -31,6 +31,7 @@ from _pytest.compat import TYPE_CHECKING from _pytest.config import _PluggyPlugin from _pytest.config import Config from _pytest.config import ExitCode +from _pytest.config.argparsing import Parser from _pytest.fixtures import FixtureRequest from _pytest.main import Session from _pytest.monkeypatch import MonkeyPatch @@ -53,7 +54,7 @@ IGNORE_PAM = [ # filenames added when obtaining details about the current user ] -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: parser.addoption( "--lsof", action="store_true", @@ -78,7 +79,7 @@ def pytest_addoption(parser): ) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: if config.getvalue("lsof"): checker = LsofFdLeakChecker() if checker.matching_platform(): @@ -938,7 +939,7 @@ class Testdir: rec = [] class Collect: - def pytest_configure(x, config): + def pytest_configure(x, config: Config) -> None: rec.append(self.make_hook_recorder(config.pluginmanager)) plugins.append(Collect()) diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 76fccb4a1..45d3384df 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -16,6 +16,7 @@ from typing import Dict from typing import Iterable from typing import List from typing import Optional +from typing import Set from typing import Tuple from typing import Union @@ -42,9 +43,12 @@ from _pytest.compat import safe_getattr from _pytest.compat import safe_isclass from _pytest.compat import STRING_TYPES from _pytest.config import Config +from _pytest.config import ExitCode from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser from _pytest.deprecated import FUNCARGNAMES from _pytest.fixtures import FuncFixtureInfo +from _pytest.main import Session from _pytest.mark import MARK_GEN from _pytest.mark import ParameterSet from _pytest.mark.structures import get_unpacked_marks @@ -57,7 +61,7 @@ from _pytest.warning_types import PytestCollectionWarning from _pytest.warning_types import PytestUnhandledCoroutineWarning -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("general") group.addoption( "--fixtures", @@ -112,13 +116,14 @@ def pytest_addoption(parser): ) -def pytest_cmdline_main(config): +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: if config.option.showfixtures: showfixtures(config) return 0 if config.option.show_fixtures_per_test: show_fixtures_per_test(config) return 0 + return None def pytest_generate_tests(metafunc: "Metafunc") -> None: @@ -127,7 +132,7 @@ def pytest_generate_tests(metafunc: "Metafunc") -> None: metafunc.parametrize(*marker.args, **marker.kwargs, _param_mark=marker) # type: ignore[misc] -def pytest_configure(config): +def pytest_configure(config: Config) -> None: config.addinivalue_line( "markers", "parametrize(argnames, argvalues): call a test function multiple " @@ -1308,13 +1313,13 @@ def _show_fixtures_per_test(config, session): write_item(session_item) -def showfixtures(config): +def showfixtures(config: Config) -> Union[int, ExitCode]: from _pytest.main import wrap_session return wrap_session(config, _showfixtures_main) -def _showfixtures_main(config, session): +def _showfixtures_main(config: Config, session: Session) -> None: import _pytest.config session.perform_collect() @@ -1325,7 +1330,7 @@ def _showfixtures_main(config, session): fm = session._fixturemanager available = [] - seen = set() + seen = set() # type: Set[Tuple[str, str]] for argname, fixturedefs in fm._arg2fixturedefs.items(): assert fixturedefs is not None diff --git a/src/_pytest/resultlog.py b/src/_pytest/resultlog.py index 3cfa9e0e9..acc89afe2 100644 --- a/src/_pytest/resultlog.py +++ b/src/_pytest/resultlog.py @@ -5,13 +5,15 @@ import os import py +from _pytest.config import Config +from _pytest.config.argparsing import Parser from _pytest.store import StoreKey resultlog_key = StoreKey["ResultLog"]() -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("terminal reporting", "resultlog plugin options") group.addoption( "--resultlog", @@ -23,7 +25,7 @@ def pytest_addoption(parser): ) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: resultlog = config.option.resultlog # prevent opening resultlog on slave nodes (xdist) if resultlog and not hasattr(config, "slaveinput"): @@ -40,7 +42,7 @@ def pytest_configure(config): _issue_warning_captured(RESULT_LOG, config.hook, stacklevel=2) -def pytest_unconfigure(config): +def pytest_unconfigure(config: Config) -> None: resultlog = config._store.get(resultlog_key, None) if resultlog: resultlog.logfile.close() diff --git a/src/_pytest/runner.py b/src/_pytest/runner.py index dec6db788..c7f6d8811 100644 --- a/src/_pytest/runner.py +++ b/src/_pytest/runner.py @@ -17,6 +17,7 @@ from _pytest import timing from _pytest._code.code import ExceptionChainRepr from _pytest._code.code import ExceptionInfo from _pytest.compat import TYPE_CHECKING +from _pytest.config.argparsing import Parser from _pytest.nodes import Collector from _pytest.nodes import Node from _pytest.outcomes import Exit @@ -27,11 +28,13 @@ if TYPE_CHECKING: from typing import Type from typing_extensions import Literal + from _pytest.main import Session + # # pytest plugin hooks -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("terminal reporting", "reporting", after="general") group.addoption( "--durations", @@ -75,11 +78,11 @@ def pytest_terminal_summary(terminalreporter): tr.write_line("{:02.2f}s {:<8} {}".format(rep.duration, rep.when, rep.nodeid)) -def pytest_sessionstart(session): +def pytest_sessionstart(session: "Session") -> None: session._setupstate = SetupState() -def pytest_sessionfinish(session): +def pytest_sessionfinish(session: "Session") -> None: session._setupstate.teardown_all() diff --git a/src/_pytest/setuponly.py b/src/_pytest/setuponly.py index 9e4cd9519..fe328d519 100644 --- a/src/_pytest/setuponly.py +++ b/src/_pytest/setuponly.py @@ -1,8 +1,14 @@ +from typing import Optional +from typing import Union + import pytest from _pytest._io.saferepr import saferepr +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config.argparsing import Parser -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("debugconfig") group.addoption( "--setuponly", @@ -76,6 +82,7 @@ def _show_fixture_action(fixturedef, msg): @pytest.hookimpl(tryfirst=True) -def pytest_cmdline_main(config): +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: if config.option.setuponly: config.option.setupshow = True + return None diff --git a/src/_pytest/setupplan.py b/src/_pytest/setupplan.py index 6fdd3aed0..834d4ae2d 100644 --- a/src/_pytest/setupplan.py +++ b/src/_pytest/setupplan.py @@ -1,7 +1,13 @@ +from typing import Optional +from typing import Union + import pytest +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config.argparsing import Parser -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("debugconfig") group.addoption( "--setupplan", @@ -19,10 +25,12 @@ def pytest_fixture_setup(fixturedef, request): my_cache_key = fixturedef.cache_key(request) fixturedef.cached_result = (None, my_cache_key, None) return fixturedef.cached_result + return None @pytest.hookimpl(tryfirst=True) -def pytest_cmdline_main(config): +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: if config.option.setupplan: config.option.setuponly = True config.option.setupshow = True + return None diff --git a/src/_pytest/skipping.py b/src/_pytest/skipping.py index 62a9ca491..5e5fcc080 100644 --- a/src/_pytest/skipping.py +++ b/src/_pytest/skipping.py @@ -1,5 +1,7 @@ """ support for skip/xfail functions and markers. """ +from _pytest.config import Config from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser from _pytest.mark.evaluate import MarkEvaluator from _pytest.outcomes import fail from _pytest.outcomes import skip @@ -12,7 +14,7 @@ evalxfail_key = StoreKey[MarkEvaluator]() unexpectedsuccess_key = StoreKey[str]() -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("general") group.addoption( "--runxfail", @@ -31,7 +33,7 @@ def pytest_addoption(parser): ) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: if config.option.runxfail: # yay a hack import pytest @@ -42,7 +44,7 @@ def pytest_configure(config): def nop(*args, **kwargs): pass - nop.Exception = xfail.Exception + nop.Exception = xfail.Exception # type: ignore[attr-defined] # noqa: F821 setattr(pytest, "xfail", nop) config.addinivalue_line( diff --git a/src/_pytest/stepwise.py b/src/_pytest/stepwise.py index 6fa21cd1c..3cbf0be9f 100644 --- a/src/_pytest/stepwise.py +++ b/src/_pytest/stepwise.py @@ -1,7 +1,10 @@ import pytest +from _pytest.config import Config +from _pytest.config.argparsing import Parser +from _pytest.main import Session -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("general") group.addoption( "--sw", @@ -19,7 +22,7 @@ def pytest_addoption(parser): @pytest.hookimpl -def pytest_configure(config): +def pytest_configure(config: Config) -> None: config.pluginmanager.register(StepwisePlugin(config), "stepwiseplugin") @@ -34,7 +37,7 @@ class StepwisePlugin: self.lastfailed = config.cache.get("cache/stepwise", None) self.skip = config.getvalue("stepwise_skip") - def pytest_sessionstart(self, session): + def pytest_sessionstart(self, session: Session) -> None: self.session = session def pytest_collection_modifyitems(self, session, config, items): @@ -100,7 +103,7 @@ class StepwisePlugin: if self.active and self.config.getoption("verbose") >= 0 and self.report_status: return "stepwise: %s" % self.report_status - def pytest_sessionfinish(self, session): + def pytest_sessionfinish(self, session: Session) -> None: if self.active: self.config.cache.set("cache/stepwise", self.lastfailed) else: diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index e384e02b2..6f4b96e1e 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -17,6 +17,7 @@ from typing import Mapping from typing import Optional from typing import Set from typing import Tuple +from typing import Union import attr import pluggy @@ -29,8 +30,10 @@ from _pytest import timing from _pytest._io import TerminalWriter from _pytest._io.wcwidth import wcswidth from _pytest.compat import order_preserving_dict +from _pytest.config import _PluggyPlugin from _pytest.config import Config from _pytest.config import ExitCode +from _pytest.config.argparsing import Parser from _pytest.deprecated import TERMINALWRITER_WRITER from _pytest.main import Session from _pytest.reports import CollectReport @@ -77,7 +80,7 @@ class MoreQuietAction(argparse.Action): namespace.quiet = getattr(namespace, "quiet", 0) + 1 -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("terminal reporting", "reporting", after="general") group._addoption( "-v", @@ -423,7 +426,7 @@ class TerminalReporter: ) self._add_stats("warnings", [warning_report]) - def pytest_plugin_registered(self, plugin): + def pytest_plugin_registered(self, plugin: _PluggyPlugin) -> None: if self.config.option.traceconfig: msg = "PLUGIN registered: {}".format(plugin) # XXX this event may happen during setup/teardown time @@ -717,7 +720,7 @@ class TerminalReporter: self._tw.line("{}{}".format(indent + " ", line)) @pytest.hookimpl(hookwrapper=True) - def pytest_sessionfinish(self, session: Session, exitstatus: ExitCode): + def pytest_sessionfinish(self, session: Session, exitstatus: Union[int, ExitCode]): outcome = yield outcome.get_result() self._tw.line("") @@ -752,10 +755,10 @@ class TerminalReporter: # Display any extra warnings from teardown here (if any). self.summary_warnings() - def pytest_keyboard_interrupt(self, excinfo): + def pytest_keyboard_interrupt(self, excinfo) -> None: self._keyboardinterrupt_memo = excinfo.getrepr(funcargs=True) - def pytest_unconfigure(self): + def pytest_unconfigure(self) -> None: if hasattr(self, "_keyboardinterrupt_memo"): self._report_keyboardinterrupt() diff --git a/src/_pytest/warnings.py b/src/_pytest/warnings.py index 33d89428b..83e338cb3 100644 --- a/src/_pytest/warnings.py +++ b/src/_pytest/warnings.py @@ -8,6 +8,8 @@ from typing import Tuple import pytest from _pytest.compat import TYPE_CHECKING +from _pytest.config import Config +from _pytest.config.argparsing import Parser from _pytest.main import Session if TYPE_CHECKING: @@ -49,7 +51,7 @@ def _parse_filter( return (action, message, category, module, lineno) -def pytest_addoption(parser): +def pytest_addoption(parser: Parser) -> None: group = parser.getgroup("pytest-warnings") group.addoption( "-W", @@ -66,7 +68,7 @@ def pytest_addoption(parser): ) -def pytest_configure(config): +def pytest_configure(config: Config) -> None: config.addinivalue_line( "markers", "filterwarnings(warning): add a warning filter to the given test. "