Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More typing work #7418

Merged
merged 8 commits into from
Jun 27, 2020
2 changes: 2 additions & 0 deletions changelog/7418.breaking.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Remove the `pytest_doctest_prepare_content` hook specification. This hook
hasn't been triggered by pytest for at least 10 years.
4 changes: 1 addition & 3 deletions src/_pytest/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -924,9 +924,7 @@ def _teardown_yield_fixture(fixturefunc, it) -> None:
except StopIteration:
pass
else:
fail_fixturefunc(
fixturefunc, "yield_fixture function has more than one 'yield'"
)
fail_fixturefunc(fixturefunc, "fixture function has more than one 'yield'")


def _eval_scope_callable(
Expand Down
19 changes: 14 additions & 5 deletions src/_pytest/freeze_support.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@
Provides a function to report all internal modules for using freezing tools
pytest
"""
import types
from typing import Iterator
from typing import List
from typing import Union


def freeze_includes():
def freeze_includes() -> List[str]:
"""
Returns a list of module names used by pytest that should be
included by cx_freeze.
Expand All @@ -17,7 +21,9 @@ def freeze_includes():
return result


def _iter_all_modules(package, prefix=""):
def _iter_all_modules(
package: Union[str, types.ModuleType], prefix: str = "",
) -> Iterator[str]:
"""
Iterates over the names of all modules that can be found in the given
package, recursively.
Expand All @@ -29,10 +35,13 @@ def _iter_all_modules(package, prefix=""):
import os
import pkgutil

if type(package) is not str:
path, prefix = package.__path__[0], package.__name__ + "."
else:
if isinstance(package, str):
path = package
else:
# Type ignored because typeshed doesn't define ModuleType.__path__
# (only defined on packages).
package_path = package.__path__ # type: ignore[attr-defined]
path, prefix = package_path[0], package.__name__ + "."
for _, name, is_package in pkgutil.iter_modules([path]):
if is_package:
for m in _iter_all_modules(os.path.join(path, name), prefix=name + "."):
Expand Down
104 changes: 51 additions & 53 deletions src/_pytest/hookspec.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
""" hook specifications for pytest plugins, invoked from main.py and builtin plugins. """
from typing import Any
from typing import Dict
from typing import List
from typing import Mapping
from typing import Optional
Expand Down Expand Up @@ -37,7 +38,6 @@
from _pytest.python import Metafunc
from _pytest.python import Module
from _pytest.python import PyCollector
from _pytest.reports import BaseReport
from _pytest.reports import CollectReport
from _pytest.reports import TestReport
from _pytest.runner import CallInfo
Expand Down Expand Up @@ -172,7 +172,7 @@ def pytest_cmdline_preparse(config: "Config", args: List[str]) -> None:


@hookspec(firstresult=True)
def pytest_cmdline_main(config: "Config") -> "Optional[Union[ExitCode, int]]":
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.

Expand Down Expand Up @@ -206,7 +206,7 @@ def pytest_load_initial_conftests(


@hookspec(firstresult=True)
def pytest_collection(session: "Session") -> Optional[Any]:
def pytest_collection(session: "Session") -> Optional[object]:
"""Perform the collection protocol for the given session.

Stops at first non-None result, see :ref:`firstresult`.
Expand Down Expand Up @@ -242,39 +242,41 @@ def pytest_collection_modifyitems(
"""


def pytest_collection_finish(session: "Session"):
""" called after collection has been performed and modified.
def pytest_collection_finish(session: "Session") -> None:
"""Called after collection has been performed and modified.

:param _pytest.main.Session session: the pytest session object
"""


@hookspec(firstresult=True)
def pytest_ignore_collect(path, config: "Config"):
""" return True to prevent considering this path for collection.
def pytest_ignore_collect(path: py.path.local, config: "Config") -> Optional[bool]:
"""Return True to prevent considering this path for collection.

This hook is consulted for all files and directories prior to calling
more specific hooks.

Stops at first non-None result, see :ref:`firstresult`
Stops at first non-None result, see :ref:`firstresult`.

:param path: a :py:class:`py.path.local` - the path to analyze
:param _pytest.config.Config config: pytest config object
"""


@hookspec(firstresult=True, warn_on_impl=COLLECT_DIRECTORY_HOOK)
def pytest_collect_directory(path, parent):
""" called before traversing a directory for collection files.
def pytest_collect_directory(path: py.path.local, parent) -> Optional[object]:
"""Called before traversing a directory for collection files.

Stops at first non-None result, see :ref:`firstresult`
Stops at first non-None result, see :ref:`firstresult`.

:param path: a :py:class:`py.path.local` - the path to analyze
"""


def pytest_collect_file(path: py.path.local, parent) -> "Optional[Collector]":
""" return collection Node or None for the given path. Any new node
needs to have the specified ``parent`` as a parent.
"""Return collection Node or None for the given path.

Any new node needs to have the specified ``parent`` as a parent.

:param path: a :py:class:`py.path.local` - the path to collect
"""
Expand All @@ -287,16 +289,16 @@ def pytest_collectstart(collector: "Collector") -> None:
""" collector starts collecting. """


def pytest_itemcollected(item):
""" we just collected a test item. """
def pytest_itemcollected(item: "Item") -> None:
"""We just collected a test item."""


def pytest_collectreport(report: "CollectReport") -> None:
""" collector finished collecting. """


def pytest_deselected(items):
""" called for test items deselected, e.g. by keyword. """
def pytest_deselected(items: Sequence["Item"]) -> None:
"""Called for deselected test items, e.g. by keyword."""


@hookspec(firstresult=True)
Expand All @@ -312,25 +314,27 @@ def pytest_make_collect_report(collector: "Collector") -> "Optional[CollectRepor


@hookspec(firstresult=True)
def pytest_pycollect_makemodule(path: py.path.local, parent) -> "Optional[Module]":
""" return a Module collector or None for the given path.
def pytest_pycollect_makemodule(path: py.path.local, parent) -> Optional["Module"]:
"""Return a 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
create test modules for files that do not match as a test module.

Stops at first non-None result, see :ref:`firstresult`
Stops at first non-None result, see :ref:`firstresult`.

:param path: a :py:class:`py.path.local` - the path of module to collect
"""


@hookspec(firstresult=True)
def pytest_pycollect_makeitem(
collector: "PyCollector", name: str, obj
) -> "Union[None, Item, Collector, List[Union[Item, Collector]]]":
""" return custom item/collector for a python object in a module, or None.
collector: "PyCollector", name: str, obj: object
) -> Union[None, "Item", "Collector", List[Union["Item", "Collector"]]]:
"""Return a custom item/collector for a Python object in a module, or None.

Stops at first non-None result, see :ref:`firstresult` """
Stops at first non-None result, see :ref:`firstresult`.
"""


@hookspec(firstresult=True)
Expand Down Expand Up @@ -466,7 +470,7 @@ def pytest_runtest_call(item: "Item") -> None:
"""


def pytest_runtest_teardown(item: "Item", nextitem: "Optional[Item]") -> None:
def pytest_runtest_teardown(item: "Item", nextitem: Optional["Item"]) -> None:
"""Called to perform the teardown phase for a test item.

The default implementation runs the finalizers and calls ``teardown()``
Expand Down Expand Up @@ -505,15 +509,19 @@ def pytest_runtest_logreport(report: "TestReport") -> None:


@hookspec(firstresult=True)
def pytest_report_to_serializable(config: "Config", report: "BaseReport"):
def pytest_report_to_serializable(
config: "Config", report: Union["CollectReport", "TestReport"],
) -> Optional[Dict[str, Any]]:
"""
Serializes the given report object into a data structure suitable for sending
over the wire, e.g. converted to JSON.
"""


@hookspec(firstresult=True)
def pytest_report_from_serializable(config: "Config", data):
def pytest_report_from_serializable(
config: "Config", data: Dict[str, Any],
) -> Optional[Union["CollectReport", "TestReport"]]:
"""
Restores a report object previously serialized with pytest_report_to_serializable().
"""
Expand All @@ -528,11 +536,11 @@ def pytest_report_from_serializable(config: "Config", data):
def pytest_fixture_setup(
fixturedef: "FixtureDef", request: "SubRequest"
) -> Optional[object]:
""" performs fixture setup execution.
"""Performs fixture setup execution.

:return: The return value of the call to the fixture function
:return: The return value of the call to the fixture function.

Stops at first non-None result, see :ref:`firstresult`
Stops at first non-None result, see :ref:`firstresult`.

.. note::
If the fixture function returns None, other implementations of
Expand All @@ -555,25 +563,25 @@ def pytest_fixture_post_finalizer(


def pytest_sessionstart(session: "Session") -> None:
""" called after the ``Session`` object has been created and before performing collection
"""Called after the ``Session`` object has been created and before performing collection
and entering the run test loop.

:param _pytest.main.Session session: the pytest session object
"""


def pytest_sessionfinish(
session: "Session", exitstatus: "Union[int, ExitCode]"
session: "Session", exitstatus: Union[int, "ExitCode"],
) -> None:
""" called after whole test run finished, right before returning the exit status to the system.
"""Called after whole test run finished, right before returning the exit status to the system.

:param _pytest.main.Session session: the pytest session object
:param int exitstatus: the status which pytest will return to the system
"""


def pytest_unconfigure(config: "Config") -> None:
""" called before test process is exited.
"""Called before test process is exited.

:param _pytest.config.Config config: pytest config object
"""
Expand All @@ -587,7 +595,7 @@ def pytest_unconfigure(config: "Config") -> None:
def pytest_assertrepr_compare(
config: "Config", op: str, left: object, right: object
) -> Optional[List[str]]:
"""return explanation for comparisons in failing assert expressions.
"""Return explanation for comparisons in failing assert expressions.

Return None for no custom explanation, otherwise return a list
of strings. The strings will be joined by newlines but any newlines
Expand All @@ -598,7 +606,7 @@ def pytest_assertrepr_compare(
"""


def pytest_assertion_pass(item, lineno: int, orig: str, expl: str) -> None:
def pytest_assertion_pass(item: "Item", lineno: int, orig: str, expl: str) -> None:
"""
**(Experimental)**

Expand Down Expand Up @@ -665,12 +673,12 @@ def pytest_report_header(


def pytest_report_collectionfinish(
config: "Config", startdir: py.path.local, items: "Sequence[Item]"
config: "Config", startdir: py.path.local, items: Sequence["Item"],
) -> Union[str, List[str]]:
"""
.. versionadded:: 3.2

return a string or list of strings to be displayed after collection has finished successfully.
Return a string or list of strings to be displayed after collection has finished successfully.

These strings will be displayed after the standard "collected X items" message.

Expand All @@ -689,7 +697,7 @@ def pytest_report_collectionfinish(

@hookspec(firstresult=True)
def pytest_report_teststatus(
report: "BaseReport", config: "Config"
report: Union["CollectReport", "TestReport"], config: "Config"
) -> Tuple[
str, str, Union[str, Mapping[str, bool]],
]:
Expand Down Expand Up @@ -734,7 +742,7 @@ def pytest_terminal_summary(
def pytest_warning_captured(
warning_message: "warnings.WarningMessage",
when: "Literal['config', 'collect', 'runtest']",
item: "Optional[Item]",
item: Optional["Item"],
location: Optional[Tuple[str, int, str]],
) -> None:
"""(**Deprecated**) Process a warning captured by the internal pytest warnings plugin.
Expand Down Expand Up @@ -797,18 +805,6 @@ def pytest_warning_recorded(
"""


# -------------------------------------------------------------------------
# doctest hooks
# -------------------------------------------------------------------------


@hookspec(firstresult=True)
def pytest_doctest_prepare_content(content):
""" return processed content for a given doctest

Stops at first non-None result, see :ref:`firstresult` """


# -------------------------------------------------------------------------
# error handling and internal debugging hooks
# -------------------------------------------------------------------------
Expand All @@ -831,7 +827,9 @@ def pytest_keyboard_interrupt(


def pytest_exception_interact(
node: "Node", call: "CallInfo[object]", report: "Union[CollectReport, TestReport]"
node: "Node",
call: "CallInfo[object]",
report: Union["CollectReport", "TestReport"],
) -> None:
"""Called when an exception was raised which can potentially be
interactively handled.
Expand Down
8 changes: 3 additions & 5 deletions src/_pytest/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -302,8 +302,8 @@ def _main(config: Config, session: "Session") -> Optional[Union[int, ExitCode]]:
return None


def pytest_collection(session: "Session") -> Sequence[nodes.Item]:
return session.perform_collect()
def pytest_collection(session: "Session") -> None:
session.perform_collect()


def pytest_runtestloop(session: "Session") -> bool:
Expand Down Expand Up @@ -343,9 +343,7 @@ def _in_venv(path: py.path.local) -> bool:
return any([fname.basename in activates for fname in bindir.listdir()])


def pytest_ignore_collect(
path: py.path.local, config: Config
) -> "Optional[Literal[True]]":
def pytest_ignore_collect(path: py.path.local, config: Config) -> Optional[bool]:
ignore_paths = config._getconftest_pathlist("collect_ignore", path=path.dirpath())
ignore_paths = ignore_paths or []
excludeopt = config.getoption("ignore")
Expand Down
2 changes: 1 addition & 1 deletion src/_pytest/python.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ def sort_key(item):
return values

def _makeitem(
self, name: str, obj
self, name: str, obj: object
) -> Union[
None, nodes.Item, nodes.Collector, List[Union[nodes.Item, nodes.Collector]]
]:
Expand Down