aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/pytest/py3/_pytest/doctest.py
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.ru>2022-02-10 16:44:39 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:39 +0300
commite9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch)
tree64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/python/pytest/py3/_pytest/doctest.py
parent2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff)
downloadydb-e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0.tar.gz
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/pytest/py3/_pytest/doctest.py')
-rw-r--r--contrib/python/pytest/py3/_pytest/doctest.py746
1 files changed, 373 insertions, 373 deletions
diff --git a/contrib/python/pytest/py3/_pytest/doctest.py b/contrib/python/pytest/py3/_pytest/doctest.py
index 797c75d9c4..64e8f0e0ee 100644
--- a/contrib/python/pytest/py3/_pytest/doctest.py
+++ b/contrib/python/pytest/py3/_pytest/doctest.py
@@ -1,47 +1,47 @@
-"""Discover and run doctests in modules and test files."""
-import bdb
-import inspect
+"""Discover and run doctests in modules and test files."""
+import bdb
+import inspect
import platform
import sys
import traceback
-import types
-import warnings
-from contextlib import contextmanager
-from typing import Any
-from typing import Callable
-from typing import Dict
-from typing import Generator
-from typing import Iterable
-from typing import List
-from typing import Optional
-from typing import Pattern
-from typing import Sequence
-from typing import Tuple
-from typing import Type
-from typing import TYPE_CHECKING
-from typing import Union
-
-import py.path
-
+import types
+import warnings
+from contextlib import contextmanager
+from typing import Any
+from typing import Callable
+from typing import Dict
+from typing import Generator
+from typing import Iterable
+from typing import List
+from typing import Optional
+from typing import Pattern
+from typing import Sequence
+from typing import Tuple
+from typing import Type
+from typing import TYPE_CHECKING
+from typing import Union
+
+import py.path
+
import pytest
-from _pytest import outcomes
+from _pytest import outcomes
from _pytest._code.code import ExceptionInfo
from _pytest._code.code import ReprFileLocation
from _pytest._code.code import TerminalRepr
-from _pytest._io import TerminalWriter
-from _pytest.compat import safe_getattr
-from _pytest.config import Config
-from _pytest.config.argparsing import Parser
+from _pytest._io import TerminalWriter
+from _pytest.compat import safe_getattr
+from _pytest.config import Config
+from _pytest.config.argparsing import Parser
from _pytest.fixtures import FixtureRequest
-from _pytest.nodes import Collector
-from _pytest.outcomes import OutcomeException
-from _pytest.pathlib import import_path
-from _pytest.python_api import approx
-from _pytest.warning_types import PytestWarning
-
-if TYPE_CHECKING:
- import doctest
-
+from _pytest.nodes import Collector
+from _pytest.outcomes import OutcomeException
+from _pytest.pathlib import import_path
+from _pytest.python_api import approx
+from _pytest.warning_types import PytestWarning
+
+if TYPE_CHECKING:
+ import doctest
+
DOCTEST_REPORT_CHOICE_NONE = "none"
DOCTEST_REPORT_CHOICE_CDIFF = "cdiff"
DOCTEST_REPORT_CHOICE_NDIFF = "ndiff"
@@ -58,11 +58,11 @@ DOCTEST_REPORT_CHOICES = (
# Lazy definition of runner class
RUNNER_CLASS = None
-# Lazy definition of output checker class
-CHECKER_CLASS: Optional[Type["doctest.OutputChecker"]] = None
+# Lazy definition of output checker class
+CHECKER_CLASS: Optional[Type["doctest.OutputChecker"]] = None
-def pytest_addoption(parser: Parser) -> None:
+def pytest_addoption(parser: Parser) -> None:
parser.addini(
"doctest_optionflags",
"option flags for doctests",
@@ -112,34 +112,34 @@ def pytest_addoption(parser: Parser) -> None:
)
-def pytest_unconfigure() -> None:
- global RUNNER_CLASS
-
- RUNNER_CLASS = None
-
-
-def pytest_collect_file(
- path: py.path.local, parent: Collector,
-) -> Optional[Union["DoctestModule", "DoctestTextfile"]]:
+def pytest_unconfigure() -> None:
+ global RUNNER_CLASS
+
+ RUNNER_CLASS = None
+
+
+def pytest_collect_file(
+ path: py.path.local, parent: Collector,
+) -> Optional[Union["DoctestModule", "DoctestTextfile"]]:
config = parent.config
if path.ext == ".py":
- if config.option.doctestmodules and not _is_setup_py(path):
- mod: DoctestModule = DoctestModule.from_parent(parent, fspath=path)
- return mod
+ if config.option.doctestmodules and not _is_setup_py(path):
+ mod: DoctestModule = DoctestModule.from_parent(parent, fspath=path)
+ return mod
elif _is_doctest(config, path, parent):
- txt: DoctestTextfile = DoctestTextfile.from_parent(parent, fspath=path)
- return txt
- return None
+ txt: DoctestTextfile = DoctestTextfile.from_parent(parent, fspath=path)
+ return txt
+ return None
-def _is_setup_py(path: py.path.local) -> bool:
+def _is_setup_py(path: py.path.local) -> bool:
if path.basename != "setup.py":
return False
- contents = path.read_binary()
- return b"setuptools" in contents or b"distutils" in contents
+ contents = path.read_binary()
+ return b"setuptools" in contents or b"distutils" in contents
-def _is_doctest(config: Config, path: py.path.local, parent) -> bool:
+def _is_doctest(config: Config, path: py.path.local, parent) -> bool:
if path.ext in (".txt", ".rst") and parent.session.isinitpath(path):
return True
globs = config.getoption("doctestglob") or ["test*.txt"]
@@ -150,12 +150,12 @@ def _is_doctest(config: Config, path: py.path.local, parent) -> bool:
class ReprFailDoctest(TerminalRepr):
- def __init__(
- self, reprlocation_lines: Sequence[Tuple[ReprFileLocation, Sequence[str]]]
- ) -> None:
+ def __init__(
+ self, reprlocation_lines: Sequence[Tuple[ReprFileLocation, Sequence[str]]]
+ ) -> None:
self.reprlocation_lines = reprlocation_lines
- def toterminal(self, tw: TerminalWriter) -> None:
+ def toterminal(self, tw: TerminalWriter) -> None:
for reprlocation, lines in self.reprlocation_lines:
for line in lines:
tw.line(line)
@@ -163,53 +163,53 @@ class ReprFailDoctest(TerminalRepr):
class MultipleDoctestFailures(Exception):
- def __init__(self, failures: Sequence["doctest.DocTestFailure"]) -> None:
- super().__init__()
+ def __init__(self, failures: Sequence["doctest.DocTestFailure"]) -> None:
+ super().__init__()
self.failures = failures
-def _init_runner_class() -> Type["doctest.DocTestRunner"]:
+def _init_runner_class() -> Type["doctest.DocTestRunner"]:
import doctest
class PytestDoctestRunner(doctest.DebugRunner):
- """Runner to collect failures.
-
- Note that the out variable in this case is a list instead of a
- stdout-like object.
+ """Runner to collect failures.
+
+ Note that the out variable in this case is a list instead of a
+ stdout-like object.
"""
def __init__(
- self,
- checker: Optional["doctest.OutputChecker"] = None,
- verbose: Optional[bool] = None,
- optionflags: int = 0,
- continue_on_failure: bool = True,
- ) -> None:
+ self,
+ checker: Optional["doctest.OutputChecker"] = None,
+ verbose: Optional[bool] = None,
+ optionflags: int = 0,
+ continue_on_failure: bool = True,
+ ) -> None:
doctest.DebugRunner.__init__(
self, checker=checker, verbose=verbose, optionflags=optionflags
)
self.continue_on_failure = continue_on_failure
- def report_failure(
- self, out, test: "doctest.DocTest", example: "doctest.Example", got: str,
- ) -> None:
+ def report_failure(
+ self, out, test: "doctest.DocTest", example: "doctest.Example", got: str,
+ ) -> None:
failure = doctest.DocTestFailure(test, example, got)
if self.continue_on_failure:
out.append(failure)
else:
raise failure
- def report_unexpected_exception(
- self,
- out,
- test: "doctest.DocTest",
- example: "doctest.Example",
- exc_info: Tuple[Type[BaseException], BaseException, types.TracebackType],
- ) -> None:
- if isinstance(exc_info[1], OutcomeException):
- raise exc_info[1]
- if isinstance(exc_info[1], bdb.BdbQuit):
- outcomes.exit("Quitting debugger")
+ def report_unexpected_exception(
+ self,
+ out,
+ test: "doctest.DocTest",
+ example: "doctest.Example",
+ exc_info: Tuple[Type[BaseException], BaseException, types.TracebackType],
+ ) -> None:
+ if isinstance(exc_info[1], OutcomeException):
+ raise exc_info[1]
+ if isinstance(exc_info[1], bdb.BdbQuit):
+ outcomes.exit("Quitting debugger")
failure = doctest.UnexpectedException(test, example, exc_info)
if self.continue_on_failure:
out.append(failure)
@@ -219,19 +219,19 @@ def _init_runner_class() -> Type["doctest.DocTestRunner"]:
return PytestDoctestRunner
-def _get_runner(
- checker: Optional["doctest.OutputChecker"] = None,
- verbose: Optional[bool] = None,
- optionflags: int = 0,
- continue_on_failure: bool = True,
-) -> "doctest.DocTestRunner":
+def _get_runner(
+ checker: Optional["doctest.OutputChecker"] = None,
+ verbose: Optional[bool] = None,
+ optionflags: int = 0,
+ continue_on_failure: bool = True,
+) -> "doctest.DocTestRunner":
# We need this in order to do a lazy import on doctest
global RUNNER_CLASS
if RUNNER_CLASS is None:
RUNNER_CLASS = _init_runner_class()
- # Type ignored because the continue_on_failure argument is only defined on
- # PytestDoctestRunner, which is lazily defined so can't be used as a type.
- return RUNNER_CLASS( # type: ignore
+ # Type ignored because the continue_on_failure argument is only defined on
+ # PytestDoctestRunner, which is lazily defined so can't be used as a type.
+ return RUNNER_CLASS( # type: ignore
checker=checker,
verbose=verbose,
optionflags=optionflags,
@@ -240,33 +240,33 @@ def _get_runner(
class DoctestItem(pytest.Item):
- def __init__(
- self,
- name: str,
- parent: "Union[DoctestTextfile, DoctestModule]",
- runner: Optional["doctest.DocTestRunner"] = None,
- dtest: Optional["doctest.DocTest"] = None,
- ) -> None:
- super().__init__(name, parent)
+ def __init__(
+ self,
+ name: str,
+ parent: "Union[DoctestTextfile, DoctestModule]",
+ runner: Optional["doctest.DocTestRunner"] = None,
+ dtest: Optional["doctest.DocTest"] = None,
+ ) -> None:
+ super().__init__(name, parent)
self.runner = runner
self.dtest = dtest
self.obj = None
- self.fixture_request: Optional[FixtureRequest] = None
-
- @classmethod
- def from_parent( # type: ignore
- cls,
- parent: "Union[DoctestTextfile, DoctestModule]",
- *,
- name: str,
- runner: "doctest.DocTestRunner",
- dtest: "doctest.DocTest",
- ):
- # incompatible signature due to to imposed limits on sublcass
- """The public named constructor."""
- return super().from_parent(name=name, parent=parent, runner=runner, dtest=dtest)
-
- def setup(self) -> None:
+ self.fixture_request: Optional[FixtureRequest] = None
+
+ @classmethod
+ def from_parent( # type: ignore
+ cls,
+ parent: "Union[DoctestTextfile, DoctestModule]",
+ *,
+ name: str,
+ runner: "doctest.DocTestRunner",
+ dtest: "doctest.DocTest",
+ ):
+ # incompatible signature due to to imposed limits on sublcass
+ """The public named constructor."""
+ return super().from_parent(name=name, parent=parent, runner=runner, dtest=dtest)
+
+ def setup(self) -> None:
if self.dtest is not None:
self.fixture_request = _setup_fixtures(self)
globs = dict(getfixture=self.fixture_request.getfixturevalue)
@@ -276,20 +276,20 @@ class DoctestItem(pytest.Item):
globs[name] = value
self.dtest.globs.update(globs)
- def runtest(self) -> None:
- assert self.dtest is not None
- assert self.runner is not None
+ def runtest(self) -> None:
+ assert self.dtest is not None
+ assert self.runner is not None
_check_all_skipped(self.dtest)
self._disable_output_capturing_for_darwin()
- failures: List["doctest.DocTestFailure"] = []
- # Type ignored because we change the type of `out` from what
- # doctest expects.
- self.runner.run(self.dtest, out=failures) # type: ignore[arg-type]
+ failures: List["doctest.DocTestFailure"] = []
+ # Type ignored because we change the type of `out` from what
+ # doctest expects.
+ self.runner.run(self.dtest, out=failures) # type: ignore[arg-type]
if failures:
raise MultipleDoctestFailures(failures)
- def _disable_output_capturing_for_darwin(self) -> None:
- """Disable output capturing. Otherwise, stdout is lost to doctest (#985)."""
+ def _disable_output_capturing_for_darwin(self) -> None:
+ """Disable output capturing. Otherwise, stdout is lost to doctest (#985)."""
if platform.system() != "Darwin":
return
capman = self.config.pluginmanager.getplugin("capturemanager")
@@ -299,20 +299,20 @@ class DoctestItem(pytest.Item):
sys.stdout.write(out)
sys.stderr.write(err)
- # TODO: Type ignored -- breaks Liskov Substitution.
- def repr_failure( # type: ignore[override]
- self, excinfo: ExceptionInfo[BaseException],
- ) -> Union[str, TerminalRepr]:
+ # TODO: Type ignored -- breaks Liskov Substitution.
+ def repr_failure( # type: ignore[override]
+ self, excinfo: ExceptionInfo[BaseException],
+ ) -> Union[str, TerminalRepr]:
import doctest
- failures: Optional[
- Sequence[Union[doctest.DocTestFailure, doctest.UnexpectedException]]
- ] = (None)
- if isinstance(
- excinfo.value, (doctest.DocTestFailure, doctest.UnexpectedException)
- ):
+ failures: Optional[
+ Sequence[Union[doctest.DocTestFailure, doctest.UnexpectedException]]
+ ] = (None)
+ if isinstance(
+ excinfo.value, (doctest.DocTestFailure, doctest.UnexpectedException)
+ ):
failures = [excinfo.value]
- elif isinstance(excinfo.value, MultipleDoctestFailures):
+ elif isinstance(excinfo.value, MultipleDoctestFailures):
failures = excinfo.value.failures
if failures is not None:
@@ -326,17 +326,17 @@ class DoctestItem(pytest.Item):
else:
lineno = test.lineno + example.lineno + 1
message = type(failure).__name__
- # TODO: ReprFileLocation doesn't expect a None lineno.
- reprlocation = ReprFileLocation(filename, lineno, message) # type: ignore[arg-type]
+ # TODO: ReprFileLocation doesn't expect a None lineno.
+ reprlocation = ReprFileLocation(filename, lineno, message) # type: ignore[arg-type]
checker = _get_checker()
report_choice = _get_report_choice(
self.config.getoption("doctestreport")
)
if lineno is not None:
- assert failure.test.docstring is not None
+ assert failure.test.docstring is not None
lines = failure.test.docstring.splitlines(False)
# add line numbers to the left of the error message
- assert test.lineno is not None
+ assert test.lineno is not None
lines = [
"%03d %s" % (i + test.lineno + 1, x)
for (i, x) in enumerate(lines)
@@ -349,7 +349,7 @@ class DoctestItem(pytest.Item):
]
indent = ">>>"
for line in example.source.splitlines():
- lines.append(f"??? {indent} {line}")
+ lines.append(f"??? {indent} {line}")
indent = "..."
if isinstance(failure, doctest.DocTestFailure):
lines += checker.output_difference(
@@ -358,21 +358,21 @@ class DoctestItem(pytest.Item):
else:
inner_excinfo = ExceptionInfo(failure.exc_info)
lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)]
- lines += [
- x.strip("\n")
- for x in traceback.format_exception(*failure.exc_info)
- ]
+ lines += [
+ x.strip("\n")
+ for x in traceback.format_exception(*failure.exc_info)
+ ]
reprlocation_lines.append((reprlocation, lines))
return ReprFailDoctest(reprlocation_lines)
else:
- return super().repr_failure(excinfo)
+ return super().repr_failure(excinfo)
- def reportinfo(self):
- assert self.dtest is not None
+ def reportinfo(self):
+ assert self.dtest is not None
return self.fspath, self.dtest.lineno, "[doctest] %s" % self.name
-def _get_flag_lookup() -> Dict[str, int]:
+def _get_flag_lookup() -> Dict[str, int]:
import doctest
return dict(
@@ -384,7 +384,7 @@ def _get_flag_lookup() -> Dict[str, int]:
COMPARISON_FLAGS=doctest.COMPARISON_FLAGS,
ALLOW_UNICODE=_get_allow_unicode_flag(),
ALLOW_BYTES=_get_allow_bytes_flag(),
- NUMBER=_get_number_flag(),
+ NUMBER=_get_number_flag(),
)
@@ -401,7 +401,7 @@ def _get_continue_on_failure(config):
continue_on_failure = config.getvalue("doctest_continue_on_failure")
if continue_on_failure:
# We need to turn off this if we use pdb since we should stop at
- # the first failure.
+ # the first failure.
if config.getvalue("usepdb"):
continue_on_failure = False
return continue_on_failure
@@ -410,11 +410,11 @@ def _get_continue_on_failure(config):
class DoctestTextfile(pytest.Module):
obj = None
- def collect(self) -> Iterable[DoctestItem]:
+ def collect(self) -> Iterable[DoctestItem]:
import doctest
- # Inspired by doctest.testfile; ideally we would use it directly,
- # but it doesn't support passing a custom checker.
+ # Inspired by doctest.testfile; ideally we would use it directly,
+ # but it doesn't support passing a custom checker.
encoding = self.config.getini("doctest_encoding")
text = self.fspath.read_text(encoding)
filename = str(self.fspath)
@@ -424,7 +424,7 @@ class DoctestTextfile(pytest.Module):
optionflags = get_optionflags(self)
runner = _get_runner(
- verbose=False,
+ verbose=False,
optionflags=optionflags,
checker=_get_checker(),
continue_on_failure=_get_continue_on_failure(self.config),
@@ -433,14 +433,14 @@ class DoctestTextfile(pytest.Module):
parser = doctest.DocTestParser()
test = parser.get_doctest(text, globs, name, filename, 0)
if test.examples:
- yield DoctestItem.from_parent(
- self, name=test.name, runner=runner, dtest=test
- )
+ yield DoctestItem.from_parent(
+ self, name=test.name, runner=runner, dtest=test
+ )
-def _check_all_skipped(test: "doctest.DocTest") -> None:
- """Raise pytest.skip() if all examples in the given DocTest have the SKIP
- option set."""
+def _check_all_skipped(test: "doctest.DocTest") -> None:
+ """Raise pytest.skip() if all examples in the given DocTest have the SKIP
+ option set."""
import doctest
all_skipped = all(x.options.get(doctest.SKIP, False) for x in test.examples)
@@ -448,98 +448,98 @@ def _check_all_skipped(test: "doctest.DocTest") -> None:
pytest.skip("all tests skipped by +SKIP option")
-def _is_mocked(obj: object) -> bool:
- """Return if an object is possibly a mock object by checking the
- existence of a highly improbable attribute."""
- return (
- safe_getattr(obj, "pytest_mock_example_attribute_that_shouldnt_exist", None)
- is not None
- )
-
-
-@contextmanager
-def _patch_unwrap_mock_aware() -> Generator[None, None, None]:
- """Context manager which replaces ``inspect.unwrap`` with a version
- that's aware of mock objects and doesn't recurse into them."""
- real_unwrap = inspect.unwrap
-
- def _mock_aware_unwrap(
- func: Callable[..., Any], *, stop: Optional[Callable[[Any], Any]] = None
- ) -> Any:
- try:
- if stop is None or stop is _is_mocked:
- return real_unwrap(func, stop=_is_mocked)
- _stop = stop
- return real_unwrap(func, stop=lambda obj: _is_mocked(obj) or _stop(func))
- except Exception as e:
- warnings.warn(
- "Got %r when unwrapping %r. This is usually caused "
- "by a violation of Python's object protocol; see e.g. "
- "https://github.com/pytest-dev/pytest/issues/5080" % (e, func),
- PytestWarning,
- )
- raise
-
- inspect.unwrap = _mock_aware_unwrap
- try:
- yield
- finally:
- inspect.unwrap = real_unwrap
-
-
+def _is_mocked(obj: object) -> bool:
+ """Return if an object is possibly a mock object by checking the
+ existence of a highly improbable attribute."""
+ return (
+ safe_getattr(obj, "pytest_mock_example_attribute_that_shouldnt_exist", None)
+ is not None
+ )
+
+
+@contextmanager
+def _patch_unwrap_mock_aware() -> Generator[None, None, None]:
+ """Context manager which replaces ``inspect.unwrap`` with a version
+ that's aware of mock objects and doesn't recurse into them."""
+ real_unwrap = inspect.unwrap
+
+ def _mock_aware_unwrap(
+ func: Callable[..., Any], *, stop: Optional[Callable[[Any], Any]] = None
+ ) -> Any:
+ try:
+ if stop is None or stop is _is_mocked:
+ return real_unwrap(func, stop=_is_mocked)
+ _stop = stop
+ return real_unwrap(func, stop=lambda obj: _is_mocked(obj) or _stop(func))
+ except Exception as e:
+ warnings.warn(
+ "Got %r when unwrapping %r. This is usually caused "
+ "by a violation of Python's object protocol; see e.g. "
+ "https://github.com/pytest-dev/pytest/issues/5080" % (e, func),
+ PytestWarning,
+ )
+ raise
+
+ inspect.unwrap = _mock_aware_unwrap
+ try:
+ yield
+ finally:
+ inspect.unwrap = real_unwrap
+
+
class DoctestModule(pytest.Module):
- def collect(self) -> Iterable[DoctestItem]:
+ def collect(self) -> Iterable[DoctestItem]:
import doctest
- class MockAwareDocTestFinder(doctest.DocTestFinder):
- """A hackish doctest finder that overrides stdlib internals to fix a stdlib bug.
-
- https://github.com/pytest-dev/pytest/issues/3456
- https://bugs.python.org/issue25532
- """
-
- def _find_lineno(self, obj, source_lines):
- """Doctest code does not take into account `@property`, this
- is a hackish way to fix it.
-
- https://bugs.python.org/issue17446
- """
- if isinstance(obj, property):
- obj = getattr(obj, "fget", obj)
- # Type ignored because this is a private function.
- return doctest.DocTestFinder._find_lineno( # type: ignore
- self, obj, source_lines,
- )
-
- def _find(
- self, tests, obj, name, module, source_lines, globs, seen
- ) -> None:
- if _is_mocked(obj):
- return
- with _patch_unwrap_mock_aware():
-
- # Type ignored because this is a private function.
- doctest.DocTestFinder._find( # type: ignore
- self, tests, obj, name, module, source_lines, globs, seen
- )
-
+ class MockAwareDocTestFinder(doctest.DocTestFinder):
+ """A hackish doctest finder that overrides stdlib internals to fix a stdlib bug.
+
+ https://github.com/pytest-dev/pytest/issues/3456
+ https://bugs.python.org/issue25532
+ """
+
+ def _find_lineno(self, obj, source_lines):
+ """Doctest code does not take into account `@property`, this
+ is a hackish way to fix it.
+
+ https://bugs.python.org/issue17446
+ """
+ if isinstance(obj, property):
+ obj = getattr(obj, "fget", obj)
+ # Type ignored because this is a private function.
+ return doctest.DocTestFinder._find_lineno( # type: ignore
+ self, obj, source_lines,
+ )
+
+ def _find(
+ self, tests, obj, name, module, source_lines, globs, seen
+ ) -> None:
+ if _is_mocked(obj):
+ return
+ with _patch_unwrap_mock_aware():
+
+ # Type ignored because this is a private function.
+ doctest.DocTestFinder._find( # type: ignore
+ self, tests, obj, name, module, source_lines, globs, seen
+ )
+
if self.fspath.basename == "conftest.py":
- module = self.config.pluginmanager._importconftest(
- self.fspath, self.config.getoption("importmode")
- )
+ module = self.config.pluginmanager._importconftest(
+ self.fspath, self.config.getoption("importmode")
+ )
else:
try:
- module = import_path(self.fspath)
+ module = import_path(self.fspath)
except ImportError:
if self.config.getvalue("doctest_ignore_import_errors"):
pytest.skip("unable to import module %r" % self.fspath)
else:
raise
- # Uses internal doctest module parsing mechanism.
- finder = MockAwareDocTestFinder()
+ # Uses internal doctest module parsing mechanism.
+ finder = MockAwareDocTestFinder()
optionflags = get_optionflags(self)
runner = _get_runner(
- verbose=False,
+ verbose=False,
optionflags=optionflags,
checker=_get_checker(),
continue_on_failure=_get_continue_on_failure(self.config),
@@ -547,165 +547,165 @@ class DoctestModule(pytest.Module):
for test in finder.find(module, module.__name__):
if test.examples: # skip empty doctests
- yield DoctestItem.from_parent(
- self, name=test.name, runner=runner, dtest=test
- )
+ yield DoctestItem.from_parent(
+ self, name=test.name, runner=runner, dtest=test
+ )
-def _setup_fixtures(doctest_item: DoctestItem) -> FixtureRequest:
- """Used by DoctestTextfile and DoctestItem to setup fixture information."""
+def _setup_fixtures(doctest_item: DoctestItem) -> FixtureRequest:
+ """Used by DoctestTextfile and DoctestItem to setup fixture information."""
- def func() -> None:
+ def func() -> None:
pass
- doctest_item.funcargs = {} # type: ignore[attr-defined]
+ doctest_item.funcargs = {} # type: ignore[attr-defined]
fm = doctest_item.session._fixturemanager
- doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined]
+ doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined]
node=doctest_item, func=func, cls=None, funcargs=False
)
- fixture_request = FixtureRequest(doctest_item, _ispytest=True)
+ fixture_request = FixtureRequest(doctest_item, _ispytest=True)
fixture_request._fillfixtures()
return fixture_request
-def _init_checker_class() -> Type["doctest.OutputChecker"]:
+def _init_checker_class() -> Type["doctest.OutputChecker"]:
import doctest
import re
class LiteralsOutputChecker(doctest.OutputChecker):
- # Based on doctest_nose_plugin.py from the nltk project
- # (https://github.com/nltk/nltk) and on the "numtest" doctest extension
- # by Sebastien Boisgerault (https://github.com/boisgera/numtest).
+ # Based on doctest_nose_plugin.py from the nltk project
+ # (https://github.com/nltk/nltk) and on the "numtest" doctest extension
+ # by Sebastien Boisgerault (https://github.com/boisgera/numtest).
_unicode_literal_re = re.compile(r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE)
_bytes_literal_re = re.compile(r"(\W|^)[bB]([rR]?[\'\"])", re.UNICODE)
- _number_re = re.compile(
- r"""
- (?P<number>
- (?P<mantissa>
- (?P<integer1> [+-]?\d*)\.(?P<fraction>\d+)
- |
- (?P<integer2> [+-]?\d+)\.
- )
- (?:
- [Ee]
- (?P<exponent1> [+-]?\d+)
- )?
- |
- (?P<integer3> [+-]?\d+)
- (?:
- [Ee]
- (?P<exponent2> [+-]?\d+)
- )
- )
- """,
- re.VERBOSE,
- )
-
- def check_output(self, want: str, got: str, optionflags: int) -> bool:
- if doctest.OutputChecker.check_output(self, want, got, optionflags):
+ _number_re = re.compile(
+ r"""
+ (?P<number>
+ (?P<mantissa>
+ (?P<integer1> [+-]?\d*)\.(?P<fraction>\d+)
+ |
+ (?P<integer2> [+-]?\d+)\.
+ )
+ (?:
+ [Ee]
+ (?P<exponent1> [+-]?\d+)
+ )?
+ |
+ (?P<integer3> [+-]?\d+)
+ (?:
+ [Ee]
+ (?P<exponent2> [+-]?\d+)
+ )
+ )
+ """,
+ re.VERBOSE,
+ )
+
+ def check_output(self, want: str, got: str, optionflags: int) -> bool:
+ if doctest.OutputChecker.check_output(self, want, got, optionflags):
return True
allow_unicode = optionflags & _get_allow_unicode_flag()
allow_bytes = optionflags & _get_allow_bytes_flag()
- allow_number = optionflags & _get_number_flag()
-
- if not allow_unicode and not allow_bytes and not allow_number:
+ allow_number = optionflags & _get_number_flag()
+
+ if not allow_unicode and not allow_bytes and not allow_number:
return False
- def remove_prefixes(regex: Pattern[str], txt: str) -> str:
- return re.sub(regex, r"\1\2", txt)
-
- if allow_unicode:
- want = remove_prefixes(self._unicode_literal_re, want)
- got = remove_prefixes(self._unicode_literal_re, got)
-
- if allow_bytes:
- want = remove_prefixes(self._bytes_literal_re, want)
- got = remove_prefixes(self._bytes_literal_re, got)
-
- if allow_number:
- got = self._remove_unwanted_precision(want, got)
-
- return doctest.OutputChecker.check_output(self, want, got, optionflags)
-
- def _remove_unwanted_precision(self, want: str, got: str) -> str:
- wants = list(self._number_re.finditer(want))
- gots = list(self._number_re.finditer(got))
- if len(wants) != len(gots):
- return got
- offset = 0
- for w, g in zip(wants, gots):
- fraction: Optional[str] = w.group("fraction")
- exponent: Optional[str] = w.group("exponent1")
- if exponent is None:
- exponent = w.group("exponent2")
- if fraction is None:
- precision = 0
- else:
- precision = len(fraction)
- if exponent is not None:
- precision -= int(exponent)
- if float(w.group()) == approx(float(g.group()), abs=10 ** -precision):
- # They're close enough. Replace the text we actually
- # got with the text we want, so that it will match when we
- # check the string literally.
- got = (
- got[: g.start() + offset] + w.group() + got[g.end() + offset :]
- )
- offset += w.end() - w.start() - (g.end() - g.start())
- return got
-
- return LiteralsOutputChecker
-
-
-def _get_checker() -> "doctest.OutputChecker":
- """Return a doctest.OutputChecker subclass that supports some
- additional options:
-
- * ALLOW_UNICODE and ALLOW_BYTES options to ignore u'' and b''
- prefixes (respectively) in string literals. Useful when the same
- doctest should run in Python 2 and Python 3.
-
- * NUMBER to ignore floating-point differences smaller than the
- precision of the literal number in the doctest.
-
- An inner class is used to avoid importing "doctest" at the module
- level.
- """
- global CHECKER_CLASS
- if CHECKER_CLASS is None:
- CHECKER_CLASS = _init_checker_class()
- return CHECKER_CLASS()
-
-
-def _get_allow_unicode_flag() -> int:
- """Register and return the ALLOW_UNICODE flag."""
+ def remove_prefixes(regex: Pattern[str], txt: str) -> str:
+ return re.sub(regex, r"\1\2", txt)
+
+ if allow_unicode:
+ want = remove_prefixes(self._unicode_literal_re, want)
+ got = remove_prefixes(self._unicode_literal_re, got)
+
+ if allow_bytes:
+ want = remove_prefixes(self._bytes_literal_re, want)
+ got = remove_prefixes(self._bytes_literal_re, got)
+
+ if allow_number:
+ got = self._remove_unwanted_precision(want, got)
+
+ return doctest.OutputChecker.check_output(self, want, got, optionflags)
+
+ def _remove_unwanted_precision(self, want: str, got: str) -> str:
+ wants = list(self._number_re.finditer(want))
+ gots = list(self._number_re.finditer(got))
+ if len(wants) != len(gots):
+ return got
+ offset = 0
+ for w, g in zip(wants, gots):
+ fraction: Optional[str] = w.group("fraction")
+ exponent: Optional[str] = w.group("exponent1")
+ if exponent is None:
+ exponent = w.group("exponent2")
+ if fraction is None:
+ precision = 0
+ else:
+ precision = len(fraction)
+ if exponent is not None:
+ precision -= int(exponent)
+ if float(w.group()) == approx(float(g.group()), abs=10 ** -precision):
+ # They're close enough. Replace the text we actually
+ # got with the text we want, so that it will match when we
+ # check the string literally.
+ got = (
+ got[: g.start() + offset] + w.group() + got[g.end() + offset :]
+ )
+ offset += w.end() - w.start() - (g.end() - g.start())
+ return got
+
+ return LiteralsOutputChecker
+
+
+def _get_checker() -> "doctest.OutputChecker":
+ """Return a doctest.OutputChecker subclass that supports some
+ additional options:
+
+ * ALLOW_UNICODE and ALLOW_BYTES options to ignore u'' and b''
+ prefixes (respectively) in string literals. Useful when the same
+ doctest should run in Python 2 and Python 3.
+
+ * NUMBER to ignore floating-point differences smaller than the
+ precision of the literal number in the doctest.
+
+ An inner class is used to avoid importing "doctest" at the module
+ level.
+ """
+ global CHECKER_CLASS
+ if CHECKER_CLASS is None:
+ CHECKER_CLASS = _init_checker_class()
+ return CHECKER_CLASS()
+
+
+def _get_allow_unicode_flag() -> int:
+ """Register and return the ALLOW_UNICODE flag."""
import doctest
return doctest.register_optionflag("ALLOW_UNICODE")
-def _get_allow_bytes_flag() -> int:
- """Register and return the ALLOW_BYTES flag."""
+def _get_allow_bytes_flag() -> int:
+ """Register and return the ALLOW_BYTES flag."""
import doctest
return doctest.register_optionflag("ALLOW_BYTES")
-def _get_number_flag() -> int:
- """Register and return the NUMBER flag."""
- import doctest
-
- return doctest.register_optionflag("NUMBER")
-
-
-def _get_report_choice(key: str) -> int:
- """Return the actual `doctest` module flag value.
-
- We want to do it as late as possible to avoid importing `doctest` and all
- its dependencies when parsing options, as it adds overhead and breaks tests.
- """
+def _get_number_flag() -> int:
+ """Register and return the NUMBER flag."""
+ import doctest
+
+ return doctest.register_optionflag("NUMBER")
+
+
+def _get_report_choice(key: str) -> int:
+ """Return the actual `doctest` module flag value.
+
+ We want to do it as late as possible to avoid importing `doctest` and all
+ its dependencies when parsing options, as it adds overhead and breaks tests.
+ """
import doctest
return {
@@ -718,7 +718,7 @@ def _get_report_choice(key: str) -> int:
@pytest.fixture(scope="session")
-def doctest_namespace() -> Dict[str, Any]:
- """Fixture that returns a :py:class:`dict` that will be injected into the
- namespace of doctests."""
+def doctest_namespace() -> Dict[str, Any]:
+ """Fixture that returns a :py:class:`dict` that will be injected into the
+ namespace of doctests."""
return dict()