diff options
author | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
---|---|---|
committer | monster <monster@ydb.tech> | 2022-07-07 14:41:37 +0300 |
commit | 06e5c21a835c0e923506c4ff27929f34e00761c2 (patch) | |
tree | 75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /contrib/python/ipython/py3/IPython/testing/plugin/pytest_ipdoctest.py | |
parent | 03f024c4412e3aa613bb543cf1660176320ba8f4 (diff) | |
download | ydb-06e5c21a835c0e923506c4ff27929f34e00761c2.tar.gz |
fix ya.make
Diffstat (limited to 'contrib/python/ipython/py3/IPython/testing/plugin/pytest_ipdoctest.py')
-rw-r--r-- | contrib/python/ipython/py3/IPython/testing/plugin/pytest_ipdoctest.py | 860 |
1 files changed, 0 insertions, 860 deletions
diff --git a/contrib/python/ipython/py3/IPython/testing/plugin/pytest_ipdoctest.py b/contrib/python/ipython/py3/IPython/testing/plugin/pytest_ipdoctest.py deleted file mode 100644 index 809713d7c8..0000000000 --- a/contrib/python/ipython/py3/IPython/testing/plugin/pytest_ipdoctest.py +++ /dev/null @@ -1,860 +0,0 @@ -# Based on Pytest doctest.py -# Original license: -# The MIT License (MIT) -# -# Copyright (c) 2004-2021 Holger Krekel and others -"""Discover and run ipdoctests in modules and test files.""" -import builtins -import bdb -import inspect -import os -import platform -import sys -import traceback -import types -import warnings -from contextlib import contextmanager -from pathlib import Path -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 pytest -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.fixtures import FixtureRequest -from _pytest.nodes import Collector -from _pytest.outcomes import OutcomeException -from _pytest.pathlib import fnmatch_ex -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" -DOCTEST_REPORT_CHOICE_UDIFF = "udiff" -DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE = "only_first_failure" - -DOCTEST_REPORT_CHOICES = ( - DOCTEST_REPORT_CHOICE_NONE, - DOCTEST_REPORT_CHOICE_CDIFF, - DOCTEST_REPORT_CHOICE_NDIFF, - DOCTEST_REPORT_CHOICE_UDIFF, - DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE, -) - -# Lazy definition of runner class -RUNNER_CLASS = None -# Lazy definition of output checker class -CHECKER_CLASS: Optional[Type["IPDoctestOutputChecker"]] = None - - -def pytest_addoption(parser: Parser) -> None: - parser.addini( - "ipdoctest_optionflags", - "option flags for ipdoctests", - type="args", - default=["ELLIPSIS"], - ) - parser.addini( - "ipdoctest_encoding", "encoding used for ipdoctest files", default="utf-8" - ) - group = parser.getgroup("collect") - group.addoption( - "--ipdoctest-modules", - action="store_true", - default=False, - help="run ipdoctests in all .py modules", - dest="ipdoctestmodules", - ) - group.addoption( - "--ipdoctest-report", - type=str.lower, - default="udiff", - help="choose another output format for diffs on ipdoctest failure", - choices=DOCTEST_REPORT_CHOICES, - dest="ipdoctestreport", - ) - group.addoption( - "--ipdoctest-glob", - action="append", - default=[], - metavar="pat", - help="ipdoctests file matching pattern, default: test*.txt", - dest="ipdoctestglob", - ) - group.addoption( - "--ipdoctest-ignore-import-errors", - action="store_true", - default=False, - help="ignore ipdoctest ImportErrors", - dest="ipdoctest_ignore_import_errors", - ) - group.addoption( - "--ipdoctest-continue-on-failure", - action="store_true", - default=False, - help="for a given ipdoctest, continue to run after the first failure", - dest="ipdoctest_continue_on_failure", - ) - - -def pytest_unconfigure() -> None: - global RUNNER_CLASS - - RUNNER_CLASS = None - - -def pytest_collect_file( - file_path: Path, - parent: Collector, -) -> Optional[Union["IPDoctestModule", "IPDoctestTextfile"]]: - config = parent.config - if file_path.suffix == ".py": - if config.option.ipdoctestmodules and not any( - (_is_setup_py(file_path), _is_main_py(file_path)) - ): - mod: IPDoctestModule = IPDoctestModule.from_parent(parent, path=file_path) - return mod - elif _is_ipdoctest(config, file_path, parent): - txt: IPDoctestTextfile = IPDoctestTextfile.from_parent(parent, path=file_path) - return txt - return None - - -if int(pytest.__version__.split(".")[0]) < 7: - _collect_file = pytest_collect_file - - def pytest_collect_file( - path, - parent: Collector, - ) -> Optional[Union["IPDoctestModule", "IPDoctestTextfile"]]: - return _collect_file(Path(path), parent) - - _import_path = import_path - - def import_path(path, root): - import py.path - - return _import_path(py.path.local(path)) - - -def _is_setup_py(path: Path) -> bool: - if path.name != "setup.py": - return False - contents = path.read_bytes() - return b"setuptools" in contents or b"distutils" in contents - - -def _is_ipdoctest(config: Config, path: Path, parent: Collector) -> bool: - if path.suffix in (".txt", ".rst") and parent.session.isinitpath(path): - return True - globs = config.getoption("ipdoctestglob") or ["test*.txt"] - return any(fnmatch_ex(glob, path) for glob in globs) - - -def _is_main_py(path: Path) -> bool: - return path.name == "__main__.py" - - -class ReprFailDoctest(TerminalRepr): - def __init__( - self, reprlocation_lines: Sequence[Tuple[ReprFileLocation, Sequence[str]]] - ) -> None: - self.reprlocation_lines = reprlocation_lines - - def toterminal(self, tw: TerminalWriter) -> None: - for reprlocation, lines in self.reprlocation_lines: - for line in lines: - tw.line(line) - reprlocation.toterminal(tw) - - -class MultipleDoctestFailures(Exception): - def __init__(self, failures: Sequence["doctest.DocTestFailure"]) -> None: - super().__init__() - self.failures = failures - - -def _init_runner_class() -> Type["IPDocTestRunner"]: - import doctest - from .ipdoctest import IPDocTestRunner - - class PytestDoctestRunner(IPDocTestRunner): - """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["IPDoctestOutputChecker"] = None, - verbose: Optional[bool] = None, - optionflags: int = 0, - continue_on_failure: bool = True, - ) -> None: - super().__init__(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: - 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") - failure = doctest.UnexpectedException(test, example, exc_info) - if self.continue_on_failure: - out.append(failure) - else: - raise failure - - return PytestDoctestRunner - - -def _get_runner( - checker: Optional["IPDoctestOutputChecker"] = None, - verbose: Optional[bool] = None, - optionflags: int = 0, - continue_on_failure: bool = True, -) -> "IPDocTestRunner": - # 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 - checker=checker, - verbose=verbose, - optionflags=optionflags, - continue_on_failure=continue_on_failure, - ) - - -class IPDoctestItem(pytest.Item): - def __init__( - self, - name: str, - parent: "Union[IPDoctestTextfile, IPDoctestModule]", - runner: Optional["IPDocTestRunner"] = 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[IPDoctestTextfile, IPDoctestModule]", - *, - name: str, - runner: "IPDocTestRunner", - dtest: "doctest.DocTest", - ): - # incompatible signature due to imposed limits on subclass - """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) - for name, value in self.fixture_request.getfixturevalue( - "ipdoctest_namespace" - ).items(): - globs[name] = value - self.dtest.globs.update(globs) - - from .ipdoctest import IPExample - - if isinstance(self.dtest.examples[0], IPExample): - # for IPython examples *only*, we swap the globals with the ipython - # namespace, after updating it with the globals (which doctest - # fills with the necessary info from the module being tested). - self._user_ns_orig = {} - self._user_ns_orig.update(_ip.user_ns) - _ip.user_ns.update(self.dtest.globs) - # We must remove the _ key in the namespace, so that Python's - # doctest code sets it naturally - _ip.user_ns.pop("_", None) - _ip.user_ns["__builtins__"] = builtins - self.dtest.globs = _ip.user_ns - - def teardown(self) -> None: - from .ipdoctest import IPExample - - # Undo the test.globs reassignment we made - if isinstance(self.dtest.examples[0], IPExample): - self.dtest.globs = {} - _ip.user_ns.clear() - _ip.user_ns.update(self._user_ns_orig) - del self._user_ns_orig - - self.dtest.globs.clear() - - 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"] = [] - - # exec(compile(..., "single", ...), ...) puts result in builtins._ - had_underscore_value = hasattr(builtins, "_") - underscore_original_value = getattr(builtins, "_", None) - - # Save our current directory and switch out to the one where the - # test was originally created, in case another doctest did a - # directory change. We'll restore this in the finally clause. - curdir = os.getcwd() - os.chdir(self.fspath.dirname) - try: - # Type ignored because we change the type of `out` from what - # ipdoctest expects. - self.runner.run(self.dtest, out=failures, clear_globs=False) # type: ignore[arg-type] - finally: - os.chdir(curdir) - if had_underscore_value: - setattr(builtins, "_", underscore_original_value) - elif hasattr(builtins, "_"): - delattr(builtins, "_") - - if failures: - raise MultipleDoctestFailures(failures) - - def _disable_output_capturing_for_darwin(self) -> None: - """Disable output capturing. Otherwise, stdout is lost to ipdoctest (pytest#985).""" - if platform.system() != "Darwin": - return - capman = self.config.pluginmanager.getplugin("capturemanager") - if capman: - capman.suspend_global_capture(in_=True) - out, err = capman.read_global_capture() - 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]: - import doctest - - 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): - failures = excinfo.value.failures - - if failures is None: - return super().repr_failure(excinfo) - - reprlocation_lines = [] - for failure in failures: - example = failure.example - test = failure.test - filename = test.filename - if test.lineno is None: - lineno = None - 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] - checker = _get_checker() - report_choice = _get_report_choice(self.config.getoption("ipdoctestreport")) - if lineno 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 - lines = [ - "%03d %s" % (i + test.lineno + 1, x) for (i, x) in enumerate(lines) - ] - # trim docstring error lines to 10 - lines = lines[max(example.lineno - 9, 0) : example.lineno + 1] - else: - lines = [ - "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example" - ] - indent = ">>>" - for line in example.source.splitlines(): - lines.append(f"??? {indent} {line}") - indent = "..." - if isinstance(failure, doctest.DocTestFailure): - lines += checker.output_difference( - example, failure.got, report_choice - ).split("\n") - else: - inner_excinfo = ExceptionInfo.from_exc_info(failure.exc_info) - lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)] - lines += [ - x.strip("\n") for x in traceback.format_exception(*failure.exc_info) - ] - reprlocation_lines.append((reprlocation, lines)) - return ReprFailDoctest(reprlocation_lines) - - def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]: - assert self.dtest is not None - return self.path, self.dtest.lineno, "[ipdoctest] %s" % self.name - - if int(pytest.__version__.split(".")[0]) < 7: - - @property - def path(self) -> Path: - return Path(self.fspath) - - -def _get_flag_lookup() -> Dict[str, int]: - import doctest - - return dict( - DONT_ACCEPT_TRUE_FOR_1=doctest.DONT_ACCEPT_TRUE_FOR_1, - DONT_ACCEPT_BLANKLINE=doctest.DONT_ACCEPT_BLANKLINE, - NORMALIZE_WHITESPACE=doctest.NORMALIZE_WHITESPACE, - ELLIPSIS=doctest.ELLIPSIS, - IGNORE_EXCEPTION_DETAIL=doctest.IGNORE_EXCEPTION_DETAIL, - COMPARISON_FLAGS=doctest.COMPARISON_FLAGS, - ALLOW_UNICODE=_get_allow_unicode_flag(), - ALLOW_BYTES=_get_allow_bytes_flag(), - NUMBER=_get_number_flag(), - ) - - -def get_optionflags(parent): - optionflags_str = parent.config.getini("ipdoctest_optionflags") - flag_lookup_table = _get_flag_lookup() - flag_acc = 0 - for flag in optionflags_str: - flag_acc |= flag_lookup_table[flag] - return flag_acc - - -def _get_continue_on_failure(config): - continue_on_failure = config.getvalue("ipdoctest_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. - if config.getvalue("usepdb"): - continue_on_failure = False - return continue_on_failure - - -class IPDoctestTextfile(pytest.Module): - obj = None - - def collect(self) -> Iterable[IPDoctestItem]: - import doctest - from .ipdoctest import IPDocTestParser - - # Inspired by doctest.testfile; ideally we would use it directly, - # but it doesn't support passing a custom checker. - encoding = self.config.getini("ipdoctest_encoding") - text = self.path.read_text(encoding) - filename = str(self.path) - name = self.path.name - globs = {"__name__": "__main__"} - - optionflags = get_optionflags(self) - - runner = _get_runner( - verbose=False, - optionflags=optionflags, - checker=_get_checker(), - continue_on_failure=_get_continue_on_failure(self.config), - ) - - parser = IPDocTestParser() - test = parser.get_doctest(text, globs, name, filename, 0) - if test.examples: - yield IPDoctestItem.from_parent( - self, name=test.name, runner=runner, dtest=test - ) - - if int(pytest.__version__.split(".")[0]) < 7: - - @property - def path(self) -> Path: - return Path(self.fspath) - - @classmethod - def from_parent( - cls, - parent, - *, - fspath=None, - path: Optional[Path] = None, - **kw, - ): - if path is not None: - import py.path - - fspath = py.path.local(path) - return super().from_parent(parent=parent, fspath=fspath, **kw) - - -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) - if all_skipped: - pytest.skip("all docstests 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 - - -class IPDoctestModule(pytest.Module): - def collect(self) -> Iterable[IPDoctestItem]: - import doctest - from .ipdoctest import DocTestFinder, IPDocTestParser - - class MockAwareDocTestFinder(DocTestFinder): - """A hackish ipdoctest 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 - - Wrapped Doctests will need to be unwrapped so the correct - line number is returned. This will be reported upstream. #8796 - """ - if isinstance(obj, property): - obj = getattr(obj, "fget", obj) - - if hasattr(obj, "__wrapped__"): - # Get the main obj in case of it being wrapped - obj = inspect.unwrap(obj) - - # Type ignored because this is a private function. - return super()._find_lineno( # type:ignore[misc] - 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. - super()._find( # type:ignore[misc] - tests, obj, name, module, source_lines, globs, seen - ) - - if self.path.name == "conftest.py": - if int(pytest.__version__.split(".")[0]) < 7: - module = self.config.pluginmanager._importconftest( - self.path, - self.config.getoption("importmode"), - ) - else: - module = self.config.pluginmanager._importconftest( - self.path, - self.config.getoption("importmode"), - rootpath=self.config.rootpath, - ) - else: - try: - module = import_path(self.path, root=self.config.rootpath) - except ImportError: - if self.config.getvalue("ipdoctest_ignore_import_errors"): - pytest.skip("unable to import module %r" % self.path) - else: - raise - # Uses internal doctest module parsing mechanism. - finder = MockAwareDocTestFinder(parser=IPDocTestParser()) - optionflags = get_optionflags(self) - runner = _get_runner( - verbose=False, - optionflags=optionflags, - checker=_get_checker(), - continue_on_failure=_get_continue_on_failure(self.config), - ) - - for test in finder.find(module, module.__name__): - if test.examples: # skip empty ipdoctests - yield IPDoctestItem.from_parent( - self, name=test.name, runner=runner, dtest=test - ) - - if int(pytest.__version__.split(".")[0]) < 7: - - @property - def path(self) -> Path: - return Path(self.fspath) - - @classmethod - def from_parent( - cls, - parent, - *, - fspath=None, - path: Optional[Path] = None, - **kw, - ): - if path is not None: - import py.path - - fspath = py.path.local(path) - return super().from_parent(parent=parent, fspath=fspath, **kw) - - -def _setup_fixtures(doctest_item: IPDoctestItem) -> FixtureRequest: - """Used by IPDoctestTextfile and IPDoctestItem to setup fixture information.""" - - def func() -> None: - pass - - doctest_item.funcargs = {} # type: ignore[attr-defined] - fm = doctest_item.session._fixturemanager - 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._fillfixtures() - return fixture_request - - -def _init_checker_class() -> Type["IPDoctestOutputChecker"]: - import doctest - import re - from .ipdoctest import IPDoctestOutputChecker - - class LiteralsOutputChecker(IPDoctestOutputChecker): - # 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 super().check_output(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: - 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 super().check_output(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") - precision = 0 if fraction is None else 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() -> "IPDoctestOutputChecker": - """Return a IPDoctestOutputChecker 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 - ipdoctest should run in Python 2 and Python 3. - - * NUMBER to ignore floating-point differences smaller than the - precision of the literal number in the ipdoctest. - - An inner class is used to avoid importing "ipdoctest" 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.""" - 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 `ipdoctest` module flag value. - - We want to do it as late as possible to avoid importing `ipdoctest` and all - its dependencies when parsing options, as it adds overhead and breaks tests. - """ - import doctest - - return { - DOCTEST_REPORT_CHOICE_UDIFF: doctest.REPORT_UDIFF, - DOCTEST_REPORT_CHOICE_CDIFF: doctest.REPORT_CDIFF, - DOCTEST_REPORT_CHOICE_NDIFF: doctest.REPORT_NDIFF, - DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE: doctest.REPORT_ONLY_FIRST_FAILURE, - DOCTEST_REPORT_CHOICE_NONE: 0, - }[key] - - -@pytest.fixture(scope="session") -def ipdoctest_namespace() -> Dict[str, Any]: - """Fixture that returns a :py:class:`dict` that will be injected into the - namespace of ipdoctests.""" - return dict() |