From 7431750bb6e48106ded6acd70ef2e4c67aad294a Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Fri, 29 Oct 2021 21:18:12 +0300 Subject: [PATCH] doc: have tighter control on what autodoc shows New versions of sphinx starting showing `__init__` parameters even when we don't want them to show because they are private (have `_ispytest` argument). The only working solution I found was to switch to `autodoc_typehints_description_target = "documented"` and explicitly document parameters for which we want to show the types. It's a little tedious and repetitive in some simple cases, but overall it results in nicer API docs. --- doc/en/conf.py | 1 + doc/en/reference/reference.rst | 2 +- src/_pytest/assertion/__init__.py | 2 +- src/_pytest/config/argparsing.py | 54 +++++--- src/_pytest/fixtures.py | 19 ++- src/_pytest/hookspec.py | 208 +++++++++++++++++++++--------- src/_pytest/junitxml.py | 5 +- src/_pytest/logging.py | 25 ++-- src/_pytest/mark/__init__.py | 4 +- src/_pytest/monkeypatch.py | 5 +- src/_pytest/nodes.py | 25 ++-- src/_pytest/outcomes.py | 9 +- src/_pytest/pytester.py | 113 ++++++++++------ src/_pytest/python_api.py | 15 ++- src/_pytest/reports.py | 10 +- src/_pytest/tmpdir.py | 6 +- 16 files changed, 335 insertions(+), 168 deletions(-) diff --git a/doc/en/conf.py b/doc/en/conf.py index fe1d54416..b0c158e5a 100644 --- a/doc/en/conf.py +++ b/doc/en/conf.py @@ -38,6 +38,7 @@ release = ".".join(version.split(".")[:2]) autodoc_member_order = "bysource" autodoc_typehints = "description" +autodoc_typehints_description_target = "documented" todo_include_todos = 1 latex_engine = "lualatex" diff --git a/doc/en/reference/reference.rst b/doc/en/reference/reference.rst index de11cba55..97afdef37 100644 --- a/doc/en/reference/reference.rst +++ b/doc/en/reference/reference.rst @@ -102,7 +102,7 @@ pytest.deprecated_call **Tutorial**: :ref:`ensuring_function_triggers` -.. autofunction:: pytest.deprecated_call() +.. autofunction:: pytest.deprecated_call([match]) :with: pytest.register_assert_rewrite diff --git a/src/_pytest/assertion/__init__.py b/src/_pytest/assertion/__init__.py index 5c971bb86..a46e58136 100644 --- a/src/_pytest/assertion/__init__.py +++ b/src/_pytest/assertion/__init__.py @@ -53,7 +53,7 @@ def register_assert_rewrite(*names: str) -> None: actually imported, usually in your __init__.py if you are a plugin using a package. - :raises TypeError: If the given module names are not strings. + :param names: The module names to register. """ for name in names: if not isinstance(name, str): diff --git a/src/_pytest/config/argparsing.py b/src/_pytest/config/argparsing.py index feae1ce7e..d3f01916b 100644 --- a/src/_pytest/config/argparsing.py +++ b/src/_pytest/config/argparsing.py @@ -66,14 +66,15 @@ class Parser: ) -> "OptionGroup": """Get (or create) a named option Group. - :name: Name of the option group. - :description: Long description for --help output. - :after: Name of another group, used for ordering --help output. + :param name: Name of the option group. + :param description: Long description for --help output. + :param after: Name of another group, used for ordering --help output. + :returns: The option group. The returned group object has an ``addoption`` method with the same signature as :func:`parser.addoption ` but will be shown in the respective group in the output of - ``pytest. --help``. + ``pytest --help``. """ for group in self._groups: if group.name == name: @@ -89,10 +90,11 @@ class Parser: def addoption(self, *opts: str, **attrs: Any) -> None: """Register a command line option. - :opts: Option names, can be short or long options. - :attrs: Same attributes which the ``add_argument()`` function of the - `argparse library `_ - accepts. + :param opts: + Option names, can be short or long options. + :param attrs: + Same attributes as the argparse library's :py:func:`add_argument() + ` function accepts. After command line parsing, options are available on the pytest config object via ``config.option.NAME`` where ``NAME`` is usually set @@ -148,7 +150,10 @@ class Parser: args: Sequence[Union[str, "os.PathLike[str]"]], namespace: Optional[argparse.Namespace] = None, ) -> argparse.Namespace: - """Parse and return a namespace object with known arguments at this point.""" + """Parse the known arguments at this point. + + :returns: An argparse namespace object. + """ return self.parse_known_and_unknown_args(args, namespace=namespace)[0] def parse_known_and_unknown_args( @@ -156,8 +161,13 @@ class Parser: args: Sequence[Union[str, "os.PathLike[str]"]], namespace: Optional[argparse.Namespace] = None, ) -> Tuple[argparse.Namespace, List[str]]: - """Parse and return a namespace object with known arguments, and - the remaining arguments unknown at this point.""" + """Parse the known arguments at this point, and also return the + remaining unknown arguments. + + :returns: + A tuple containing an argparse namespace object for the known + arguments, and a list of the unknown arguments. + """ optparser = self._getparser() strargs = [os.fspath(x) for x in args] return optparser.parse_known_args(strargs, namespace=namespace) @@ -173,9 +183,9 @@ class Parser: ) -> None: """Register an ini-file option. - :name: + :param name: Name of the ini-variable. - :type: + :param type: Type of the variable. Can be: * ``string``: a string @@ -189,7 +199,7 @@ class Parser: The ``paths`` variable type. Defaults to ``string`` if ``None`` or not passed. - :default: + :param default: Default value if no ini-file option exists but is queried. The value of ini-variables can be retrieved via a call to @@ -354,24 +364,30 @@ class OptionGroup: self.options: List[Argument] = [] self.parser = parser - def addoption(self, *optnames: str, **attrs: Any) -> None: + def addoption(self, *opts: str, **attrs: Any) -> None: """Add an option to this group. If a shortened version of a long option is specified, it will be suppressed in the help. ``addoption('--twowords', '--two-words')`` results in help showing ``--two-words`` only, but ``--twowords`` gets accepted **and** the automatic destination is in ``args.twowords``. + + :param opts: + Option names, can be short or long options. + :param attrs: + Same attributes as the argparse library's :py:func:`add_argument() + ` function accepts. """ - conflict = set(optnames).intersection( + conflict = set(opts).intersection( name for opt in self.options for name in opt.names() ) if conflict: raise ValueError("option names %s already added" % conflict) - option = Argument(*optnames, **attrs) + option = Argument(*opts, **attrs) self._addoption_instance(option, shortupper=False) - def _addoption(self, *optnames: str, **attrs: Any) -> None: - option = Argument(*optnames, **attrs) + def _addoption(self, *opts: str, **attrs: Any) -> None: + option = Argument(*opts, **attrs) self._addoption_instance(option, shortupper=True) def _addoption_instance(self, option: "Argument", shortupper: bool = False) -> None: diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index d1d36d7fa..30b6054d0 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -513,8 +513,8 @@ class FixtureRequest: return self._pyfuncitem.session # type: ignore[no-any-return] def addfinalizer(self, finalizer: Callable[[], object]) -> None: - """Add finalizer/teardown function to be called after the last test - within the requesting test context finished execution.""" + """Add finalizer/teardown function to be called without arguments after + the last test within the requesting test context finished execution.""" # XXX usually this method is shadowed by fixturedef specific ones. self._addfinalizer(finalizer, scope=self.scope) @@ -529,13 +529,16 @@ class FixtureRequest: on all function invocations. :param marker: - A :class:`pytest.MarkDecorator` object created by a call - to ``pytest.mark.NAME(...)``. + An object created by a call to ``pytest.mark.NAME(...)``. """ self.node.add_marker(marker) def raiseerror(self, msg: Optional[str]) -> NoReturn: - """Raise a FixtureLookupError with the given message.""" + """Raise a FixtureLookupError exception. + + :param msg: + An optional custom error message. + """ raise self._fixturemanager.FixtureLookupError(None, self, msg) def _fillfixtures(self) -> None: @@ -557,6 +560,8 @@ class FixtureRequest: phase, but during the test teardown phase a fixture's value may not be available. + :param argname: + The fixture name. :raises pytest.FixtureLookupError: If the given fixture could not be found. """ @@ -768,8 +773,8 @@ class SubRequest(FixtureRequest): return f"" def addfinalizer(self, finalizer: Callable[[], object]) -> None: - """Add finalizer/teardown function to be called after the last test - within the requesting test context finished execution.""" + """Add finalizer/teardown function to be called without arguments after + the last test within the requesting test context finished execution.""" self._fixturedef.addfinalizer(finalizer) def _schedule_finalizers( diff --git a/src/_pytest/hookspec.py b/src/_pytest/hookspec.py index a03c0e9ab..cc0828dd1 100644 --- a/src/_pytest/hookspec.py +++ b/src/_pytest/hookspec.py @@ -143,7 +143,7 @@ def pytest_configure(config: "Config") -> None: def pytest_cmdline_parse( pluginmanager: "PytestPluginManager", args: List[str] ) -> Optional["Config"]: - """Return an initialized config object, parsing the specified args. + """Return an initialized :class:`~pytest.Config`, parsing the specified args. Stops at first non-None result, see :ref:`firstresult`. @@ -152,8 +152,9 @@ def pytest_cmdline_parse( ``plugins`` arg when using `pytest.main`_ to perform an in-process test run. - :param pytest.PytestPluginManager pluginmanager: The pytest plugin manager. - :param List[str] args: List of arguments passed on the command line. + :param pluginmanager: The pytest plugin manager. + :param args: List of arguments passed on the command line. + :returns: A pytest config object. """ @@ -167,8 +168,8 @@ def pytest_cmdline_preparse(config: "Config", args: List[str]) -> None: .. note:: This hook will not be called for ``conftest.py`` files, only for setuptools plugins. - :param pytest.Config config: The pytest config object. - :param List[str] args: Arguments passed on the command line. + :param config: The pytest config object. + :param args: Arguments passed on the command line. """ @@ -179,7 +180,8 @@ def pytest_cmdline_main(config: "Config") -> Optional[Union["ExitCode", int]]: Stops at first non-None result, see :ref:`firstresult`. - :param pytest.Config config: The pytest config object. + :param config: The pytest config object. + :returns: The exit code. """ @@ -192,9 +194,9 @@ def pytest_load_initial_conftests( .. note:: This hook will not be called for ``conftest.py`` files, only for setuptools plugins. - :param pytest.Config early_config: The pytest config object. - :param List[str] args: Arguments passed on the command line. - :param pytest.Parser parser: To add command line options. + :param early_config: The pytest config object. + :param args: Arguments passed on the command line. + :param parser: To add command line options. """ @@ -236,7 +238,7 @@ def pytest_collection(session: "Session") -> Optional[object]: for example the terminal plugin uses it to start displaying the collection counter (and returns `None`). - :param pytest.Session session: The pytest session object. + :param session: The pytest session object. """ @@ -246,16 +248,16 @@ def pytest_collection_modifyitems( """Called after collection has been performed. May filter or re-order the items in-place. - :param pytest.Session session: The pytest session object. - :param pytest.Config config: The pytest config object. - :param List[pytest.Item] items: List of item objects. + :param session: The pytest session object. + :param config: The pytest config object. + :param items: List of item objects. """ def pytest_collection_finish(session: "Session") -> None: """Called after collection has been performed and modified. - :param pytest.Session session: The pytest session object. + :param session: The pytest session object. """ @@ -270,9 +272,9 @@ def pytest_ignore_collect( Stops at first non-None result, see :ref:`firstresult`. - :param pathlib.Path collection_path : The path to analyze. - :param LEGACY_PATH path: The path to analyze (deprecated). - :param pytest.Config config: The pytest config object. + :param collection_path: The path to analyze. + :param path: The path to analyze (deprecated). + :param config: The pytest config object. .. versionchanged:: 7.0.0 The ``collection_path`` parameter was added as a :class:`pathlib.Path` @@ -284,12 +286,12 @@ def pytest_ignore_collect( def pytest_collect_file( file_path: Path, path: "LEGACY_PATH", parent: "Collector" ) -> "Optional[Collector]": - """Create a Collector for the given path, or None if not relevant. + """Create a :class:`~pytest.Collector` for the given path, or None if not relevant. The new node needs to have the specified ``parent`` as a parent. - :param pathlib.Path file_path: The path to analyze. - :param LEGACY_PATH path: The path to collect (deprecated). + :param file_path: The path to analyze. + :param path: The path to collect (deprecated). .. versionchanged:: 7.0.0 The ``file_path`` parameter was added as a :class:`pathlib.Path` @@ -302,21 +304,36 @@ def pytest_collect_file( def pytest_collectstart(collector: "Collector") -> None: - """Collector starts collecting.""" + """Collector starts collecting. + + :param collector: + The collector. + """ def pytest_itemcollected(item: "Item") -> None: - """We just collected a test item.""" + """We just collected a test item. + + :param item: + The item. + """ def pytest_collectreport(report: "CollectReport") -> None: - """Collector finished collecting.""" + """Collector finished collecting. + + :param report: + The collect report. + """ def pytest_deselected(items: Sequence["Item"]) -> None: """Called for deselected test items, e.g. by keyword. May be called multiple times. + + :param items: + The items. """ @@ -326,6 +343,9 @@ def pytest_make_collect_report(collector: "Collector") -> "Optional[CollectRepor a :class:`~pytest.CollectReport`. Stops at first non-None result, see :ref:`firstresult`. + + :param collector: + The collector. """ @@ -338,16 +358,16 @@ def pytest_make_collect_report(collector: "Collector") -> "Optional[CollectRepor def pytest_pycollect_makemodule( module_path: Path, path: "LEGACY_PATH", parent ) -> Optional["Module"]: - """Return a Module collector or None for the given path. + """Return a :class:`pytest.Module` collector or None for the given path. This hook will be called for each matching test module path. - The pytest_collect_file hook needs to be used if you want to + The :hook:`pytest_collect_file` hook needs to be used if you want to create test modules for files that do not match as a test module. Stops at first non-None result, see :ref:`firstresult`. - :param pathlib.Path module_path: The path of the module to collect. - :param LEGACY_PATH path: The path of the module to collect (deprecated). + :param module_path: The path of the module to collect. + :param path: The path of the module to collect (deprecated). .. versionchanged:: 7.0.0 The ``module_path`` parameter was added as a :class:`pathlib.Path` @@ -364,6 +384,15 @@ def pytest_pycollect_makeitem( """Return a custom item/collector for a Python object in a module, or None. Stops at first non-None result, see :ref:`firstresult`. + + :param collector: + The module/class collector. + :param name: + The name of the object in the module/class. + :param obj: + The object. + :returns: + The created items/collectors. """ @@ -372,11 +401,18 @@ def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]: """Call underlying test function. Stops at first non-None result, see :ref:`firstresult`. + + :param pyfuncitem: + The function item. """ def pytest_generate_tests(metafunc: "Metafunc") -> None: - """Generate (multiple) parametrized calls to a test function.""" + """Generate (multiple) parametrized calls to a test function. + + :param metafunc: + The :class:`~pytest.Metafunc` helper for the test function. + """ @hookspec(firstresult=True) @@ -391,7 +427,7 @@ def pytest_make_parametrize_id( Stops at first non-None result, see :ref:`firstresult`. - :param pytest.Config config: The pytest config object. + :param config: The pytest config object. :param val: The parametrized value. :param str argname: The automatic parameter name produced by pytest. """ @@ -416,7 +452,7 @@ def pytest_runtestloop(session: "Session") -> Optional[object]: If at any point ``session.shouldfail`` or ``session.shouldstop`` are set, the loop is terminated after the runtest protocol for the current item is finished. - :param pytest.Session session: The pytest session object. + :param session: The pytest session object. Stops at first non-None result, see :ref:`firstresult`. The return value is not used, but only stops further processing. @@ -468,7 +504,7 @@ def pytest_runtest_logstart( See :hook:`pytest_runtest_protocol` for a description of the runtest protocol. - :param str nodeid: Full node ID of the item. + :param nodeid: Full node ID of the item. :param location: A tuple of ``(filename, lineno, testname)``. """ @@ -480,7 +516,7 @@ def pytest_runtest_logfinish( See :hook:`pytest_runtest_protocol` for a description of the runtest protocol. - :param str nodeid: Full node ID of the item. + :param nodeid: Full node ID of the item. :param location: A tuple of ``(filename, lineno, testname)``. """ @@ -492,6 +528,9 @@ def pytest_runtest_setup(item: "Item") -> None: parents (which haven't been setup yet). This includes obtaining the values of fixtures required by the item (which haven't been obtained yet). + + :param item: + The item. """ @@ -499,6 +538,9 @@ def pytest_runtest_call(item: "Item") -> None: """Called to run the test for test item (the call phase). The default implementation calls ``item.runtest()``. + + :param item: + The item. """ @@ -510,6 +552,8 @@ def pytest_runtest_teardown(item: "Item", nextitem: Optional["Item"]) -> None: includes running the teardown phase of fixtures required by the item (if they go out of scope). + :param item: + The item. :param nextitem: The scheduled-to-be-next test item (None if no further test item is scheduled). This argument is used to perform exact teardowns, i.e. @@ -527,6 +571,7 @@ def pytest_runtest_makereport( See :hook:`pytest_runtest_protocol` for a description of the runtest protocol. + :param item: The item. :param call: The :class:`~pytest.CallInfo` for the phase. Stops at first non-None result, see :ref:`firstresult`. @@ -547,7 +592,11 @@ def pytest_report_to_serializable( report: Union["CollectReport", "TestReport"], ) -> Optional[Dict[str, Any]]: """Serialize the given report object into a data structure suitable for - sending over the wire, e.g. converted to JSON.""" + sending over the wire, e.g. converted to JSON. + + :param config: The pytest config object. + :param report: The report. + """ @hookspec(firstresult=True) @@ -556,7 +605,10 @@ def pytest_report_from_serializable( data: Dict[str, Any], ) -> Optional[Union["CollectReport", "TestReport"]]: """Restore a report object previously serialized with - :hook:`pytest_report_to_serializable`.""" + :hook:`pytest_report_to_serializable`. + + :param config: The pytest config object. + """ # ------------------------------------------------------------------------- @@ -570,7 +622,12 @@ def pytest_fixture_setup( ) -> Optional[object]: """Perform fixture setup execution. - :returns: The return value of the call to the fixture function. + :param fixturdef: + The fixture definition object. + :param request: + The fixture request object. + :returns: + The return value of the call to the fixture function. Stops at first non-None result, see :ref:`firstresult`. @@ -586,7 +643,13 @@ def pytest_fixture_post_finalizer( ) -> None: """Called after fixture teardown, but before the cache is cleared, so the fixture result ``fixturedef.cached_result`` is still available (not - ``None``).""" + ``None``). + + :param fixturdef: + The fixture definition object. + :param request: + The fixture request object. + """ # ------------------------------------------------------------------------- @@ -598,7 +661,7 @@ def pytest_sessionstart(session: "Session") -> None: """Called after the ``Session`` object has been created and before performing collection and entering the run test loop. - :param pytest.Session session: The pytest session object. + :param session: The pytest session object. """ @@ -608,15 +671,15 @@ def pytest_sessionfinish( ) -> None: """Called after whole test run finished, right before returning the exit status to the system. - :param pytest.Session session: The pytest session object. - :param int exitstatus: The status which pytest will return to the system. + :param session: The pytest session object. + :param exitstatus: The status which pytest will return to the system. """ def pytest_unconfigure(config: "Config") -> None: """Called before test process is exited. - :param pytest.Config config: The pytest config object. + :param config: The pytest config object. """ @@ -635,7 +698,10 @@ def pytest_assertrepr_compare( *in* a string will be escaped. Note that all but the first line will be indented slightly, the intention is for the first line to be a summary. - :param pytest.Config config: The pytest config object. + :param config: The pytest config object. + :param op: The operator, e.g. `"=="`, `"!="`, `"not in"`. + :param left: The left operand. + :param right: The right operand. """ @@ -660,10 +726,10 @@ def pytest_assertion_pass(item: "Item", lineno: int, orig: str, expl: str) -> No You need to **clean the .pyc** files in your project directory and interpreter libraries when enabling this option, as assertions will require to be re-written. - :param pytest.Item item: pytest item object of current test. - :param int lineno: Line number of the assert statement. - :param str orig: String with the original assertion. - :param str expl: String with the assert explanation. + :param item: pytest item object of current test. + :param lineno: Line number of the assert statement. + :param orig: String with the original assertion. + :param expl: String with the assert explanation. """ @@ -677,9 +743,9 @@ def pytest_report_header( ) -> Union[str, List[str]]: """Return a string or list of strings to be displayed as header info for terminal reporting. - :param pytest.Config config: The pytest config object. - :param Path start_path: The starting dir. - :param LEGACY_PATH startdir: The starting dir (deprecated). + :param config: The pytest config object. + :param start_path: The starting dir. + :param startdir: The starting dir (deprecated). .. note:: @@ -714,9 +780,9 @@ def pytest_report_collectionfinish( .. versionadded:: 3.2 - :param pytest.Config config: The pytest config object. - :param Path start_path: The starting dir. - :param LEGACY_PATH startdir: The starting dir (deprecated). + :param config: The pytest config object. + :param start_path: The starting dir. + :param startdir: The starting dir (deprecated). :param items: List of pytest items that are going to be executed; this list should not be modified. .. note:: @@ -755,6 +821,7 @@ def pytest_report_teststatus( :param report: The report object whose status is to be returned. :param config: The pytest config object. + :returns: The test status. Stops at first non-None result, see :ref:`firstresult`. """ @@ -767,9 +834,9 @@ def pytest_terminal_summary( ) -> None: """Add a section to terminal summary reporting. - :param _pytest.terminal.TerminalReporter terminalreporter: The internal terminal reporter object. - :param int exitstatus: The exit status that will be reported back to the OS. - :param pytest.Config config: The pytest config object. + :param terminalreporter: The internal terminal reporter object. + :param exitstatus: The exit status that will be reported back to the OS. + :param config: The pytest config object. .. versionadded:: 4.2 The ``config`` parameter. @@ -785,21 +852,21 @@ def pytest_warning_recorded( ) -> None: """Process a warning captured by the internal pytest warnings plugin. - :param warnings.WarningMessage warning_message: + :param warning_message: The captured warning. This is the same object produced by :py:func:`warnings.catch_warnings`, and contains the same attributes as the parameters of :py:func:`warnings.showwarning`. - :param str when: + :param when: Indicates when the warning was captured. Possible values: * ``"config"``: during pytest configuration/initialization stage. * ``"collect"``: during test collection. * ``"runtest"``: during test execution. - :param str nodeid: + :param nodeid: Full id of the item. - :param tuple|None location: + :param location: When available, holds information about the execution context of the captured warning (filename, linenumber, function). ``function`` evaluates to when the execution context is at the module level. @@ -824,7 +891,7 @@ def pytest_markeval_namespace(config: "Config") -> Dict[str, Any]: .. versionadded:: 6.2 - :param pytest.Config config: The pytest config object. + :param config: The pytest config object. :returns: A dictionary of additional globals to add. """ @@ -842,13 +909,19 @@ def pytest_internalerror( Return True to suppress the fallback handling of printing an INTERNALERROR message directly to sys.stderr. + + :param excrepr: The exception repr object. + :param excinfo: The exception info. """ def pytest_keyboard_interrupt( excinfo: "ExceptionInfo[Union[KeyboardInterrupt, Exit]]", ) -> None: - """Called for keyboard interrupt.""" + """Called for keyboard interrupt. + + :param excinfo: The exception info. + """ def pytest_exception_interact( @@ -867,6 +940,13 @@ def pytest_exception_interact( This hook is not called if the exception that was raised is an internal exception like ``skip.Exception``. + + :param node: + The item or collector. + :param call: + The call information. Contains the exception. + :param report: + The collection or test report. """ @@ -876,8 +956,8 @@ def pytest_enter_pdb(config: "Config", pdb: "pdb.Pdb") -> None: Can be used by plugins to take special action just before the python debugger enters interactive mode. - :param pytest.Config config: The pytest config object. - :param pdb.Pdb pdb: The Pdb instance. + :param config: The pytest config object. + :param pdb: The Pdb instance. """ @@ -887,6 +967,6 @@ def pytest_leave_pdb(config: "Config", pdb: "pdb.Pdb") -> None: Can be used by plugins to take special action just after the python debugger leaves interactive mode. - :param pytest.Config config: The pytest config object. - :param pdb.Pdb pdb: The Pdb instance. + :param config: The pytest config object. + :param pdb: The Pdb instance. """ diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index 66057ef6f..7a5170f32 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -354,7 +354,10 @@ def record_testsuite_property(request: FixtureRequest) -> Callable[[str, object] record_testsuite_property("ARCH", "PPC") record_testsuite_property("STORAGE_TYPE", "CEPH") - ``name`` must be a string, ``value`` will be converted to a string and properly xml-escaped. + :param name: + The property name. + :param value: + The property value. Will be converted to a string. .. warning:: diff --git a/src/_pytest/logging.py b/src/_pytest/logging.py index 2eb69fdbf..f9091399f 100644 --- a/src/_pytest/logging.py +++ b/src/_pytest/logging.py @@ -37,6 +37,8 @@ from _pytest.terminal import TerminalReporter if TYPE_CHECKING: logging_StreamHandler = logging.StreamHandler[StringIO] + + from typing_extensions import Literal else: logging_StreamHandler = logging.StreamHandler @@ -382,20 +384,19 @@ class LogCaptureFixture: @property def handler(self) -> LogCaptureHandler: - """Get the logging handler used by the fixture. - - :rtype: LogCaptureHandler - """ + """Get the logging handler used by the fixture.""" return self._item.stash[caplog_handler_key] - def get_records(self, when: str) -> List[logging.LogRecord]: + def get_records( + self, when: "Literal['setup', 'call', 'teardown']" + ) -> List[logging.LogRecord]: """Get the logging records for one of the possible test phases. - :param str when: - Which test phase to obtain the records from. Valid values are: "setup", "call" and "teardown". + :param when: + Which test phase to obtain the records from. + Valid values are: "setup", "call" and "teardown". :returns: The list of captured records at the given stage. - :rtype: List[logging.LogRecord] .. versionadded:: 3.4 """ @@ -452,8 +453,8 @@ class LogCaptureFixture: The levels of the loggers changed by this function will be restored to their initial values at the end of the test. - :param int level: The level. - :param str logger: The logger to update. If not given, the root logger. + :param level: The level. + :param logger: The logger to update. If not given, the root logger. """ logger_obj = logging.getLogger(logger) # Save the original log-level to restore it during teardown. @@ -471,8 +472,8 @@ class LogCaptureFixture: the end of the 'with' statement the level is restored to its original value. - :param int level: The level. - :param str logger: The logger to update. If not given, the root logger. + :param level: The level. + :param logger: The logger to update. If not given, the root logger. """ logger_obj = logging.getLogger(logger) orig_level = logger_obj.level diff --git a/src/_pytest/mark/__init__.py b/src/_pytest/mark/__init__.py index a03f0f89c..6717d1135 100644 --- a/src/_pytest/mark/__init__.py +++ b/src/_pytest/mark/__init__.py @@ -62,8 +62,8 @@ def param( assert eval(test_input) == expected :param values: Variable args of the values of the parameter set, in order. - :keyword marks: A single mark or a list of marks to be applied to this parameter set. - :keyword str id: The id to attribute to this parameter set. + :param marks: A single mark or a list of marks to be applied to this parameter set. + :param id: The id to attribute to this parameter set. """ return ParameterSet.param(*values, marks=marks, id=id) diff --git a/src/_pytest/monkeypatch.py b/src/_pytest/monkeypatch.py index 91d590fb3..fdb252c5c 100644 --- a/src/_pytest/monkeypatch.py +++ b/src/_pytest/monkeypatch.py @@ -115,7 +115,7 @@ class MonkeyPatch: Returned by the :fixture:`monkeypatch` fixture. - :versionchanged:: 6.2 + .. versionchanged:: 6.2 Can now also be used directly as `pytest.MonkeyPatch()`, for when the fixture is not available. In this case, use :meth:`with MonkeyPatch.context() as mp: ` or remember to call @@ -338,7 +338,8 @@ class MonkeyPatch: def chdir(self, path: Union[str, "os.PathLike[str]"]) -> None: """Change the current working directory to the specified path. - Path can be a string or a path object. + :param path: + The path to change into. """ if self._cwd is None: self._cwd = os.getcwd() diff --git a/src/_pytest/nodes.py b/src/_pytest/nodes.py index 1a168043a..cfb9b5a36 100644 --- a/src/_pytest/nodes.py +++ b/src/_pytest/nodes.py @@ -193,7 +193,7 @@ class Node(metaclass=NodeMeta): nodeid: Optional[str] = None, ) -> None: #: A unique name within the scope of the parent node. - self.name = name + self.name: str = name #: The parent collector node. self.parent = parent @@ -208,7 +208,7 @@ class Node(metaclass=NodeMeta): if session: #: The pytest session this node is part of. - self.session = session + self.session: Session = session else: if not parent: raise TypeError("session or parent must be provided") @@ -239,9 +239,7 @@ class Node(metaclass=NodeMeta): #: A place where plugins can store information on the node for their #: own use. - #: - #: :type: Stash - self.stash = Stash() + self.stash: Stash = Stash() # Deprecated alias. Was never public. Can be removed in a few releases. self._store = self.stash @@ -326,7 +324,10 @@ class Node(metaclass=NodeMeta): def listchain(self) -> List["Node"]: """Return list of all parent collectors up to self, starting from - the root of collection tree.""" + the root of collection tree. + + :returns: The nodes. + """ chain = [] item: Optional[Node] = self while item is not None: @@ -340,6 +341,8 @@ class Node(metaclass=NodeMeta): ) -> None: """Dynamically add a marker object to the node. + :param marker: + The marker. :param append: Whether to append the marker, or prepend it. """ @@ -361,6 +364,7 @@ class Node(metaclass=NodeMeta): """Iterate over all markers of the node. :param name: If given, filter the results by the name attribute. + :returns: An iterator of the markers of the node. """ return (x[1] for x in self.iter_markers_with_node(name=name)) @@ -407,7 +411,8 @@ class Node(metaclass=NodeMeta): return [x.name for x in self.listchain()] def addfinalizer(self, fin: Callable[[], object]) -> None: - """Register a function to be called when this node is finalized. + """Register a function to be called without arguments when this node is + finalized. This method can only be called when this node is active in a setup chain, for example during self.setup(). @@ -416,7 +421,11 @@ class Node(metaclass=NodeMeta): def getparent(self, cls: Type[_NodeType]) -> Optional[_NodeType]: """Get the next parent node (including self) which is an instance of - the given class.""" + the given class. + + :param cls: The node class to search for. + :returns: The node, if found. + """ current: Optional[Node] = self while current and not isinstance(current, cls): current = current.parent diff --git a/src/_pytest/outcomes.py b/src/_pytest/outcomes.py index 684efae77..e46b663dd 100644 --- a/src/_pytest/outcomes.py +++ b/src/_pytest/outcomes.py @@ -241,6 +241,9 @@ def xfail(reason: str = "") -> NoReturn: This function should be called only during testing (setup, call or teardown). + :param reason: + The message to show the user as reason for the xfail. + .. note:: It is better to use the :ref:`pytest.mark.xfail ref` marker when possible to declare a test to be xfailed under certain conditions @@ -256,12 +259,12 @@ def importorskip( """Import and return the requested module ``modname``, or skip the current test if the module cannot be imported. - :param str modname: + :param modname: The name of the module to import. - :param str minversion: + :param minversion: If given, the imported module's ``__version__`` attribute must be at least this minimal version, otherwise the test is still skipped. - :param str reason: + :param reason: If given, this reason is shown as the message when the module cannot be imported. diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index d8586a056..a9299944d 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -661,17 +661,7 @@ class Pytester: against expected output, perfect for black-box testing of pytest plugins. It attempts to isolate the test run from external factors as much as possible, modifying - the current working directory to ``path`` and environment variables during initialization. - - Attributes: - - :ivar Path path: temporary directory path used to create files/run tests from, etc. - - :ivar plugins: - A list of plugins to use with :py:meth:`parseconfig` and - :py:meth:`runpytest`. Initially this is an empty list but plugins can - be added to the list. The type of items to add to the list depends on - the method using them so refer to them for details. + the current working directory to :attr:`path` and environment variables during initialization. """ __test__ = False @@ -700,6 +690,10 @@ class Pytester: name = request.node.name self._name = name self._path: Path = tmp_path_factory.mktemp(name, numbered=True) + #: A list of plugins to use with :py:meth:`parseconfig` and + #: :py:meth:`runpytest`. Initially this is an empty list but plugins can + #: be added to the list. The type of items to add to the list depends on + #: the method using them so refer to them for details. self.plugins: List[Union[str, _PluggyPlugin]] = [] self._cwd_snapshot = CwdSnapshot() self._sys_path_snapshot = SysPathsSnapshot() @@ -724,7 +718,7 @@ class Pytester: @property def path(self) -> Path: - """Temporary directory where files are created and pytest is executed.""" + """Temporary directory path used to create files/run tests from, etc.""" return self._path def __repr__(self) -> str: @@ -755,7 +749,7 @@ class Pytester: return SysModulesSnapshot(preserve=preserve_module) def make_hook_recorder(self, pluginmanager: PytestPluginManager) -> HookRecorder: - """Create a new :py:class:`HookRecorder` for a PluginManager.""" + """Create a new :class:`HookRecorder` for a :class:`PytestPluginManager`.""" pluginmanager.reprec = reprec = HookRecorder(pluginmanager, _ispytest=True) self._request.addfinalizer(reprec.finish_recording) return reprec @@ -804,7 +798,7 @@ class Pytester: def makefile(self, ext: str, *args: str, **kwargs: str) -> Path: r"""Create new text file(s) in the test directory. - :param str ext: + :param ext: The extension the file(s) should use, including the dot, e.g. `.py`. :param args: All args are treated as strings and joined using newlines. @@ -813,6 +807,8 @@ class Pytester: :param kwargs: Each keyword is the name of a file, while the value of it will be written as contents of the file. + :returns: + The first created file. Examples: @@ -832,11 +828,19 @@ class Pytester: return self._makefile(ext, args, kwargs) def makeconftest(self, source: str) -> Path: - """Write a conftest.py file with 'source' as contents.""" + """Write a contest.py file. + + :param source: The contents. + :returns: The conftest.py file. + """ return self.makepyfile(conftest=source) def makeini(self, source: str) -> Path: - """Write a tox.ini file with 'source' as contents.""" + """Write a tox.ini file. + + :param source: The contents. + :returns: The tox.ini file. + """ return self.makefile(".ini", tox=source) def getinicfg(self, source: str) -> SectionWrapper: @@ -845,7 +849,10 @@ class Pytester: return IniConfig(str(p))["pytest"] def makepyprojecttoml(self, source: str) -> Path: - """Write a pyproject.toml file with 'source' as contents. + """Write a pyproject.toml file. + + :param source: The contents. + :returns: The pyproject.ini file. .. versionadded:: 6.0 """ @@ -898,6 +905,9 @@ class Pytester: This is undone automatically when this object dies at the end of each test. + + :param path: + The path. """ if path is None: path = self.path @@ -905,7 +915,13 @@ class Pytester: self._monkeypatch.syspath_prepend(str(path)) def mkdir(self, name: Union[str, "os.PathLike[str]"]) -> Path: - """Create a new (sub)directory.""" + """Create a new (sub)directory. + + :param name: + The name of the directory, relative to the pytester path. + :returns: + The created directory. + """ p = self.path / name p.mkdir() return p @@ -924,14 +940,15 @@ class Pytester: def copy_example(self, name: Optional[str] = None) -> Path: """Copy file from project's directory into the testdir. - :param str name: The name of the file to copy. - :return: path to the copied directory (inside ``self.path``). - + :param name: + The name of the file to copy. + :return: + Path to the copied directory (inside ``self.path``). """ - example_dir = self._request.config.getini("pytester_example_dir") - if example_dir is None: + example_dir_ = self._request.config.getini("pytester_example_dir") + if example_dir_ is None: raise ValueError("pytester_example_dir is unset, can't copy examples") - example_dir = self._request.config.rootpath / example_dir + example_dir: Path = self._request.config.rootpath / example_dir_ for extra_element in self._request.node.iter_markers("pytester_example_path"): assert extra_element.args @@ -967,14 +984,16 @@ class Pytester: def getnode( self, config: Config, arg: Union[str, "os.PathLike[str]"] - ) -> Optional[Union[Collector, Item]]: - """Return the collection node of a file. + ) -> Union[Collector, Item]: + """Get the collection node of a file. - :param pytest.Config config: + :param config: A pytest config. See :py:meth:`parseconfig` and :py:meth:`parseconfigure` for creating it. - :param os.PathLike[str] arg: + :param arg: Path to the file. + :returns: + The node. """ session = Session.from_config(config) assert "::" not in str(arg) @@ -984,13 +1003,18 @@ class Pytester: config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK) return res - def getpathnode(self, path: Union[str, "os.PathLike[str]"]): + def getpathnode( + self, path: Union[str, "os.PathLike[str]"] + ) -> Union[Collector, Item]: """Return the collection node of a file. This is like :py:meth:`getnode` but uses :py:meth:`parseconfigure` to create the (configured) pytest Config instance. - :param os.PathLike[str] path: Path to the file. + :param path: + Path to the file. + :returns: + The node. """ path = Path(path) config = self.parseconfigure(path) @@ -1006,6 +1030,11 @@ class Pytester: This recurses into the collection node and returns a list of all the test items contained within. + + :param colitems: + The collection nodes. + :returns: + The collected items. """ session = colitems[0].session result: List[Item] = [] @@ -1192,15 +1221,16 @@ class Pytester: return new_args def parseconfig(self, *args: Union[str, "os.PathLike[str]"]) -> Config: - """Return a new pytest Config instance from given commandline args. + """Return a new pytest :class:`pytest.Config` instance from given + commandline args. - This invokes the pytest bootstrapping code in _pytest.config to create - a new :py:class:`_pytest.core.PluginManager` and call the - pytest_cmdline_parse hook to create a new - :py:class:`pytest.Config` instance. + This invokes the pytest bootstrapping code in _pytest.config to create a + new :py:class:`pytest.PytestPluginManager` and call the + :hook:`pytest_cmdline_parse` hook to create a new :class:`pytest.Config` + instance. - If :py:attr:`plugins` has been populated they should be plugin modules - to be registered with the PluginManager. + If :attr:`plugins` has been populated they should be plugin modules + to be registered with the plugin manager. """ import _pytest.config @@ -1218,7 +1248,8 @@ class Pytester: """Return a new pytest configured Config instance. Returns a new :py:class:`pytest.Config` instance like - :py:meth:`parseconfig`, but also calls the pytest_configure hook. + :py:meth:`parseconfig`, but also calls the :hook:`pytest_configure` + hook. """ config = self.parseconfig(*args) config._do_configure() @@ -1237,6 +1268,8 @@ class Pytester: The module source. :param funcname: The name of the test function for which to return a test item. + :returns: + The test item. """ items = self.getitems(source) for item in items: @@ -1377,6 +1410,8 @@ class Pytester: - Otherwise, it is passed through to :py:class:`subprocess.Popen`. For further information in this case, consult the document of the ``stdin`` parameter in :py:class:`subprocess.Popen`. + :returns: + The result. """ __tracebackhide__ = True @@ -1463,6 +1498,8 @@ class Pytester: :param timeout: The period in seconds after which to timeout and raise :py:class:`Pytester.TimeoutExpired`. + :returns: + The result. """ __tracebackhide__ = True p = make_numbered_dir(root=self.path, prefix="runpytest-", mode=0o700) diff --git a/src/_pytest/python_api.py b/src/_pytest/python_api.py index d825931de..00e377f40 100644 --- a/src/_pytest/python_api.py +++ b/src/_pytest/python_api.py @@ -798,15 +798,18 @@ def raises( def raises( expected_exception: Union[Type[E], Tuple[Type[E], ...]], *args: Any, **kwargs: Any ) -> Union["RaisesContext[E]", _pytest._code.ExceptionInfo[E]]: - r"""Assert that a code block/function call raises ``expected_exception`` - or raise a failure exception otherwise. + r"""Assert that a code block/function call raises an exception. - :kwparam match: + :param typing.Type[E] | typing.Tuple[typing.Type[E], ...] expected_exception: + The excpected exception type, or a tuple if one of multiple possible + exception types are excepted. + :kwparam str | typing.Pattern[str] | None match: If specified, a string containing a regular expression, or a regular expression object, that is tested against the string - representation of the exception using :py:func:`re.search`. To match a literal - string that may contain :std:ref:`special characters `, the pattern can - first be escaped with :py:func:`re.escape`. + representation of the exception using :func:`re.search`. + + To match a literal string that may contain :ref:`special characters + `, the pattern can first be escaped with :func:`re.escape`. (This is only used when :py:func:`pytest.raises` is used as a context manager, and passed through to the function otherwise. diff --git a/src/_pytest/reports.py b/src/_pytest/reports.py index 20862d603..c35f7087e 100644 --- a/src/_pytest/reports.py +++ b/src/_pytest/reports.py @@ -276,7 +276,7 @@ class TestReport(BaseReport): #: A name -> value dictionary containing all keywords and #: markers associated with a test invocation. - self.keywords = keywords + self.keywords: Mapping[str, Any] = keywords #: Test outcome, always one of "passed", "failed", "skipped". self.outcome = outcome @@ -298,7 +298,7 @@ class TestReport(BaseReport): self.sections = list(sections) #: Time it took to run just the test. - self.duration = duration + self.duration: float = duration self.__dict__.update(extra) @@ -309,7 +309,11 @@ class TestReport(BaseReport): @classmethod def from_item_and_call(cls, item: Item, call: "CallInfo[None]") -> "TestReport": - """Create and fill a TestReport with standard item and call info.""" + """Create and fill a TestReport with standard item and call info. + + :param item: The item. + :param call: The call info. + """ when = call.when # Remove "collect" from the Literal type -- only for collection calls. assert when != "collect" diff --git a/src/_pytest/tmpdir.py b/src/_pytest/tmpdir.py index 12dc463a2..9497a0d49 100644 --- a/src/_pytest/tmpdir.py +++ b/src/_pytest/tmpdir.py @@ -100,7 +100,11 @@ class TempPathFactory: return p def getbasetemp(self) -> Path: - """Return the base temporary directory, creating it if needed.""" + """Return the base temporary directory, creating it if needed. + + :returns: + The base temporary directory. + """ if self._basetemp is not None: return self._basetemp