Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-pytest-sphinx for 
openSUSE:Factory checked in at 2023-05-10 16:18:54
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pytest-sphinx (Old)
 and      /work/SRC/openSUSE:Factory/.python-pytest-sphinx.new.1533 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pytest-sphinx"

Wed May 10 16:18:54 2023 rev:6 rq:1085834 version:0.5.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-pytest-sphinx/python-pytest-sphinx.changes    
    2022-04-25 23:35:10.878387369 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-pytest-sphinx.new.1533/python-pytest-sphinx.changes
      2023-05-10 16:18:55.623117586 +0200
@@ -1,0 +2,8 @@
+Mon May  8 08:26:45 UTC 2023 - Dirk Müller <[email protected]>
+
+- update to 0.5.0:
+  * Mention in the README that the doctest directive is
+    supported.
+  * CI improvements
+
+-------------------------------------------------------------------

Old:
----
  pytest-sphinx-0.4.0.tar.gz

New:
----
  pytest-sphinx-0.5.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-pytest-sphinx.spec ++++++
--- /var/tmp/diff_new_pack.EMpAtM/_old  2023-05-10 16:18:56.063120189 +0200
+++ /var/tmp/diff_new_pack.EMpAtM/_new  2023-05-10 16:18:56.067120213 +0200
@@ -1,7 +1,7 @@
 #
 # spec file for package python-pytest-sphinx
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,13 +19,15 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-pytest-sphinx
-Version:        0.4.0
+Version:        0.5.0
 Release:        0
 Summary:        Doctest plugin for pytest with support for Sphinx-specific 
doctest-directives
 License:        BSD-3-Clause
 URL:            https://github.com/thisch/pytest-sphinx
 Source:         
https://github.com/thisch/pytest-sphinx/archive/v%{version}.tar.gz#/pytest-sphinx-%{version}.tar.gz
+BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module setuptools}
+BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 Requires:       python-pytest >= 7.0.0
@@ -43,10 +45,10 @@
 %setup -q -n pytest-sphinx-%{version}
 
 %build
-%python_build
+%pyproject_wheel
 
 %install
-%python_install
+%pyproject_install
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 
 %check
@@ -55,6 +57,8 @@
 %files %{python_files}
 %doc README.rst
 %license LICENSE
-%{python_sitelib}/*
+%{python_sitelib}/pytest_sphinx.py
+%{python_sitelib}/pytest_sphinx-%{version}.dist-info
+%pycache_only %{python_sitelib}/__pycache__/*
 
 %changelog

++++++ pytest-sphinx-0.4.0.tar.gz -> pytest-sphinx-0.5.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pytest-sphinx-0.4.0/.github/workflows/pypi-upload.yml 
new/pytest-sphinx-0.5.0/.github/workflows/pypi-upload.yml
--- old/pytest-sphinx-0.4.0/.github/workflows/pypi-upload.yml   2022-03-30 
22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/.github/workflows/pypi-upload.yml   2022-09-06 
22:46:09.000000000 +0200
@@ -13,7 +13,10 @@
       - uses: actions/checkout@v3
 
       - name: Set up Python
-        uses: actions/setup-python@v3
+        uses: actions/setup-python@v4
+        with:
+          cache: 'pip'
+          cache-dependency-path: 'pyproject.toml'
 
       - name: Install latest pip, build, twine
         run: |
@@ -26,4 +29,4 @@
         env:
           TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
         run: |
-          twine upload --verbose -u '__token__' dist/*
\ No newline at end of file
+          twine upload --verbose -u '__token__' dist/*
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/.github/workflows/test.yml 
new/pytest-sphinx-0.5.0/.github/workflows/test.yml
--- old/pytest-sphinx-0.4.0/.github/workflows/test.yml  2022-03-30 
22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/.github/workflows/test.yml  2022-09-06 
22:46:09.000000000 +0200
@@ -22,22 +22,34 @@
     strategy:
       fail-fast: false
       matrix:
-        python-version: ["3.7", "3.8", "3.9", "3.10"]
+        python-version: ["3.7", "3.8", "3.9", "3.10", "3.11-dev"]
         os: [ubuntu-latest, macOS-latest, windows-latest]
 
     steps:
       - uses: actions/checkout@v3
 
       - name: Set up Python ${{ matrix.python-version }}
-        uses: actions/setup-python@v3
+        uses: actions/setup-python@v4
         with:
           python-version: ${{ matrix.python-version }}
+          cache: 'pip'
+          cache-dependency-path: 'pyproject.toml'
 
       - name: Install dependencies
         run: |
+          python -m pip install -e .[lint]
           python -m pip install --upgrade pip
           python -m pip install --upgrade tox
 
+      - name: Lint (flake8)
+        run: flake8
+
+      - name: Lint (black)
+        run: black --check .
+
+      - name: Lint (isort)
+        run: isort --check .
+
       - name: Unit tests
         run: |
           tox -e ci-py -- -v --color=yes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/.gitignore 
new/pytest-sphinx-0.5.0/.gitignore
--- old/pytest-sphinx-0.4.0/.gitignore  2022-03-30 22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/.gitignore  2022-09-06 22:46:09.000000000 +0200
@@ -9,6 +9,7 @@
 # Distribution / packaging
 .Python
 env/
+.*env*
 build/
 develop-eggs/
 dist/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/.isort.cfg 
new/pytest-sphinx-0.5.0/.isort.cfg
--- old/pytest-sphinx-0.4.0/.isort.cfg  1970-01-01 01:00:00.000000000 +0100
+++ new/pytest-sphinx-0.5.0/.isort.cfg  2022-09-06 22:46:09.000000000 +0200
@@ -0,0 +1,6 @@
+[settings]
+line_length=90
+default_section=THIRDPARTY
+no_lines_before=LOCALFOLDER
+force_single_line=True
+sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/.pre-commit-config.yaml 
new/pytest-sphinx-0.5.0/.pre-commit-config.yaml
--- old/pytest-sphinx-0.4.0/.pre-commit-config.yaml     1970-01-01 
01:00:00.000000000 +0100
+++ new/pytest-sphinx-0.5.0/.pre-commit-config.yaml     2022-09-06 
22:46:09.000000000 +0200
@@ -0,0 +1,16 @@
+# See https://pre-commit.com for more information
+# See https://pre-commit.com/hooks.html for more hooks
+repos:
+  - repo: https://github.com/psf/black
+    rev: 22.3.0
+    hooks:
+      - id: black
+  # nice but doesn't support sphinx syntax - see 
https://github.com/Lucas-C/pre-commit-hooks-markup/issues/13
+  # - repo: https://github.com/Lucas-C/pre-commit-hooks-markup
+  #   rev: v1.0.1
+  #   hooks:
+  #     - id: rst-linter
+  - repo: https://github.com/pycqa/isort
+    rev: 5.10.1
+    hooks:
+      - id: isort
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/CHANGELOG.md 
new/pytest-sphinx-0.5.0/CHANGELOG.md
--- old/pytest-sphinx-0.4.0/CHANGELOG.md        2022-03-30 22:29:23.000000000 
+0200
+++ new/pytest-sphinx-0.5.0/CHANGELOG.md        2022-09-06 22:46:09.000000000 
+0200
@@ -7,6 +7,16 @@
 ## [Unreleased]
 ###
 
+## [0.5.0] - 2022-09-06
+###
+ - Mention in the README that the doctest directive is supported.
+ - internal: Improve CI setup, from [Tony
+   Narlock](https://www.git-pull.com).
+ - internal: Switch to a src/ structure, from [Tony
+   Narlock](https://www.git-pull.com).
+ - internal: Switch from setup.py to a PEP-621 pyproject.toml, from
+   [Tony Narlock](https://www.git-pull.com).
+
 ## [0.4.0] - 2022-03-30
 ###
  - Drop python2.7 (Fixes #14)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/MANIFEST.in 
new/pytest-sphinx-0.5.0/MANIFEST.in
--- old/pytest-sphinx-0.4.0/MANIFEST.in 2022-03-30 22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/MANIFEST.in 1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-include LICENSE
-include README.rst
-
-recursive-exclude * __pycache__
-recursive-exclude * *.py[co]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/README.rst 
new/pytest-sphinx-0.5.0/README.rst
--- old/pytest-sphinx-0.4.0/README.rst  2022-03-30 22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/README.rst  2022-09-06 22:46:09.000000000 +0200
@@ -14,6 +14,7 @@
 Features
 --------
 
+* support for the ``doctest`` directive
 * support for ``testcode`` and ``testoutput`` directives
 * support for ``testsetup`` and ``testcleanup`` is planned (pull-requests 
welcome)
 * support for parsing global optionflags (``doctest_optionflags``) from
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/pyproject.toml 
new/pytest-sphinx-0.5.0/pyproject.toml
--- old/pytest-sphinx-0.4.0/pyproject.toml      1970-01-01 01:00:00.000000000 
+0100
+++ new/pytest-sphinx-0.5.0/pyproject.toml      2022-09-06 22:46:09.000000000 
+0200
@@ -0,0 +1,55 @@
+[project]
+name = "pytest-sphinx"
+version = "0.5.0"
+description = "Doctest plugin for pytest with support for Sphinx-specific 
doctest-directives"
+readme = "README.rst"
+requires-python = ">=3.7"
+license = { file = "LICENSE" }
+keywords = ["sphinx", "pytest", "rst"]
+authors = [
+    { name="Thomas Hisch", email="[email protected]" }
+]
+maintainers = [
+    { name="Thomas Hisch", email="[email protected]" }
+]
+
+classifiers = [
+    "Development Status :: 4 - Beta",
+    "Framework :: Pytest",
+    "Intended Audience :: Developers",
+    "Topic :: Software Development :: Testing",
+    "Programming Language :: Python",
+    "Programming Language :: Python :: 3",
+    "Programming Language :: Python :: 3.7",
+    "Programming Language :: Python :: 3.8",
+    "Programming Language :: Python :: 3.9",
+    "Programming Language :: Python :: 3.10",
+    "Programming Language :: Python :: Implementation :: CPython",
+    "Operating System :: OS Independent",
+    "License :: OSI Approved :: BSD License",
+]
+
+# Requirements
+dependencies = [
+    "pytest >=7.0.0",
+]
+
+[project.optional-dependencies]
+lint = [
+    "isort >= 5",
+    "flake8",
+    "black"
+]
+
+[project.urls]
+homepage = "https://github.com/thisch/pytest-sphinx";
+
+[project.entry-points."pytest11"]
+"sphinx" = "pytest_sphinx"
+
+[tool.isort]
+profile = "black"
+
+[build-system]
+requires = ["setuptools"]
+build-backend = "setuptools.build_meta"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/pytest_sphinx.py 
new/pytest-sphinx-0.5.0/pytest_sphinx.py
--- old/pytest-sphinx-0.4.0/pytest_sphinx.py    2022-03-30 22:29:23.000000000 
+0200
+++ new/pytest-sphinx-0.5.0/pytest_sphinx.py    1970-01-01 01:00:00.000000000 
+0100
@@ -1,535 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-http://www.sphinx-doc.org/en/stable/ext/doctest.html
-https://github.com/sphinx-doc/sphinx/blob/master/sphinx/ext/doctest.py
-
-* TODO
-** CLEANUP: use the sphinx directive parser from the sphinx project
-"""
-
-import doctest
-import enum
-from pathlib import Path
-import re
-import sys
-import textwrap
-import traceback
-
-import _pytest.doctest
-import pytest
-from _pytest.doctest import _is_mocked
-from _pytest.doctest import _patch_unwrap_mock_aware
-from _pytest.doctest import DoctestItem
-from _pytest.pathlib import import_path
-
-
-class SphinxDoctestDirectives(enum.Enum):
-    TESTCODE = 1
-    TESTOUTPUT = 2
-    TESTSETUP = 3
-    TESTCLEANUP = 4
-    DOCTEST = 5
-
-
-_DIRECTIVES_W_OPTIONS = (
-    SphinxDoctestDirectives.TESTOUTPUT,
-    SphinxDoctestDirectives.DOCTEST,
-)
-_DIRECTIVES_W_SKIPIF = (
-    SphinxDoctestDirectives.TESTCODE,
-    SphinxDoctestDirectives.TESTOUTPUT,
-    SphinxDoctestDirectives.TESTSETUP,
-    SphinxDoctestDirectives.TESTCLEANUP,
-    SphinxDoctestDirectives.DOCTEST,
-)
-
-
-def pytest_collect_file(path, parent):
-    config = parent.config
-    if path.ext == ".py":
-        if config.option.doctestmodules:
-            return SphinxDoctestModule.from_parent(parent, 
path=Path(path.strpath))
-    elif _is_doctest(config, path, parent):
-        return SphinxDoctestTextfile.from_parent(parent, 
path=Path(path.strpath))
-
-
-def _is_doctest(config, path, parent):
-    if path.ext in (".txt", ".rst") and parent.session.isinitpath(path):
-        return True
-    globs = config.getoption("doctestglob") or ["test*.txt"]
-    for glob in globs:
-        if path.check(fnmatch=glob):
-            return True
-    return False
-
-
-# This regular expression looks for option directives in the expected output
-# (testoutput) code of an example.  Option directives are comments starting
-# with ":options:".
-_OPTION_DIRECTIVE_RE = re.compile(r':options:\s*([^\n\'"]*)$')
-_OPTION_SKIPIF_RE = re.compile(r':skipif:\s*([^\n\'"]*)$')
-
-_DIRECTIVE_RE = re.compile(
-    r"\s*\.\. ("
-    r"testcode|testoutput|testsetup|testcleanup|doctest"
-    r')::\s*([^\n\'"]*)$'
-)
-
-
-def _split_into_body_and_options(section_content):
-    """Parse the the full content of a directive and split it.
-
-    It is split into a string, where the options (:options:, :hide: and
-    :skipif:) are removed, and into options.
-
-    If there are options in `section_content`, they have to appear at the
-    very beginning. The first line that is not an option (:options:, :hide:
-    and :skipif:) and not a newline is the first line of the string that is
-    returned (`remaining`).
-
-    Parameters
-    ----------
-    section_content : str
-        String consisting of optional options (:skipif:, :hide:
-        or :options:), and of a body.
-
-    Returns
-    -------
-    body : str
-    skipif_expr : str or None
-    flag_settings : dict
-
-    Raises
-    ------
-    ValueError
-        * If options and the body of the section are not
-        separated by a newline.
-        * If the body of the section is empty.
-
-    """
-    lines = section_content.strip().splitlines()
-
-    skipif_expr = None
-    flag_settings = {}
-    i = 0
-    for line in lines:
-        stripped = line.strip()
-        if _OPTION_SKIPIF_RE.match(stripped):
-            skipif_expr = _OPTION_SKIPIF_RE.match(stripped).group(1)
-            i += 1
-        elif _OPTION_DIRECTIVE_RE.match(stripped):
-            option_strings = (
-                _OPTION_DIRECTIVE_RE.match(stripped).group(1).replace(",", " 
").split()
-            )
-            for option in option_strings:
-                if (
-                    option[0] not in "+-"
-                    or option[1:] not in doctest.OPTIONFLAGS_BY_NAME
-                ):
-                    raise ValueError(
-                        "doctest " "has an invalid option {}".format(option)
-                    )
-                flag = doctest.OPTIONFLAGS_BY_NAME[option[1:]]
-                flag_settings[flag] = option[0] == "+"
-            i += 1
-        elif stripped == ":hide:":
-            i += 1
-        else:
-            break
-
-    if i == len(lines):
-        raise ValueError("no code/output")
-
-    body = "\n".join(lines[i:]).lstrip()
-    if not body:
-        raise ValueError("no code/output")
-
-    if i and lines[i].strip():
-        # no newline between option block and body
-        raise ValueError("invalid option block: {!r}".format(section_content))
-
-    return body, skipif_expr, flag_settings
-
-
-def _get_next_textoutputsections(sections, index):
-    """Yield successive TESTOUTPUT sections."""
-    for j in range(index, len(sections)):
-        section = sections[j]
-        if section.directive == SphinxDoctestDirectives.TESTOUTPUT:
-            yield section
-        else:
-            break
-
-
-class Section(object):
-    def __init__(self, directive, content, lineno, groups=None):
-        super(Section, self).__init__()
-        self.directive = directive
-        self.groups = groups
-        self.lineno = lineno
-        body, skipif_expr, options = _split_into_body_and_options(content)
-
-        if skipif_expr and self.directive not in _DIRECTIVES_W_SKIPIF:
-            raise ValueError(":skipif: not allowed in 
{}".format(self.directive))
-        if options and self.directive not in _DIRECTIVES_W_OPTIONS:
-            raise ValueError(":options: not allowed in 
{}".format(self.directive))
-        self.body = body
-        self.skipif_expr = skipif_expr
-        self.options = options
-
-
-def get_sections(docstring):
-    lines = textwrap.dedent(docstring).splitlines()
-    sections = []
-
-    def _get_indentation(line):
-        return len(line) - len(line.lstrip())
-
-    def add_match(directive, i, j, groups):
-        sections.append(
-            Section(
-                directive,
-                textwrap.dedent("\n".join(lines[i + 1 : j])),
-                lineno=j - 1,
-                groups=groups,
-            )
-        )
-
-    i = 0
-    while True:
-        try:
-            line = lines[i]
-        except IndexError:
-            break
-
-        match = _DIRECTIVE_RE.match(line)
-        if match:
-            directive = getattr(SphinxDoctestDirectives, 
match.group(1).upper())
-            groups = [x.strip() for x in (match.group(2) or 
"default").split(",")]
-            indentation = _get_indentation(line)
-            # find the end of the block
-            j = i
-            while True:
-                j += 1
-                try:
-                    block_line = lines[j]
-                except IndexError:
-                    add_match(directive, i, j, groups)
-                    break
-                if block_line.lstrip() and _get_indentation(block_line) <= 
indentation:
-                    add_match(directive, i, j, groups)
-                    i = j - 1
-                    break
-        i += 1
-    return sections
-
-
-def docstring2examples(docstring, globs=None):
-    """
-    Parse all sphinx test directives in the docstring and create a
-    list of examples.
-    """
-    # TODO subclass doctest.DocTestParser instead?
-
-    if not globs:
-        globs = {}
-
-    sections = get_sections(docstring)
-
-    def get_testoutput_section_data(section):
-        want = section.body
-        exc_msg = None
-        options = {}
-
-        if section.skipif_expr and eval(section.skipif_expr, globs):
-            want = ""
-        else:
-            options = section.options
-            match = doctest.DocTestParser._EXCEPTION_RE.match(want)
-            if match:
-                exc_msg = match.group("msg")
-
-        return want, options, section.lineno, exc_msg
-
-    examples = []
-    for i, current_section in enumerate(sections):
-        # TODO support SphinxDoctestDirectives.TESTSETUP, ...
-        if current_section.directive == SphinxDoctestDirectives.TESTCODE:
-            next_testoutput_sections = _get_next_textoutputsections(sections, 
i + 1)
-            section_data_seq = [
-                get_testoutput_section_data(s) for s in 
next_testoutput_sections
-            ]
-
-            num_unskipped_sections = len([d for d in section_data_seq if d[0]])
-            if num_unskipped_sections > 1:
-                raise ValueError("There are multiple unskipped TESTOUTPUT 
sections")
-
-            if num_unskipped_sections:
-                want, options, _, exc_msg = next(d for d in section_data_seq 
if d[0])
-            else:
-                # no unskipped testoutput section
-                # do we really need doctest.Example to test
-                # independent TESTCODE sections?
-                want, options, exc_msg = "", {}, None
-
-            if current_section.skipif_expr and 
eval(current_section.skipif_expr, globs):
-                # TODO add the doctest.Example to `examples` but mark it as
-                # skipped.
-                continue
-
-            examples.append(
-                doctest.Example(
-                    source=current_section.body,
-                    want=want,
-                    exc_msg=exc_msg,
-                    # we want to see the ..testcode lines in the
-                    # console output but not the ..testoutput
-                    # lines
-                    # TODO why do we want to hide testoutput??
-                    lineno=current_section.lineno,
-                    options=options,
-                )
-            )
-    return examples
-
-
-class SphinxDocTestRunner(doctest.DebugRunner):
-    """
-    overwrite doctest.DocTestRunner.__run, since it uses 'single' for the
-    `compile` function instead of 'exec'.
-    """
-
-    def _DocTestRunner__run(self, test, compileflags, out):
-        """
-        Run the examples in `test`.
-
-        Write the outcome of each example with one of the
-        `DocTestRunner.report_*` methods, using the writer function
-        `out`.  `compileflags` is the set of compiler flags that should
-        be used to execute examples.  Return a tuple `(f, t)`, where `t`
-        is the number of examples tried, and `f` is the number of
-        examples that failed.  The examples are run in the namespace
-        `test.globs`.
-
-        """
-        # Keep track of the number of failures and tries.
-        failures = tries = 0
-
-        # Save the option flags (since option directives can be used
-        # to modify them).
-        original_optionflags = self.optionflags
-
-        SUCCESS, FAILURE, BOOM = range(3)  # `outcome` state
-
-        check = self._checker.check_output
-
-        # Process each example.
-        for examplenum, example in enumerate(test.examples):
-
-            # If REPORT_ONLY_FIRST_FAILURE is set, then suppress
-            # reporting after the first failure.
-            quiet = (
-                self.optionflags & doctest.REPORT_ONLY_FIRST_FAILURE and 
failures > 0
-            )
-
-            # Merge in the example's options.
-            self.optionflags = original_optionflags
-            if example.options:
-                for (optionflag, val) in example.options.items():
-                    if val:
-                        self.optionflags |= optionflag
-                    else:
-                        self.optionflags &= ~optionflag
-
-            # If 'SKIP' is set, then skip this example.
-            if self.optionflags & doctest.SKIP:
-                continue
-
-            # Record that we started this example.
-            tries += 1
-            if not quiet:
-                self.report_start(out, test, example)
-
-            # Use a special filename for compile(), so we can retrieve
-            # the source code during interactive debugging (see
-            # __patched_linecache_getlines).
-            filename = "<doctest %s[%d]>" % (test.name, examplenum)
-
-            # Run the example in the given context (globs), and record
-            # any exception that gets raised.  (But don't intercept
-            # keyboard interrupts.)
-            try:
-                # Don't blink!  This is where the user's code gets run.
-                exec(
-                    compile(example.source, filename, "exec", compileflags, 1),
-                    test.globs,
-                )
-                self.debugger.set_continue()  # ==== Example Finished ====
-                exception = None
-            except KeyboardInterrupt:
-                raise
-            except Exception:
-                exception = sys.exc_info()
-                self.debugger.set_continue()  # ==== Example Finished ====
-
-            got = self._fakeout.getvalue()  # the actual output
-            self._fakeout.truncate(0)
-            outcome = FAILURE  # guilty until proved innocent or insane
-
-            # If the example executed without raising any exceptions,
-            # verify its output.
-            if exception is None:
-                if check(example.want, got, self.optionflags):
-                    outcome = SUCCESS
-
-            # The example raised an exception:  check if it was expected.
-            else:
-                exc_msg = traceback.format_exception_only(*exception[:2])[-1]
-                if not quiet:
-                    got += doctest._exception_traceback(exception)
-
-                # If `example.exc_msg` is None, then we weren't expecting
-                # an exception.
-                if example.exc_msg is None:
-                    outcome = BOOM
-
-                # We expected an exception:  see whether it matches.
-                elif check(example.exc_msg, exc_msg, self.optionflags):
-                    outcome = SUCCESS
-
-                # Another chance if they didn't care about the detail.
-                elif self.optionflags & doctest.IGNORE_EXCEPTION_DETAIL:
-                    if check(
-                        doctest._strip_exception_details(example.exc_msg),
-                        doctest._strip_exception_details(exc_msg),
-                        self.optionflags,
-                    ):
-                        outcome = SUCCESS
-
-            # Report the outcome.
-            if outcome is SUCCESS:
-                if not quiet:
-                    self.report_success(out, test, example, got)
-            elif outcome is FAILURE:
-                if not quiet:
-                    self.report_failure(out, test, example, got)
-                failures += 1
-            elif outcome is BOOM:
-                if not quiet:
-                    self.report_unexpected_exception(out, test, example, 
exception)
-                failures += 1
-            else:
-                assert False, ("unknown outcome", outcome)
-
-            if failures and self.optionflags & doctest.FAIL_FAST:
-                break
-
-        # Restore the option flags (in case they were modified)
-        self.optionflags = original_optionflags
-
-        # Record and return the number of failures and tries.
-        self._DocTestRunner__record_outcome(test, failures, tries)
-        return doctest.TestResults(failures, tries)
-
-
-class SphinxDocTestParser(object):
-    def get_doctest(self, docstring, globs, name, filename, lineno):
-        # TODO document why we need to overwrite? get_doctest
-        return doctest.DocTest(
-            examples=docstring2examples(docstring, globs=globs),
-            globs=globs,
-            name=name,
-            filename=filename,
-            lineno=lineno,
-            docstring=docstring,
-        )
-
-
-class SphinxDoctestTextfile(pytest.Module):
-    obj = None
-
-    def collect(self):
-        # 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)
-        name = self.fspath.basename
-
-        optionflags = _pytest.doctest.get_optionflags(self)
-        runner = SphinxDocTestRunner(
-            verbose=0,
-            optionflags=optionflags,
-            checker=_pytest.doctest._get_checker(),
-        )
-
-        test = doctest.DocTest(
-            examples=docstring2examples(text),
-            globs={},
-            name=name,
-            filename=name,
-            lineno=0,
-            docstring=text,
-        )
-
-        if test.examples:
-            yield DoctestItem.from_parent(
-                parent=self, name=test.name, runner=runner, dtest=test
-            )
-
-
-class SphinxDoctestModule(pytest.Module):
-    def collect(self):
-        if self.fspath.basename == "conftest.py":
-            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("doctest_ignore_import_errors"):
-                    pytest.skip("unable to import module %r" % self.path)
-                else:
-                    raise
-        optionflags = _pytest.doctest.get_optionflags(self)
-
-        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
-
-            fix taken from https://github.com/pytest-dev/pytest/pull/4212/
-            """
-
-            def _find(self, tests, obj, name, module, source_lines, globs, 
seen):
-                if _is_mocked(obj):
-                    return
-                with _patch_unwrap_mock_aware():
-                    doctest.DocTestFinder._find(
-                        self,
-                        tests,
-                        obj,
-                        name,
-                        module,
-                        source_lines,
-                        globs,
-                        seen,
-                    )
-
-        finder = MockAwareDocTestFinder(parser=SphinxDocTestParser())
-
-        runner = SphinxDocTestRunner(
-            verbose=0,
-            optionflags=optionflags,
-            checker=_pytest.doctest._get_checker(),
-        )
-
-        for test in finder.find(module, module.__name__):
-            if test.examples:
-                yield DoctestItem.from_parent(
-                    parent=self, name=test.name, runner=runner, dtest=test
-                )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/setup.cfg 
new/pytest-sphinx-0.5.0/setup.cfg
--- old/pytest-sphinx-0.4.0/setup.cfg   1970-01-01 01:00:00.000000000 +0100
+++ new/pytest-sphinx-0.5.0/setup.cfg   2022-09-06 22:46:09.000000000 +0200
@@ -0,0 +1,4 @@
+[flake8]
+exclude = .*/,.tox,*.egg
+max-line-length = 88
+extend-ignore = E203
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/setup.py 
new/pytest-sphinx-0.5.0/setup.py
--- old/pytest-sphinx-0.4.0/setup.py    2022-03-30 22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/setup.py    1970-01-01 01:00:00.000000000 +0100
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-import codecs
-import os
-
-from setuptools import setup
-
-
-def read(fname):
-    file_path = os.path.join(os.path.dirname(__file__), fname)
-    return codecs.open(file_path, encoding="utf-8").read()
-
-
-setup(
-    name="pytest-sphinx",
-    version="0.4.0",
-    author="Thomas Hisch",
-    author_email="[email protected]",
-    maintainer="Thomas Hisch",
-    maintainer_email="[email protected]",
-    license="BSD-3",
-    url="https://github.com/thisch/pytest-sphinx";,
-    description=(
-        "Doctest plugin for pytest with support for "
-        "Sphinx-specific doctest-directives"
-    ),
-    long_description=read("README.rst"),
-    py_modules=["pytest_sphinx"],
-    install_requires=["pytest>=7.0.0"],
-    classifiers=[
-        "Development Status :: 4 - Beta",
-        "Framework :: Pytest",
-        "Intended Audience :: Developers",
-        "Topic :: Software Development :: Testing",
-        "Programming Language :: Python",
-        "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.7",
-        "Programming Language :: Python :: 3.8",
-        "Programming Language :: Python :: 3.9",
-        "Programming Language :: Python :: 3.10",
-        "Programming Language :: Python :: Implementation :: CPython",
-        "Operating System :: OS Independent",
-        "License :: OSI Approved :: BSD License",
-    ],
-    entry_points={"pytest11": ["sphinx = pytest_sphinx"]},
-)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/src/pytest_sphinx.py 
new/pytest-sphinx-0.5.0/src/pytest_sphinx.py
--- old/pytest-sphinx-0.4.0/src/pytest_sphinx.py        1970-01-01 
01:00:00.000000000 +0100
+++ new/pytest-sphinx-0.5.0/src/pytest_sphinx.py        2022-09-06 
22:46:09.000000000 +0200
@@ -0,0 +1,541 @@
+"""
+http://www.sphinx-doc.org/en/stable/ext/doctest.html
+https://github.com/sphinx-doc/sphinx/blob/master/sphinx/ext/doctest.py
+
+* TODO
+** CLEANUP: use the sphinx directive parser from the sphinx project
+"""
+
+import doctest
+import enum
+import re
+import sys
+import textwrap
+import traceback
+from pathlib import Path
+
+import _pytest.doctest
+import pytest
+from _pytest.doctest import DoctestItem
+from _pytest.doctest import _is_mocked
+from _pytest.doctest import _patch_unwrap_mock_aware
+from _pytest.pathlib import import_path
+
+
+class SphinxDoctestDirectives(enum.Enum):
+    TESTCODE = 1
+    TESTOUTPUT = 2
+    TESTSETUP = 3
+    TESTCLEANUP = 4
+    DOCTEST = 5
+
+
+_DIRECTIVES_W_OPTIONS = (
+    SphinxDoctestDirectives.TESTOUTPUT,
+    SphinxDoctestDirectives.DOCTEST,
+)
+_DIRECTIVES_W_SKIPIF = (
+    SphinxDoctestDirectives.TESTCODE,
+    SphinxDoctestDirectives.TESTOUTPUT,
+    SphinxDoctestDirectives.TESTSETUP,
+    SphinxDoctestDirectives.TESTCLEANUP,
+    SphinxDoctestDirectives.DOCTEST,
+)
+
+
+def pytest_collect_file(path, parent):
+    config = parent.config
+    if path.ext == ".py":
+        if config.option.doctestmodules:
+            return SphinxDoctestModule.from_parent(parent, 
path=Path(path.strpath))
+    elif _is_doctest(config, path, parent):
+        return SphinxDoctestTextfile.from_parent(parent, 
path=Path(path.strpath))
+
+
+def _is_doctest(config, path, parent):
+    if path.ext in (".txt", ".rst") and parent.session.isinitpath(path):
+        return True
+    globs = config.getoption("doctestglob") or ["test*.txt"]
+    for glob in globs:
+        if path.check(fnmatch=glob):
+            return True
+    return False
+
+
+# This regular expression looks for option directives in the expected output
+# (testoutput) code of an example.  Option directives are comments starting
+# with ":options:".
+_OPTION_DIRECTIVE_RE = re.compile(r':options:\s*([^\n\'"]*)$')
+_OPTION_SKIPIF_RE = re.compile(r':skipif:\s*([^\n\'"]*)$')
+
+_DIRECTIVE_RE = re.compile(
+    r"""
+    \s*\.\.\s
+    (?P<directive>(testcode|testoutput|testsetup|testcleanup|doctest))
+    ::\s*
+    (?P<argument>([^\n'"]*))
+    $
+    """,
+    re.VERBOSE,
+)
+
+
+def _split_into_body_and_options(section_content):
+    """Parse the the full content of a directive and split it.
+
+    It is split into a string, where the options (:options:, :hide: and
+    :skipif:) are removed, and into options.
+
+    If there are options in `section_content`, they have to appear at the
+    very beginning. The first line that is not an option (:options:, :hide:
+    and :skipif:) and not a newline is the first line of the string that is
+    returned (`remaining`).
+
+    Parameters
+    ----------
+    section_content : str
+        String consisting of optional options (:skipif:, :hide:
+        or :options:), and of a body.
+
+    Returns
+    -------
+    body : str
+    skipif_expr : str or None
+    flag_settings : dict
+
+    Raises
+    ------
+    ValueError
+        * If options and the body of the section are not
+        separated by a newline.
+        * If the body of the section is empty.
+
+    """
+    lines = section_content.strip().splitlines()
+
+    skipif_expr = None
+    flag_settings = {}
+    i = 0
+    for line in lines:
+        stripped = line.strip()
+        if _OPTION_SKIPIF_RE.match(stripped):
+            skipif_expr = _OPTION_SKIPIF_RE.match(stripped).group(1)
+            i += 1
+        elif _OPTION_DIRECTIVE_RE.match(stripped):
+            option_strings = (
+                _OPTION_DIRECTIVE_RE.match(stripped).group(1).replace(",", " 
").split()
+            )
+            for option in option_strings:
+                if (
+                    option[0] not in "+-"
+                    or option[1:] not in doctest.OPTIONFLAGS_BY_NAME
+                ):
+                    raise ValueError(f"doctest has an invalid option {option}")
+                flag = doctest.OPTIONFLAGS_BY_NAME[option[1:]]
+                flag_settings[flag] = option[0] == "+"
+            i += 1
+        elif stripped == ":hide:":
+            i += 1
+        else:
+            break
+
+    if i == len(lines):
+        raise ValueError("no code/output")
+
+    body = "\n".join(lines[i:]).lstrip()
+    if not body:
+        raise ValueError("no code/output")
+
+    if i and lines[i].strip():
+        # no newline between option block and body
+        raise ValueError(f"invalid option block: {section_content!r}")
+
+    return body, skipif_expr, flag_settings
+
+
+def _get_next_textoutputsections(sections, index):
+    """Yield successive TESTOUTPUT sections."""
+    for j in range(index, len(sections)):
+        section = sections[j]
+        if section.directive == SphinxDoctestDirectives.TESTOUTPUT:
+            yield section
+        else:
+            break
+
+
+class Section:
+    def __init__(self, directive, content, lineno, groups=None):
+        super().__init__()
+        self.directive = directive
+        self.groups = groups
+        self.lineno = lineno
+        body, skipif_expr, options = _split_into_body_and_options(content)
+
+        if skipif_expr and self.directive not in _DIRECTIVES_W_SKIPIF:
+            raise ValueError(f":skipif: not allowed in {self.directive}")
+        if options and self.directive not in _DIRECTIVES_W_OPTIONS:
+            raise ValueError(f":options: not allowed in {self.directive}")
+        self.body = body
+        self.skipif_expr = skipif_expr
+        self.options = options
+
+
+def get_sections(docstring):
+    lines = textwrap.dedent(docstring).splitlines()
+    sections = []
+
+    def _get_indentation(line):
+        return len(line) - len(line.lstrip())
+
+    def add_match(directive, i, j, groups):
+        sections.append(
+            Section(
+                directive,
+                textwrap.dedent("\n".join(lines[i + 1 : j])),
+                lineno=j - 1,
+                groups=groups,
+            )
+        )
+
+    i = 0
+    while True:
+        try:
+            line = lines[i]
+        except IndexError:
+            break
+
+        match = _DIRECTIVE_RE.match(line)
+        if match:
+            group = match.groupdict()
+            directive = getattr(SphinxDoctestDirectives, 
group["directive"].upper())
+            groups = [x.strip() for x in (group["argument"] or 
"default").split(",")]
+            indentation = _get_indentation(line)
+            # find the end of the block
+            j = i
+            while True:
+                j += 1
+                try:
+                    block_line = lines[j]
+                except IndexError:
+                    add_match(directive, i, j, groups)
+                    break
+                if block_line.lstrip() and _get_indentation(block_line) <= 
indentation:
+                    add_match(directive, i, j, groups)
+                    i = j - 1
+                    break
+        i += 1
+    return sections
+
+
+def docstring2examples(docstring, globs=None):
+    """
+    Parse all sphinx test directives in the docstring and create a
+    list of examples.
+    """
+    # TODO subclass doctest.DocTestParser instead?
+
+    if not globs:
+        globs = {}
+
+    sections = get_sections(docstring)
+
+    def get_testoutput_section_data(section):
+        want = section.body
+        exc_msg = None
+        options = {}
+
+        if section.skipif_expr and eval(section.skipif_expr, globs):
+            want = ""
+        else:
+            options = section.options
+            match = doctest.DocTestParser._EXCEPTION_RE.match(want)
+            if match:
+                exc_msg = match.group("msg")
+
+        return want, options, section.lineno, exc_msg
+
+    examples = []
+    for i, current_section in enumerate(sections):
+        # TODO support SphinxDoctestDirectives.TESTSETUP, ...
+        if current_section.directive == SphinxDoctestDirectives.TESTCODE:
+            next_testoutput_sections = _get_next_textoutputsections(sections, 
i + 1)
+            section_data_seq = [
+                get_testoutput_section_data(s) for s in 
next_testoutput_sections
+            ]
+
+            num_unskipped_sections = len([d for d in section_data_seq if d[0]])
+            if num_unskipped_sections > 1:
+                raise ValueError("There are multiple unskipped TESTOUTPUT 
sections")
+
+            if num_unskipped_sections:
+                want, options, _, exc_msg = next(d for d in section_data_seq 
if d[0])
+            else:
+                # no unskipped testoutput section
+                # do we really need doctest.Example to test
+                # independent TESTCODE sections?
+                want, options, exc_msg = "", {}, None
+
+            if current_section.skipif_expr and 
eval(current_section.skipif_expr, globs):
+                # TODO add the doctest.Example to `examples` but mark it as
+                # skipped.
+                continue
+
+            examples.append(
+                doctest.Example(
+                    source=current_section.body,
+                    want=want,
+                    exc_msg=exc_msg,
+                    # we want to see the ..testcode lines in the
+                    # console output but not the ..testoutput
+                    # lines
+                    # TODO why do we want to hide testoutput??
+                    lineno=current_section.lineno,
+                    options=options,
+                )
+            )
+    return examples
+
+
+class SphinxDocTestRunner(doctest.DebugRunner):
+    """
+    overwrite doctest.DocTestRunner.__run, since it uses 'single' for the
+    `compile` function instead of 'exec'.
+    """
+
+    def _DocTestRunner__run(self, test, compileflags, out):
+        """
+        Run the examples in `test`.
+
+        Write the outcome of each example with one of the
+        `DocTestRunner.report_*` methods, using the writer function
+        `out`.  `compileflags` is the set of compiler flags that should
+        be used to execute examples.  Return a tuple `(f, t)`, where `t`
+        is the number of examples tried, and `f` is the number of
+        examples that failed.  The examples are run in the namespace
+        `test.globs`.
+
+        """
+        # Keep track of the number of failures and tries.
+        failures = tries = 0
+
+        # Save the option flags (since option directives can be used
+        # to modify them).
+        original_optionflags = self.optionflags
+
+        SUCCESS, FAILURE, BOOM = range(3)  # `outcome` state
+
+        check = self._checker.check_output
+
+        # Process each example.
+        for examplenum, example in enumerate(test.examples):
+
+            # If REPORT_ONLY_FIRST_FAILURE is set, then suppress
+            # reporting after the first failure.
+            quiet = (
+                self.optionflags & doctest.REPORT_ONLY_FIRST_FAILURE and 
failures > 0
+            )
+
+            # Merge in the example's options.
+            self.optionflags = original_optionflags
+            if example.options:
+                for (optionflag, val) in example.options.items():
+                    if val:
+                        self.optionflags |= optionflag
+                    else:
+                        self.optionflags &= ~optionflag
+
+            # If 'SKIP' is set, then skip this example.
+            if self.optionflags & doctest.SKIP:
+                continue
+
+            # Record that we started this example.
+            tries += 1
+            if not quiet:
+                self.report_start(out, test, example)
+
+            # Use a special filename for compile(), so we can retrieve
+            # the source code during interactive debugging (see
+            # __patched_linecache_getlines).
+            filename = "<doctest %s[%d]>" % (test.name, examplenum)
+
+            # Run the example in the given context (globs), and record
+            # any exception that gets raised.  (But don't intercept
+            # keyboard interrupts.)
+            try:
+                # Don't blink!  This is where the user's code gets run.
+                exec(
+                    compile(example.source, filename, "exec", compileflags, 1),
+                    test.globs,
+                )
+                self.debugger.set_continue()  # ==== Example Finished ====
+                exception = None
+            except KeyboardInterrupt:
+                raise
+            except Exception:
+                exception = sys.exc_info()
+                self.debugger.set_continue()  # ==== Example Finished ====
+
+            got = self._fakeout.getvalue()  # the actual output
+            self._fakeout.truncate(0)
+            outcome = FAILURE  # guilty until proved innocent or insane
+
+            # If the example executed without raising any exceptions,
+            # verify its output.
+            if exception is None:
+                if check(example.want, got, self.optionflags):
+                    outcome = SUCCESS
+
+            # The example raised an exception:  check if it was expected.
+            else:
+                exc_msg = traceback.format_exception_only(*exception[:2])[-1]
+                if not quiet:
+                    got += doctest._exception_traceback(exception)
+
+                # If `example.exc_msg` is None, then we weren't expecting
+                # an exception.
+                if example.exc_msg is None:
+                    outcome = BOOM
+
+                # We expected an exception:  see whether it matches.
+                elif check(example.exc_msg, exc_msg, self.optionflags):
+                    outcome = SUCCESS
+
+                # Another chance if they didn't care about the detail.
+                elif self.optionflags & doctest.IGNORE_EXCEPTION_DETAIL:
+                    if check(
+                        doctest._strip_exception_details(example.exc_msg),
+                        doctest._strip_exception_details(exc_msg),
+                        self.optionflags,
+                    ):
+                        outcome = SUCCESS
+
+            # Report the outcome.
+            if outcome is SUCCESS:
+                if not quiet:
+                    self.report_success(out, test, example, got)
+            elif outcome is FAILURE:
+                if not quiet:
+                    self.report_failure(out, test, example, got)
+                failures += 1
+            elif outcome is BOOM:
+                if not quiet:
+                    self.report_unexpected_exception(out, test, example, 
exception)
+                failures += 1
+            else:
+                assert False, ("unknown outcome", outcome)
+
+            if failures and self.optionflags & doctest.FAIL_FAST:
+                break
+
+        # Restore the option flags (in case they were modified)
+        self.optionflags = original_optionflags
+
+        # Record and return the number of failures and tries.
+        self._DocTestRunner__record_outcome(test, failures, tries)
+        return doctest.TestResults(failures, tries)
+
+
+class SphinxDocTestParser:
+    def get_doctest(self, docstring, globs, name, filename, lineno):
+        # TODO document why we need to overwrite? get_doctest
+        return doctest.DocTest(
+            examples=docstring2examples(docstring, globs=globs),
+            globs=globs,
+            name=name,
+            filename=filename,
+            lineno=lineno,
+            docstring=docstring,
+        )
+
+
+class SphinxDoctestTextfile(pytest.Module):
+    obj = None
+
+    def collect(self):
+        # 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)
+        name = self.fspath.basename
+
+        optionflags = _pytest.doctest.get_optionflags(self)
+        runner = SphinxDocTestRunner(
+            verbose=0,
+            optionflags=optionflags,
+            checker=_pytest.doctest._get_checker(),
+        )
+
+        test = doctest.DocTest(
+            examples=docstring2examples(text),
+            globs={},
+            name=name,
+            filename=name,
+            lineno=0,
+            docstring=text,
+        )
+
+        if test.examples:
+            yield DoctestItem.from_parent(
+                parent=self, name=test.name, runner=runner, dtest=test
+            )
+
+
+class SphinxDoctestModule(pytest.Module):
+    def collect(self):
+        if self.fspath.basename == "conftest.py":
+            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("doctest_ignore_import_errors"):
+                    pytest.skip("unable to import module %r" % self.path)
+                else:
+                    raise
+        optionflags = _pytest.doctest.get_optionflags(self)
+
+        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
+
+            fix taken from https://github.com/pytest-dev/pytest/pull/4212/
+            """
+
+            def _find(self, tests, obj, name, module, source_lines, globs, 
seen):
+                if _is_mocked(obj):
+                    return
+                with _patch_unwrap_mock_aware():
+                    doctest.DocTestFinder._find(
+                        self,
+                        tests,
+                        obj,
+                        name,
+                        module,
+                        source_lines,
+                        globs,
+                        seen,
+                    )
+
+        if sys.version_info < (3, 10):
+            finder = MockAwareDocTestFinder(parser=SphinxDocTestParser())
+        else:
+            finder = doctest.DocTestFinder(parser=SphinxDocTestParser())
+
+        runner = SphinxDocTestRunner(
+            verbose=0,
+            optionflags=optionflags,
+            checker=_pytest.doctest._get_checker(),
+        )
+
+        for test in finder.find(module, module.__name__):
+            if test.examples:
+                yield DoctestItem.from_parent(
+                    parent=self, name=test.name, runner=runner, dtest=test
+                )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/tests/test_doc2test.py 
new/pytest-sphinx-0.5.0/tests/test_doc2test.py
--- old/pytest-sphinx-0.4.0/tests/test_doc2test.py      2022-03-30 
22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/tests/test_doc2test.py      2022-09-06 
22:46:09.000000000 +0200
@@ -91,7 +91,7 @@
     rstpath = os.path.join(
         os.path.dirname(__file__), "testdata", "using_the_shapereader.rst"
     )
-    with open(rstpath, "r") as fh:
+    with open(rstpath) as fh:
         sections = get_sections(fh.read())
 
     assert len(sections) == 9
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/tests/test_options.py 
new/pytest-sphinx-0.5.0/tests/test_options.py
--- old/pytest-sphinx-0.4.0/tests/test_options.py       2022-03-30 
22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/tests/test_options.py       2022-09-06 
22:46:09.000000000 +0200
@@ -2,6 +2,7 @@
 import textwrap
 
 import pytest
+
 from pytest_sphinx import _split_into_body_and_options
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/tests/test_python_files.py 
new/pytest-sphinx-0.5.0/tests/test_python_files.py
--- old/pytest-sphinx-0.4.0/tests/test_python_files.py  2022-03-30 
22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/tests/test_python_files.py  2022-09-06 
22:46:09.000000000 +0200
@@ -1,4 +1,3 @@
-# -*- coding: utf-8 -*-
 import textwrap
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/tests/test_sphinx_doctest.py 
new/pytest-sphinx-0.5.0/tests/test_sphinx_doctest.py
--- old/pytest-sphinx-0.4.0/tests/test_sphinx_doctest.py        2022-03-30 
22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/tests/test_sphinx_doctest.py        2022-09-06 
22:46:09.000000000 +0200
@@ -83,7 +83,7 @@
     """
     )
 
-    assert expected in output, "{!r}\n\n{!r}".format(expected, output)
+    assert expected in output, f"{expected!r}\n\n{output!r}"
 
 
 def test_simple_doctest_success(sphinx_tester):
@@ -111,6 +111,49 @@
             """
 
         sphinx_output = sphinx_tester(code)
+        assert "1 items passed all tests" in sphinx_output
+
+        plugin_result = testdir.runpytest("--doctest-glob=index.rst").stdout
+        plugin_result.fnmatch_lines(["*=== 1 passed in *"])
+
+    def test_doctest(self, testdir, sphinx_tester):
+        code = """
+            .. doctest::
+
+               >>> print("msg from testcode directive")
+               msg from testcode directive
+            """
+
+        sphinx_output = sphinx_tester(code)
+        assert "1 items passed all tests" in sphinx_output
+
+        plugin_result = testdir.runpytest("--doctest-glob=index.rst").stdout
+        plugin_result.fnmatch_lines(["*=== 1 passed in *"])
+
+    def test_doctest_multiple(self, testdir, sphinx_tester):
+        code = """
+            .. doctest::
+
+                >>> import operator
+
+                >>> operator.lt(1, 3)
+                True
+
+                >>> operator.lt(6, 2)
+                False
+
+            .. doctest::
+
+                >>> four = 2 + 2
+
+                >>> four
+                4
+
+                >>> print(f'Two plus two: {four}')
+                Two plus two: 4
+            """
+
+        sphinx_output = sphinx_tester(code)
         assert "1 items passed all tests" in sphinx_output
 
         plugin_result = testdir.runpytest("--doctest-glob=index.rst").stdout
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/tests/test_text_files.py 
new/pytest-sphinx-0.5.0/tests/test_text_files.py
--- old/pytest-sphinx-0.4.0/tests/test_text_files.py    2022-03-30 
22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/tests/test_text_files.py    2022-09-06 
22:46:09.000000000 +0200
@@ -1,4 +1,5 @@
 import _pytest.doctest
+
 import pytest_sphinx
 
 
@@ -199,3 +200,36 @@
 
     result = testdir.runpytest()
     result.stdout.fnmatch_lines(["*=== 1 passed in *"])
+
+
+def test_doctest_directive(testdir):
+    testdir.maketxtfile(
+        test_something=r"""
+        This is a paragraph. This is the
+        next sentence.
+
+        .. doctest::
+
+           >>> assert False
+           Traceback (most recent call last):
+           ...
+           AssertionError
+    """
+    )
+
+    result = testdir.runpytest()
+    result.stdout.fnmatch_lines(["*=== 1 passed in *"])
+
+    testdir.maketxtfile(
+        test_something=r"""
+        This is a paragraph. This is the
+        next sentence.
+
+        .. doctest::
+
+           >>> assert False
+    """
+    )
+
+    result = testdir.runpytest()
+    result.stdout.fnmatch_lines(["*=== 1 failed in *"])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-sphinx-0.4.0/tox.ini 
new/pytest-sphinx-0.5.0/tox.ini
--- old/pytest-sphinx-0.4.0/tox.ini     2022-03-30 22:29:23.000000000 +0200
+++ new/pytest-sphinx-0.5.0/tox.ini     2022-09-06 22:46:09.000000000 +0200
@@ -1,6 +1,7 @@
 # For more information about tox, see https://tox.readthedocs.io/en/latest/
 [tox]
-envlist = py37,py38,py39,py310,ci-py
+envlist = py37,py38,py39,py310,py311,ci-py
+isolated_build = true
 
 [testenv]
 deps =

Reply via email to