Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-pytest-doctestplus for 
openSUSE:Factory checked in at 2024-01-03 12:27:11
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-pytest-doctestplus (Old)
 and      /work/SRC/openSUSE:Factory/.python-pytest-doctestplus.new.28375 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-pytest-doctestplus"

Wed Jan  3 12:27:11 2024 rev:17 rq:1135878 version:1.1.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-pytest-doctestplus/python-pytest-doctestplus.changes
      2023-10-05 20:03:54.408346718 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-pytest-doctestplus.new.28375/python-pytest-doctestplus.changes
   2024-01-03 12:27:13.636384893 +0100
@@ -1,0 +2,11 @@
+Sun Dec 31 13:32:06 UTC 2023 - Dirk Müller <dmuel...@suse.com>
+
+- update to 1.1.0:
+  * Added --doctest-plus-generate-diff to update documentation
+    based on actual output.
+  * Fix module level __doctest_requires__.
+  * Versions of Python <3.8 are no longer supported.
+  * Fix erroneous attempt to import __main__.py by skipping it.
+  * Respect pytest --import-mode.
+
+-------------------------------------------------------------------

Old:
----
  pytest-doctestplus-1.0.0.tar.gz

New:
----
  pytest-doctestplus-1.1.0.tar.gz

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

Other differences:
------------------
++++++ python-pytest-doctestplus.spec ++++++
--- /var/tmp/diff_new_pack.j9b8JH/_old  2024-01-03 12:27:14.164404175 +0100
+++ /var/tmp/diff_new_pack.j9b8JH/_new  2024-01-03 12:27:14.164404175 +0100
@@ -27,16 +27,16 @@
 
 %{?sle15_python_module_pythons}
 Name:           python-pytest-doctestplus%{psuffix}
-Version:        1.0.0
+Version:        1.1.0
 Release:        0
 Summary:        Pytest plugin with advanced doctest features
 License:        BSD-3-Clause
 URL:            https://github.com/scientific-python/pytest-doctestplus
 Source:         
https://files.pythonhosted.org/packages/source/p/pytest-doctestplus/pytest-doctestplus-%{version}.tar.gz
-BuildRequires:  %{python_module base >= 3.7}
-BuildRequires:  %{python_module packaging >= 17.0}
+BuildRequires:  %{python_module base >= 3.8}
+BuildRequires:  %{python_module pip}
 BuildRequires:  %{python_module setuptools_scm}
-BuildRequires:  %{python_module setuptools}
+BuildRequires:  %{python_module wheel}
 BuildRequires:  fdupes
 BuildRequires:  python-rpm-macros
 Requires:       python-packaging >= 17.0
@@ -49,6 +49,7 @@
 BuildRequires:  %{python_module pip >= 19.3.1}
 BuildRequires:  %{python_module pytest-doctestplus = %{version}}
 BuildRequires:  %{python_module pytest-remotedata >= 0.3.2}
+BuildRequires:  git-core
 %else
 BuildArch:      noarch
 %endif
@@ -63,11 +64,11 @@
 %setup -q -n pytest-doctestplus-%{version}
 
 %build
-%python_build
+%pyproject_wheel
 
 %install
 %if !%{with test}
-%python_install
+%pyproject_install
 %python_expand %fdupes %{buildroot}%{$python_sitelib}
 %endif
 
@@ -75,7 +76,7 @@
 %check
 export LANG=en_US.UTF8
 export PY_IGNORE_IMPORTMISMATCH=1
-%pytest tests/ --doctest-plus --doctest-rst -k "not test_remote_data_url"
+%pytest tests/ --doctest-plus --doctest-rst -k "not test_remote_data_url and 
not test_import_mode"
 %endif
 
 %if !%{with test}
@@ -83,6 +84,6 @@
 %doc CHANGES.rst README.rst
 %license LICENSE.rst
 %{python_sitelib}/pytest_doctestplus
-%{python_sitelib}/pytest_doctestplus-%{version}*-info
+%{python_sitelib}/pytest_doctestplus-%{version}.dist-info
 %endif
 

++++++ pytest-doctestplus-1.0.0.tar.gz -> pytest-doctestplus-1.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pytest-doctestplus-1.0.0/.github/workflows/publish.yml 
new/pytest-doctestplus-1.1.0/.github/workflows/publish.yml
--- old/pytest-doctestplus-1.0.0/.github/workflows/publish.yml  2023-08-11 
18:21:57.000000000 +0200
+++ new/pytest-doctestplus-1.1.0/.github/workflows/publish.yml  2023-12-13 
19:12:44.000000000 +0100
@@ -13,7 +13,7 @@
     if: ((github.event_name == 'push' && startsWith(github.ref, 'refs/tags')) 
|| contains(github.event.pull_request.labels.*.name, 'Build wheels'))
 
     steps:
-    - uses: actions/checkout@v3
+    - uses: actions/checkout@v4
       with:
         fetch-depth: 0
     - uses: actions/setup-python@v4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pytest-doctestplus-1.0.0/.github/workflows/python-tests.yml 
new/pytest-doctestplus-1.1.0/.github/workflows/python-tests.yml
--- old/pytest-doctestplus-1.0.0/.github/workflows/python-tests.yml     
2023-08-11 18:21:57.000000000 +0200
+++ new/pytest-doctestplus-1.1.0/.github/workflows/python-tests.yml     
2023-12-13 19:12:44.000000000 +0100
@@ -8,8 +8,8 @@
       - '*'
   workflow_dispatch:
   schedule:
-    # Run every Sunday at 03:53 UTC
-    - cron: 53 3 * * 0
+    # Run every Tuesday at 03:53 UTC
+    - cron: 53 3 * * 2
 
 jobs:
   tests:
@@ -19,17 +19,17 @@
       matrix:
         include:
           - os: ubuntu-latest
-            python-version: 3.7
-            toxenv: py37-test-pytest46
+            python-version: 3.8
+            toxenv: py38-test-pytestoldest
           - os: windows-latest
-            python-version: 3.7
-            toxenv: py37-test-pytest50
+            python-version: 3.8
+            toxenv: py38-test-pytest50
           - os: macos-latest
-            python-version: 3.7
-            toxenv: py37-test-pytest51
+            python-version: 3.8
+            toxenv: py38-test-pytest51
           - os: ubuntu-latest
-            python-version: 3.7
-            toxenv: py37-test-pytest52
+            python-version: 3.8
+            toxenv: py38-test-pytest52
           - os: windows-latest
             python-version: 3.8
             toxenv: py38-test-pytest53
@@ -65,11 +65,11 @@
             python-version: '3.11'
             toxenv: py311-test-pytestdev
           - os: ubuntu-latest
-            python-version: '3.12-dev'
+            python-version: '3.12'
             toxenv: py312-test-pytestdev
 
     steps:
-    - uses: actions/checkout@v3
+    - uses: actions/checkout@v4
       with:
         fetch-depth: 0
     - name: Set up Python ${{ matrix.python-version }}
@@ -80,11 +80,3 @@
       run: python -m pip install tox
     - name: Run Tox
       run: tox ${{ matrix.toxargs }} -v -e ${{ matrix.toxenv }}
-
-    # - name: Slack Notification
-    #   uses: 8398a7/action-slack@v3
-    #   with:
-    #     status: ${{ job.status }}
-    #   env:
-    #     SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
-    #   if: always() # TODO: cron
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-doctestplus-1.0.0/.mailmap 
new/pytest-doctestplus-1.1.0/.mailmap
--- old/pytest-doctestplus-1.0.0/.mailmap       2023-08-11 18:21:57.000000000 
+0200
+++ new/pytest-doctestplus-1.1.0/.mailmap       2023-12-13 19:12:44.000000000 
+0100
@@ -12,7 +12,9 @@
 Matteo Bachetti         <mat...@matteobachetti.it> 
<matteo.bache...@irap.omp.eu>
 Michael Seifert        <michaelseifer...@yahoo.de>
 Pey Lian Lim           <l...@stsci.edu> 
<2090236+pl...@users.noreply.github.com>
+Philipp A.             <flying-sh...@web.de>
 Pratik Patel           <pratikpatel15...@gmail.com>
+Sebastian Berg         <sebasti...@nvidia.com> <sebast...@sipsolutions.net>
 Simon Conseil          <cont...@saimon.org> <s.cons...@ip2i.in2p3.fr>
 Simon Conseil          <cont...@saimon.org> <scons...@gemini.edu>
 Tinuade Adeleke        <summittinu...@gmail.com>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-doctestplus-1.0.0/CHANGES.rst 
new/pytest-doctestplus-1.1.0/CHANGES.rst
--- old/pytest-doctestplus-1.0.0/CHANGES.rst    2023-08-11 18:21:57.000000000 
+0200
+++ new/pytest-doctestplus-1.1.0/CHANGES.rst    2023-12-13 19:12:44.000000000 
+0100
@@ -1,3 +1,18 @@
+1.1.0 (2023-12-13)
+==================
+
+- Added ``--doctest-plus-generate-diff`` to update documentation based on
+  actual output. [#227]
+
+- Fix module level ``__doctest_requires__``. [#228]
+
+- Versions of Python <3.8 are no longer supported. [#217]
+
+- Fix erroneous attempt to import ``__main__.py`` by skipping it. [#232]
+
+- Respect pytest ``--import-mode``. [#233]
+
+
 1.0.0 (2023-08-11)
 ==================
 
@@ -69,7 +84,7 @@
 0.9.0 (2021-01-14)
 ==================
 
-- Declare ``setuptools`` runtime dependency [#93]
+- Declare ``setuptools`` runtime dependency. [#132]
 
 - Add ``SHOW_WARNINGS`` flag to show warnings. [#136]
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-doctestplus-1.0.0/PKG-INFO 
new/pytest-doctestplus-1.1.0/PKG-INFO
--- old/pytest-doctestplus-1.0.0/PKG-INFO       2023-08-11 18:22:14.703384200 
+0200
+++ new/pytest-doctestplus-1.1.0/PKG-INFO       2023-12-13 19:12:59.113894500 
+0100
@@ -1,12 +1,12 @@
 Metadata-Version: 2.1
 Name: pytest-doctestplus
-Version: 1.0.0
+Version: 1.1.0
 Summary: Pytest plugin with advanced doctest features.
 Home-page: https://github.com/scientific-python/pytest-doctestplus
 Author: Scientific Python Developers
 License: BSD
 Keywords: doctest,rst,pytest,py.test
-Classifier: Development Status :: 3 - Alpha
+Classifier: Development Status :: 5 - Production/Stable
 Classifier: Framework :: Pytest
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: BSD License
@@ -14,7 +14,6 @@
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
@@ -23,10 +22,16 @@
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Topic :: Software Development :: Testing
 Classifier: Topic :: Utilities
-Requires-Python: >=3.7
+Requires-Python: >=3.8
 Description-Content-Type: text/x-rst
-Provides-Extra: test
 License-File: LICENSE.rst
+Requires-Dist: pytest>=4.6
+Requires-Dist: setuptools>=30.3.0
+Requires-Dist: packaging>=17.0
+Provides-Extra: test
+Requires-Dist: numpy; extra == "test"
+Requires-Dist: pytest-remotedata>=0.3.2; extra == "test"
+Requires-Dist: sphinx; extra == "test"
 
 ==================
 pytest-doctestplus
@@ -71,6 +76,10 @@
 * optional inclusion of ``*.rst`` files for doctests (see `Setup and 
Configuration`_)
 * optional inclusion of doctests in docstrings of Numpy ufuncs
 
+Further, ``pytest-doctestplus`` supports editing files to fix incorrect 
docstrings
+(See `Fixing Existing Docstrings`_).
+
+.. _pytest-remotedata: https://github.com/astropy/pytest-remotedata
 
 Installation
 ------------
@@ -132,6 +141,23 @@
 doctest settings, see the `doctest documentation
 <https://docs.python.org/3/library/doctest.html#option-flags>`_.
 
+Running Tests in Markdown Files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To run doctests in Markdown files, invoke pytest with the command line options
+``--doctest-plus --doctest-glob '*.md'``.
+
+If you write doctests inside `GitHub-style triple backtick fenced code blocks
+<https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#fenced-code-blocks>`_,
+then in order for pytest-doctest to find and run them you need to include an
+extra trailing newline inside your code blocks, like this::
+
+    ```pycon
+    >>> 1 + 2
+    2
+
+    ```
+
 Doctest Directives
 ~~~~~~~~~~~~~~~~~~
 
@@ -387,6 +413,54 @@
 ``conf.py`` file.
 
 
+Fixing Existing Docstrings
+--------------------------
+The plugin has basic support to fix docstrings, this can be enabled by
+running ``pytest`` with ``--doctest-plus-generate-diff``.
+Without further options, this will print out a diff and a list of files that
+would be modified.  Using ``--doctest-plus-generate-diff=overwrite`` will
+modify the files in-place, so it is recommended to run the check first to
+verify the paths.
+You may wish to review changes manually and only commit some patches e.g. 
using ``git commit --patch``.
+
+The current diff generation is still very basic, for example, it does not 
account for
+existing ``...``.  By default a diff is only generated for *failing* doctests.
+
+In general, a mass edit may wish to focus on a specific change and
+possibly include passing tests.  So you can opt-in into the behavior by
+adding a hook to your ``conftest.py``::
+
+    @pytest.hookimpl
+    def pytest_doctestplus_diffhook(info):
+        info["use"] = True  # Overwrite all results (even successes)
+        if info["fileno"] is None:
+            # E.g. NumPy has C docstrings that cannot be found, we can add
+            # custom logic here to try and find these:
+            info["filename"] = ...
+            info["lineno"] = ...
+
+Where ``info`` is a dictionary containing the following items:
+
+* ``use``: ``True`` or ``False`` signalling whether to apply the diff.  This is
+  set to ``False`` if a doctest succeeded and ``True`` if the doctest failed.
+* ``name``: The name of the test (e.g. the function being documented)
+* ``filename``: The file that contains the test (this can be wrong in certain
+  situation and in that case ``test_lineno`` will be wrong as well).
+* ``source``: The source code that was executed for this test
+* ``test_lineno``: The line of code where the example block (or function) 
starts.
+  In some cases, the test file cannot be found and the lineno will be ``None``,
+  you can manually try to fix these.
+* ``example_lineno``: The line number of the example snippet
+  (individual ``>>>``).
+* ``want``: The current documentation.
+* ``got``: The result of executing the example.
+
+You can modify the dictionary in-place to modify the behavior.
+
+Please note that we assume that this API will be used only occasionally and
+reserve the right to change it at any time.
+
+
 Development Status
 ------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-doctestplus-1.0.0/README.rst 
new/pytest-doctestplus-1.1.0/README.rst
--- old/pytest-doctestplus-1.0.0/README.rst     2023-08-11 18:21:57.000000000 
+0200
+++ new/pytest-doctestplus-1.1.0/README.rst     2023-12-13 19:12:44.000000000 
+0100
@@ -41,6 +41,10 @@
 * optional inclusion of ``*.rst`` files for doctests (see `Setup and 
Configuration`_)
 * optional inclusion of doctests in docstrings of Numpy ufuncs
 
+Further, ``pytest-doctestplus`` supports editing files to fix incorrect 
docstrings
+(See `Fixing Existing Docstrings`_).
+
+.. _pytest-remotedata: https://github.com/astropy/pytest-remotedata
 
 Installation
 ------------
@@ -102,6 +106,23 @@
 doctest settings, see the `doctest documentation
 <https://docs.python.org/3/library/doctest.html#option-flags>`_.
 
+Running Tests in Markdown Files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To run doctests in Markdown files, invoke pytest with the command line options
+``--doctest-plus --doctest-glob '*.md'``.
+
+If you write doctests inside `GitHub-style triple backtick fenced code blocks
+<https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#fenced-code-blocks>`_,
+then in order for pytest-doctest to find and run them you need to include an
+extra trailing newline inside your code blocks, like this::
+
+    ```pycon
+    >>> 1 + 2
+    2
+
+    ```
+
 Doctest Directives
 ~~~~~~~~~~~~~~~~~~
 
@@ -357,6 +378,54 @@
 ``conf.py`` file.
 
 
+Fixing Existing Docstrings
+--------------------------
+The plugin has basic support to fix docstrings, this can be enabled by
+running ``pytest`` with ``--doctest-plus-generate-diff``.
+Without further options, this will print out a diff and a list of files that
+would be modified.  Using ``--doctest-plus-generate-diff=overwrite`` will
+modify the files in-place, so it is recommended to run the check first to
+verify the paths.
+You may wish to review changes manually and only commit some patches e.g. 
using ``git commit --patch``.
+
+The current diff generation is still very basic, for example, it does not 
account for
+existing ``...``.  By default a diff is only generated for *failing* doctests.
+
+In general, a mass edit may wish to focus on a specific change and
+possibly include passing tests.  So you can opt-in into the behavior by
+adding a hook to your ``conftest.py``::
+
+    @pytest.hookimpl
+    def pytest_doctestplus_diffhook(info):
+        info["use"] = True  # Overwrite all results (even successes)
+        if info["fileno"] is None:
+            # E.g. NumPy has C docstrings that cannot be found, we can add
+            # custom logic here to try and find these:
+            info["filename"] = ...
+            info["lineno"] = ...
+
+Where ``info`` is a dictionary containing the following items:
+
+* ``use``: ``True`` or ``False`` signalling whether to apply the diff.  This is
+  set to ``False`` if a doctest succeeded and ``True`` if the doctest failed.
+* ``name``: The name of the test (e.g. the function being documented)
+* ``filename``: The file that contains the test (this can be wrong in certain
+  situation and in that case ``test_lineno`` will be wrong as well).
+* ``source``: The source code that was executed for this test
+* ``test_lineno``: The line of code where the example block (or function) 
starts.
+  In some cases, the test file cannot be found and the lineno will be ``None``,
+  you can manually try to fix these.
+* ``example_lineno``: The line number of the example snippet
+  (individual ``>>>``).
+* ``want``: The current documentation.
+* ``got``: The result of executing the example.
+
+You can modify the dictionary in-place to modify the behavior.
+
+Please note that we assume that this API will be used only occasionally and
+reserve the right to change it at any time.
+
+
 Development Status
 ------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pytest-doctestplus-1.0.0/pytest_doctestplus/newhooks.py 
new/pytest-doctestplus-1.1.0/pytest_doctestplus/newhooks.py
--- old/pytest-doctestplus-1.0.0/pytest_doctestplus/newhooks.py 1970-01-01 
01:00:00.000000000 +0100
+++ new/pytest-doctestplus-1.1.0/pytest_doctestplus/newhooks.py 2023-12-13 
19:12:44.000000000 +0100
@@ -0,0 +1,5 @@
+# Licensed under a 3-clause BSD style license - see LICENSE.rst
+
+
+def pytest_doctestplus_diffhook(info):
+    """ called when a diff would be generated normally. """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pytest-doctestplus-1.0.0/pytest_doctestplus/output_checker.py 
new/pytest-doctestplus-1.1.0/pytest_doctestplus/output_checker.py
--- old/pytest-doctestplus-1.0.0/pytest_doctestplus/output_checker.py   
2023-08-11 18:21:57.000000000 +0200
+++ new/pytest-doctestplus-1.1.0/pytest_doctestplus/output_checker.py   
2023-12-13 19:12:44.000000000 +0100
@@ -43,8 +43,6 @@
     rtol = 1e-05
     atol = 1e-08
 
-    _original_output_checker = doctest.OutputChecker
-
     _str_literal_re = re.compile(
         r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE)
     _byteorder_re = re.compile(
@@ -55,9 +53,6 @@
         r"([0-9]+)L", re.UNICODE)
 
     def __init__(self):
-        # NOTE OutputChecker is an old-style class with no __init__ method,
-        # so we can't call the base class version of __init__ here
-
         exp = r'(?:e[+-]?\d+)'
 
         got_floats = (r'\s*([+-]?\d+\.\d*{0}?|'
@@ -80,6 +75,10 @@
         fmidend = r'(?<={}){}(?={}|$)'.format(front_sep, want_floats, back_sep)
         self.num_want_rgx = re.compile(r'({}|{})'.format(fbeg, fmidend))
 
+        # As of 2023-09-26, Python base class has no init, but just in case
+        # it acquires one.
+        super().__init__()
+
     def do_fixes(self, want, got):
         want = re.sub(self._str_literal_re, r'\1\2', want)
         want = re.sub(self._byteorder_re, r'\1\2\3', want)
@@ -281,19 +280,13 @@
         if flags & FLOAT_CMP:
             return self.normalize_floats(want, got, flags)
 
-        # Can't use super here because doctest.OutputChecker is not a
-        # new-style class.
-        return self._original_output_checker.check_output(
-            self, want, got, flags)
+        return super().check_output(want, got, flags)
 
     def output_difference(self, want, got, flags):
         if flags & FIX:
             want, got = self.do_fixes(want, got)
 
-        # Can't use super here because doctest.OutputChecker is not a
-        # new-style class.
-        return self._original_output_checker.output_difference(
-            self, want, got, flags)
+        return super().output_difference(want, got, flags)
 
 
 try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pytest-doctestplus-1.0.0/pytest_doctestplus/plugin.py 
new/pytest-doctestplus-1.1.0/pytest_doctestplus/plugin.py
--- old/pytest-doctestplus-1.0.0/pytest_doctestplus/plugin.py   2023-08-11 
18:21:57.000000000 +0200
+++ new/pytest-doctestplus-1.1.0/pytest_doctestplus/plugin.py   2023-12-13 
19:12:44.000000000 +0100
@@ -1,4 +1,5 @@
 # Licensed under a 3-clause BSD style license - see LICENSE.rst
+
 """
 This plugin provides advanced doctest support and enables the testing of .rst
 files.
@@ -8,8 +9,11 @@
 import os
 import re
 import sys
+import tempfile
 import warnings
+from collections import defaultdict
 from pathlib import Path
+import subprocess
 from textwrap import indent
 from unittest import SkipTest
 
@@ -119,6 +123,20 @@
     parser.addoption("--doctest-only", action="store_true",
                      help="Test only doctests. Implies usage of doctest-plus.")
 
+    parser.addoption("--doctest-plus-generate-diff",
+                     help=(
+                         "Generate a diff where expected output and actual "
+                         "output differ.  "
+                         "The diff is printed to stdout if not using "
+                         "`--doctest-plus-generate-diff=overwrite` which "
+                         "causes editing of the original files.\n"
+                         "NOTE: Unless an in-pace build is picked up, python "
+                         "file paths may point to unexpected places. "
+                         "If 'overwrite' is not used, will create a temporary "
+                         "folder and use `git diff -p` to generate a diff."),
+                     choices=["diff", "overwrite"],
+                     action="store", nargs="?", default=False, const="diff")
+
     parser.addini("text_file_format",
                   "Default format for docs. "
                   "This is no longer recommended, use --doctest-glob instead.")
@@ -160,6 +178,11 @@
                   default=[])
 
 
+def pytest_addhooks(pluginmanager):
+    from pytest_doctestplus import newhooks
+    pluginmanager.add_hookspecs(newhooks)
+
+
 def get_optionflags(parent):
     optionflags_str = parent.config.getini('doctest_optionflags')
     flag_int = 0
@@ -185,6 +208,8 @@
 def pytest_configure(config):
     doctest_plugin = config.pluginmanager.getplugin('doctest')
     run_regular_doctest = config.option.doctestmodules and not 
config.option.doctest_plus
+    if config.option.doctest_plus_generate_diff:
+        config.option.doctest_only = True
     use_doctest_plus = config.getini(
         'doctest_plus') or config.option.doctest_plus or 
config.option.doctest_only
     use_doctest_ufunc = config.getini(
@@ -204,13 +229,17 @@
     use_rst = config.getini('doctest_rst') or config.option.doctest_rst
     file_ext = config.option.text_file_format or 
config.getini('text_file_format') or 'rst'
     if use_rst:
-        config.option.doctestglob.append('*.{}'.format(file_ext))
+        config.option.doctestglob.append(f'*.{file_ext}')
 
     # override default comment characters
     ext_comment_pairs = [pair.split('=') for pair in 
config.getini('text_file_comment_chars')]
     for ext, chars in ext_comment_pairs:
         comment_characters[ext] = chars
 
+    # Fetch the global hook function:
+    global doctestplus_diffhook
+    doctestplus_diffhook = config.hook.pytest_doctestplus_diffhook
+
     class DocTestModulePlus(doctest_plugin.DoctestModule):
         # pytest 2.4.0 defines "collect".  Prior to that, it defined
         # "runtest".  The "collect" approach is better, because we can
@@ -228,7 +257,7 @@
                 fspath = self.fspath
                 filepath = self.fspath.basename
 
-            if filepath == "setup.py":
+            if filepath in ("setup.py", "__main__.py"):
                 return
             elif filepath == "conftest.py":
                 if PYTEST_GE_7_0:
@@ -245,11 +274,12 @@
                 try:
                     if PYTEST_GT_5:
                         from _pytest.pathlib import import_path
+                        mode = self.config.getoption("importmode")
 
                     if PYTEST_GE_7_0:
-                        module = import_path(fspath, root=self.config.rootpath)
+                        module = import_path(fspath, mode=mode, 
root=self.config.rootpath)
                     elif PYTEST_GT_5:
-                        module = import_path(fspath)
+                        module = import_path(fspath, mode=mode)
                     else:
                         module = fspath.pyimport()
                 except ImportError:
@@ -268,6 +298,7 @@
                 checker=OutputChecker(),
                 # Helper disables continue-on-failure when debugging is enabled
                 continue_on_failure=_get_continue_on_failure(config),
+                generate_diff=config.option.doctest_plus_generate_diff,
             )
 
             for test in finder.find(module):
@@ -332,6 +363,7 @@
             runner = DebugRunnerPlus(
                 verbose=False, optionflags=optionflags, 
checker=OutputChecker(),
                 continue_on_failure=_get_continue_on_failure(self.config),
+                generate_diff=self.config.option.doctest_plus_generate_diff,
             )
 
             parser = DocTestParserPlus()
@@ -394,7 +426,7 @@
                     skip_next = False
                     lines = entry.strip().splitlines()
                     if any(re.match(
-                            '{} doctest-skip-all'.format(comment_char), 
x.strip()) for x in lines):
+                            f'{comment_char} doctest-skip-all', x.strip()) for 
x in lines):
                         skip_all = True
                         continue
 
@@ -405,7 +437,7 @@
                     # special environment to be in between, e.g. \begin{python}
                     last_lines = lines[-2:]
                     matches = [re.match(
-                        r'{}\s+doctest-skip\s*::(\s+.*)?'.format(comment_char),
+                        fr'{comment_char}\s+doctest-skip\s*::(\s+.*)?',
                         last_line) for last_line in last_lines]
 
                     if len(matches) > 1:
@@ -423,7 +455,7 @@
 
                     if config.getoption('remote_data', 'none') != 'any':
                         matches = (re.match(
-                            
r'{}\s+doctest-remote-data\s*::'.format(comment_char),
+                            fr'{comment_char}\s+doctest-remote-data\s*::',
                             last_line) for last_line in last_lines)
 
                         if any(matches):
@@ -431,7 +463,7 @@
                             continue
 
                     matches = [re.match(
-                        
r'{}\s+doctest-requires\s*::\s+(.*)'.format(comment_char),
+                        fr'{comment_char}\s+doctest-requires\s*::\s+(.*)',
                         last_line) for last_line in last_lines]
 
                     if len(matches) > 1:
@@ -487,7 +519,7 @@
     config.pluginmanager.unregister(doctest_plugin)
 
 
-class DoctestPlus(object):
+class DoctestPlus:
     def __init__(self, doctest_module_item_cls, doctest_textfile_item_cls, 
file_globs):
         """
         doctest_module_item_cls should be a class inheriting
@@ -673,6 +705,7 @@
             if mod in cls._import_cache:
                 if not cls._import_cache[mod]:
                     return False
+                continue
 
             if cls._module_checker.check(mod):
                 cls._import_cache[mod] = True
@@ -714,9 +747,17 @@
                 for pats, mods in reqs.items():
                     if not isinstance(pats, tuple):
                         pats = (pats,)
+
                     for pat in pats:
-                        if not fnmatch.fnmatch(test.name, '.'.join((name, 
pat))):
-                            continue
+                        if pat == '*':
+                            pass
+                        elif pat == '.' and test.name == name:
+                            pass
+                        elif fnmatch.fnmatch(test.name, '.'.join((name, pat))):
+                            pass
+                        else:
+                            continue  # The pattern does not apply
+
                         if not self.check_required_modules(mods):
                             return False
                 return True
@@ -726,12 +767,143 @@
         return tests
 
 
+def write_modified_file(fname, new_fname, changes):
+    # Sort in reversed order to edit the lines:
+    bad_tests = []
+    changes.sort(key=lambda x: (x["test_lineno"], x["example_lineno"]),
+                 reverse=True)
+
+    with open(fname, "r") as f:
+        text = f.readlines()
+
+    for change in changes:
+        if change["test_lineno"] is None:
+            bad_tests.append(change["name"])
+            continue
+        lineno = change["test_lineno"] + change["example_lineno"] + 1
+
+        indentation = " " * change["nindent"]
+        want = indent(change["want"], indentation, lambda x: True)
+        # Replace fully blank lines with the required `<BLANKLINE>`
+        # (May need to do this also if line contains only whitespace)
+        got = change["got"].replace("\n\n", "\n<BLANKLINE>\n")
+        got = indent(got, indentation, lambda x: True)
+
+        text[lineno:lineno+want.count("\n")] = [got]
+
+    with open(new_fname, "w") as f:
+        f.write("".join(text))
+
+    return bad_tests
+
+
+def pytest_terminal_summary(terminalreporter, exitstatus, config):
+    changesets = DebugRunnerPlus._changesets
+    diff_mode = DebugRunnerPlus._generate_diff
+    DebugRunnerPlus._changesets = defaultdict(lambda: [])
+    DebugRunnerPlus._generate_diff = None
+    all_bad_tests = []
+    if not diff_mode:
+        return  # we do not report or apply diffs
+
+    if diff_mode != "overwrite":
+        # In this mode, we write a corrected file to a temporary folder in
+        # order to compare them (rather than modifying the file).
+        terminalreporter.section("Reporting DoctestPlus Diffs")
+        if not changesets:
+            terminalreporter.write_line("No doc changes to show")
+            return
+
+        # Strip away the common part of the path to make it a bit clearner...
+        common_path = os.path.commonpath(changesets.keys())
+        if not os.path.isdir(common_path):
+            common_path = os.path.split(common_path)[0]
+
+        with tempfile.TemporaryDirectory() as tmpdirname:
+            for fname, changes in changesets.items():
+                # Create a new filename and ensure the path exists (in the
+                # temporary directory).
+                new_fname = fname.replace(common_path, tmpdirname)
+                os.makedirs(os.path.split(new_fname)[0], exist_ok=True)
+
+                bad_tests = write_modified_file(fname, new_fname, changes)
+                all_bad_tests.extend(bad_tests)
+
+                # git diff returns 1 to signal changes, so just ignore the
+                # exit status:
+                with subprocess.Popen(
+                        ["git", "diff", "-p", "--no-index", fname, new_fname],
+                        stdout=subprocess.PIPE, stderr=subprocess.PIPE, 
text=True) as p:
+                    p.wait()
+                    # Diff should be fine, but write error if not:
+                    diff = p.stderr.read()
+                    diff += p.stdout.read()
+
+                    # hide the temporary directory (cleaning up anyway):
+                    if not os.path.isabs(common_path):
+                        diff = diff.replace(tmpdirname, "/" + common_path)
+                    else:
+                        # diff seems to not include extra /
+                        diff = diff.replace(tmpdirname, common_path)
+                    terminalreporter.write(diff)
+                    terminalreporter.write_line(f"{tmpdirname}, {common_path}")
+
+                terminalreporter.section("Files with modifications", "-")
+                terminalreporter.write_line(
+                    "The following files would be overwritten with "
+                    "`--doctest-plus-generate-diff=overwrite`:")
+                for fname in changesets:
+                    terminalreporter.write_line(f"    {fname}")
+                terminalreporter.write_line(
+                    "make sure these file paths are correct before calling 
it!")
+    else:
+        # We are in overwrite mode so will write the modified version directly
+        # back into the same file and only report which files were changed.
+        terminalreporter.section("DoctestPlus Fixing File Docs")
+        if not changesets:
+            terminalreporter.write_line("No doc changes to apply")
+            return
+        terminalreporter.write_line("Applied fix to the following files:")
+        for fname, changes in changesets.items():
+            bad_tests = write_modified_file(fname, fname, changes)
+            all_bad_tests.extend(bad_tests)
+            terminalreporter.write_line(f"    {fname}")
+
+    if all_bad_tests:
+        terminalreporter.section("Broken Linenumbers", "-")
+        terminalreporter.write_line(
+            "Doctestplus was unable to fix the following tests "
+            "(their source is hidden or `__module__` overridden?)")
+        for bad_test in all_bad_tests:
+            terminalreporter.write_line(f"    {bad_test}")
+        terminalreporter.write_line(
+            "You can implementing a hook function to fix this (see README).")
+
+
 class DebugRunnerPlus(doctest.DebugRunner):
-    def __init__(self, checker=None, verbose=None, optionflags=0, 
continue_on_failure=True):
+    _changesets = defaultdict(lambda: [])
+    _generate_diff = False
+
+    def __init__(self, checker=None, verbose=None, optionflags=0,
+                 continue_on_failure=True, generate_diff=False):
+        # generated_diff is False, "diff", or "overwrite" (only need 
truthiness)
+        DebugRunnerPlus._generate_diff = generate_diff
+
         super().__init__(checker=checker, verbose=verbose, 
optionflags=optionflags)
         self.continue_on_failure = continue_on_failure
 
+    def report_success(self, out, test, example, got):
+        if self._generate_diff:
+            self.track_diff(False, out, test, example, got)
+            return
+
+        return super().report_success(out, test, example, got)
+
     def report_failure(self, out, test, example, got):
+        if self._generate_diff:
+            self.track_diff(True, out, test, example, got)
+            return
+
         failure = doctest.DocTestFailure(test, example, got)
         if self.continue_on_failure:
             out.append(failure)
@@ -747,3 +919,17 @@
             out.append(failure)
         else:
             raise failure
+
+    def track_diff(self, use, out, test, example, got):
+        if example.want == got:
+            return
+
+        info = dict(use=use, name=test.name, filename=test.filename,
+                    source=example.source, nindent=example.indent,
+                    want=example.want, got=got, test_lineno=test.lineno,
+                    example_lineno=example.lineno)
+        doctestplus_diffhook(info=info)
+        if not info["use"]:
+            return
+
+        self._changesets[info["filename"]].append(info)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pytest-doctestplus-1.0.0/pytest_doctestplus/version.py 
new/pytest-doctestplus-1.1.0/pytest_doctestplus/version.py
--- old/pytest-doctestplus-1.0.0/pytest_doctestplus/version.py  2023-08-11 
18:22:14.000000000 +0200
+++ new/pytest-doctestplus-1.1.0/pytest_doctestplus/version.py  2023-12-13 
19:12:59.000000000 +0100
@@ -1,4 +1,16 @@
 # file generated by setuptools_scm
 # don't change, don't track in version control
-__version__ = version = '1.0.0'
-__version_tuple__ = version_tuple = (1, 0, 0)
+TYPE_CHECKING = False
+if TYPE_CHECKING:
+    from typing import Tuple, Union
+    VERSION_TUPLE = Tuple[Union[int, str], ...]
+else:
+    VERSION_TUPLE = object
+
+version: str
+__version__: str
+__version_tuple__: VERSION_TUPLE
+version_tuple: VERSION_TUPLE
+
+__version__ = version = '1.1.0'
+__version_tuple__ = version_tuple = (1, 1, 0)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pytest-doctestplus-1.0.0/pytest_doctestplus.egg-info/PKG-INFO 
new/pytest-doctestplus-1.1.0/pytest_doctestplus.egg-info/PKG-INFO
--- old/pytest-doctestplus-1.0.0/pytest_doctestplus.egg-info/PKG-INFO   
2023-08-11 18:22:14.000000000 +0200
+++ new/pytest-doctestplus-1.1.0/pytest_doctestplus.egg-info/PKG-INFO   
2023-12-13 19:12:59.000000000 +0100
@@ -1,12 +1,12 @@
 Metadata-Version: 2.1
 Name: pytest-doctestplus
-Version: 1.0.0
+Version: 1.1.0
 Summary: Pytest plugin with advanced doctest features.
 Home-page: https://github.com/scientific-python/pytest-doctestplus
 Author: Scientific Python Developers
 License: BSD
 Keywords: doctest,rst,pytest,py.test
-Classifier: Development Status :: 3 - Alpha
+Classifier: Development Status :: 5 - Production/Stable
 Classifier: Framework :: Pytest
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: BSD License
@@ -14,7 +14,6 @@
 Classifier: Programming Language :: Python
 Classifier: Programming Language :: Python :: 3
 Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.7
 Classifier: Programming Language :: Python :: 3.8
 Classifier: Programming Language :: Python :: 3.9
 Classifier: Programming Language :: Python :: 3.10
@@ -23,10 +22,16 @@
 Classifier: Programming Language :: Python :: Implementation :: CPython
 Classifier: Topic :: Software Development :: Testing
 Classifier: Topic :: Utilities
-Requires-Python: >=3.7
+Requires-Python: >=3.8
 Description-Content-Type: text/x-rst
-Provides-Extra: test
 License-File: LICENSE.rst
+Requires-Dist: pytest>=4.6
+Requires-Dist: setuptools>=30.3.0
+Requires-Dist: packaging>=17.0
+Provides-Extra: test
+Requires-Dist: numpy; extra == "test"
+Requires-Dist: pytest-remotedata>=0.3.2; extra == "test"
+Requires-Dist: sphinx; extra == "test"
 
 ==================
 pytest-doctestplus
@@ -71,6 +76,10 @@
 * optional inclusion of ``*.rst`` files for doctests (see `Setup and 
Configuration`_)
 * optional inclusion of doctests in docstrings of Numpy ufuncs
 
+Further, ``pytest-doctestplus`` supports editing files to fix incorrect 
docstrings
+(See `Fixing Existing Docstrings`_).
+
+.. _pytest-remotedata: https://github.com/astropy/pytest-remotedata
 
 Installation
 ------------
@@ -132,6 +141,23 @@
 doctest settings, see the `doctest documentation
 <https://docs.python.org/3/library/doctest.html#option-flags>`_.
 
+Running Tests in Markdown Files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To run doctests in Markdown files, invoke pytest with the command line options
+``--doctest-plus --doctest-glob '*.md'``.
+
+If you write doctests inside `GitHub-style triple backtick fenced code blocks
+<https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#fenced-code-blocks>`_,
+then in order for pytest-doctest to find and run them you need to include an
+extra trailing newline inside your code blocks, like this::
+
+    ```pycon
+    >>> 1 + 2
+    2
+
+    ```
+
 Doctest Directives
 ~~~~~~~~~~~~~~~~~~
 
@@ -387,6 +413,54 @@
 ``conf.py`` file.
 
 
+Fixing Existing Docstrings
+--------------------------
+The plugin has basic support to fix docstrings, this can be enabled by
+running ``pytest`` with ``--doctest-plus-generate-diff``.
+Without further options, this will print out a diff and a list of files that
+would be modified.  Using ``--doctest-plus-generate-diff=overwrite`` will
+modify the files in-place, so it is recommended to run the check first to
+verify the paths.
+You may wish to review changes manually and only commit some patches e.g. 
using ``git commit --patch``.
+
+The current diff generation is still very basic, for example, it does not 
account for
+existing ``...``.  By default a diff is only generated for *failing* doctests.
+
+In general, a mass edit may wish to focus on a specific change and
+possibly include passing tests.  So you can opt-in into the behavior by
+adding a hook to your ``conftest.py``::
+
+    @pytest.hookimpl
+    def pytest_doctestplus_diffhook(info):
+        info["use"] = True  # Overwrite all results (even successes)
+        if info["fileno"] is None:
+            # E.g. NumPy has C docstrings that cannot be found, we can add
+            # custom logic here to try and find these:
+            info["filename"] = ...
+            info["lineno"] = ...
+
+Where ``info`` is a dictionary containing the following items:
+
+* ``use``: ``True`` or ``False`` signalling whether to apply the diff.  This is
+  set to ``False`` if a doctest succeeded and ``True`` if the doctest failed.
+* ``name``: The name of the test (e.g. the function being documented)
+* ``filename``: The file that contains the test (this can be wrong in certain
+  situation and in that case ``test_lineno`` will be wrong as well).
+* ``source``: The source code that was executed for this test
+* ``test_lineno``: The line of code where the example block (or function) 
starts.
+  In some cases, the test file cannot be found and the lineno will be ``None``,
+  you can manually try to fix these.
+* ``example_lineno``: The line number of the example snippet
+  (individual ``>>>``).
+* ``want``: The current documentation.
+* ``got``: The result of executing the example.
+
+You can modify the dictionary in-place to modify the behavior.
+
+Please note that we assume that this API will be used only occasionally and
+reserve the right to change it at any time.
+
+
 Development Status
 ------------------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/pytest-doctestplus-1.0.0/pytest_doctestplus.egg-info/SOURCES.txt 
new/pytest-doctestplus-1.1.0/pytest_doctestplus.egg-info/SOURCES.txt
--- old/pytest-doctestplus-1.0.0/pytest_doctestplus.egg-info/SOURCES.txt        
2023-08-11 18:22:14.000000000 +0200
+++ new/pytest-doctestplus-1.1.0/pytest_doctestplus.egg-info/SOURCES.txt        
2023-12-13 19:12:59.000000000 +0100
@@ -13,6 +13,7 @@
 licenses/README.rst
 licenses/SYMPY_LICENSE.rst
 pytest_doctestplus/__init__.py
+pytest_doctestplus/newhooks.py
 pytest_doctestplus/output_checker.py
 pytest_doctestplus/plugin.py
 pytest_doctestplus/utils.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-doctestplus-1.0.0/setup.cfg 
new/pytest-doctestplus-1.1.0/setup.cfg
--- old/pytest-doctestplus-1.0.0/setup.cfg      2023-08-11 18:22:14.703384200 
+0200
+++ new/pytest-doctestplus-1.1.0/setup.cfg      2023-12-13 19:12:59.113894500 
+0100
@@ -3,7 +3,7 @@
 url = https://github.com/scientific-python/pytest-doctestplus
 author = Scientific Python Developers
 classifiers = 
-       Development Status :: 3 - Alpha
+       Development Status :: 5 - Production/Stable
        Framework :: Pytest
        Intended Audience :: Developers
        License :: OSI Approved :: BSD License
@@ -11,7 +11,6 @@
        Programming Language :: Python
        Programming Language :: Python :: 3
        Programming Language :: Python :: 3 :: Only
-       Programming Language :: Python :: 3.7
        Programming Language :: Python :: 3.8
        Programming Language :: Python :: 3.9
        Programming Language :: Python :: 3.10
@@ -29,7 +28,7 @@
 [options]
 zip_safe = False
 packages = find:
-python_requires = >=3.7
+python_requires = >=3.8
 setup_requires = 
        setuptools_scm
 install_requires = 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-doctestplus-1.0.0/tests/conftest.py 
new/pytest-doctestplus-1.1.0/tests/conftest.py
--- old/pytest-doctestplus-1.0.0/tests/conftest.py      2023-08-11 
18:21:57.000000000 +0200
+++ new/pytest-doctestplus-1.1.0/tests/conftest.py      2023-12-13 
19:12:44.000000000 +0100
@@ -8,7 +8,7 @@
 
 # Keep this until we require numpy to be >=2.0 or there is a directive in 
doctestplus
 # to support multiple ways of repr
-if Version(np.__version__) > Version("2.0.0.dev0+151"):
+if Version(np.__version__) >= Version("2.0.dev"):
     np.set_printoptions(legacy="1.25")
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-doctestplus-1.0.0/tests/python/doctests.py 
new/pytest-doctestplus-1.1.0/tests/python/doctests.py
--- old/pytest-doctestplus-1.0.0/tests/python/doctests.py       2023-08-11 
18:21:57.000000000 +0200
+++ new/pytest-doctestplus-1.1.0/tests/python/doctests.py       2023-12-13 
19:12:44.000000000 +0100
@@ -1,5 +1,12 @@
 # Licensed under a 3-clause BSD style license - see LICENSE.rst
 
+"""
+Also module level skips should be matched with `*` and `.`, test at least
+the `.` version (the star would match all others too).
+
+>>> import foobar
+"""
+
 __doctest_skip__ = [
     'skip_this_test',
     'ClassWithSomeBadDocTests.this_test_fails',
@@ -7,6 +14,7 @@
 ]
 
 __doctest_requires__ = {
+    '.': ['foobar'],
     'depends_on_foobar': ['foobar'],
     'depends_on_foobar_submodule': ['foobar.baz'],
     'depends_on_two_modules': ['os', 'foobar'],
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-doctestplus-1.0.0/tests/test_doctestplus.py 
new/pytest-doctestplus-1.1.0/tests/test_doctestplus.py
--- old/pytest-doctestplus-1.0.0/tests/test_doctestplus.py      2023-08-11 
18:21:57.000000000 +0200
+++ new/pytest-doctestplus-1.1.0/tests/test_doctestplus.py      2023-12-13 
19:12:44.000000000 +0100
@@ -3,6 +3,8 @@
 from textwrap import dedent
 import sys
 
+from packaging.version import Version
+
 import pytest
 
 import doctest
@@ -12,6 +14,9 @@
 pytest_plugins = ['pytester']
 
 
+PYTEST_LT_6 = Version(pytest.__version__) < Version('6.0.0')
+
+
 def test_ignored_whitespace(testdir):
     testdir.makeini(
         """
@@ -593,6 +598,32 @@
     ).assertoutcome(passed=1)
 
 
+@pytest.mark.xfail(reason='known issue, fenced code blocks require an extra 
trailing newline')
+def test_markdown_fenced_code(testdir):
+    testdir.makefile('.md', foo="""\
+```
+>>> 1 + 1
+2
+```
+""")
+    testdir.inline_run(
+        '--doctest-plus', '--doctest-glob', '*.md'
+    ).assertoutcome(passed=1)
+
+
+def test_markdown_fenced_code_with_extra_newline(testdir):
+    testdir.makefile('.md', foo="""\
+```
+>>> 1 + 1
+2
+
+```
+""")
+    testdir.inline_run(
+        '--doctest-plus', '--doctest-glob', '*.md'
+    ).assertoutcome(passed=1)
+
+
 def test_text_file_comments(testdir):
     testdir.makefile(
         '.md',
@@ -769,20 +800,38 @@
     )
 
 
-def test_doctest_subpackage_requires(testdir, caplog):
+# Note that each entry under doctest_subpackage_requires has different 
whitespace
+# around the = to make sure that all cases work properly.
+SUBPACKAGE_REQUIRES_INI = (
+    "makeini",
+    """
+    [pytest]
+    doctest_subpackage_requires =
+        test/a/* = pytest>1
+        test/b/*= pytest>1;averyfakepackage>99999.9
+        test/c/*=anotherfakepackage>=22000.1.2
+    """
+)
+SUBPACKAGE_REQUIRES_PYPROJECT = (
+    "makepyprojecttoml",
+    """
+    [tool.pytest.ini_options]
+    doctest_subpackage_requires = [
+        "test/a/* = pytest>1",
+        "test/b/*= pytest>1;averyfakepackage>99999.9",
+        "test/c/*=anotherfakepackage>=22000.1.2",
+    ]
+    """
+)
 
-    # Note that each entry below has different whitespace around the = to
-    # make sure that all cases work properly.
 
-    testdir.makeini(
-        """
-        [pytest]
-        doctest_subpackage_requires =
-            test/a/* = pytest>1
-            test/b/*= pytest>1;averyfakepackage>99999.9
-            test/c/*=anotherfakepackage>=22000.1.2
-    """
-    )
+@pytest.fixture()
+def subpackage_requires_testdir(testdir, request):
+    if request.param[0] == 'makepyprojecttoml' and PYTEST_LT_6:
+        return None, None
+
+    config_file = getattr(testdir, request.param[0])(request.param[1])
+
     test = testdir.mkdir('test')
     a = test.mkdir('a')
     b = test.mkdir('b')
@@ -801,12 +850,46 @@
     b.join('testcode.py').write(pyfile)
     c.join('testcode.py').write(pyfile)
 
-    reprec = testdir.inline_run(test, "--doctest-plus")
+    return config_file, testdir
+
+
+@pytest.mark.parametrize('subpackage_requires_testdir', 
[SUBPACKAGE_REQUIRES_INI, SUBPACKAGE_REQUIRES_PYPROJECT], indirect=True)
+def test_doctest_subpackage_requires(subpackage_requires_testdir, caplog):
+    config_file, testdir = subpackage_requires_testdir
+    if config_file is None:
+        pytest.skip("pyproject.toml not supported in pytest<6")
+
+    reprec = testdir.inline_run(str(testdir), f"-c={config_file}", 
"--doctest-plus")
     reprec.assertoutcome(passed=1)
     assert reprec.listoutcomes()[0][0].location[0] == os.path.join('test', 
'a', 'testcode.py')
     assert caplog.text == ''
 
 
+@pytest.mark.parametrize(('import_mode', 'expected'), [
+    pytest.param('importlib', dict(passed=2), 
marks=pytest.mark.skipif(PYTEST_LT_6, reason="importlib import mode not 
supported on Pytest <6"), id="importlib"),
+    pytest.param('append', dict(failed=1), id="append"),
+    pytest.param('prepend', dict(failed=1), id="prepend"),
+])
+def test_import_mode(testdir, import_mode, expected):
+    """Test that two files with the same name but in different folders work 
with --import-mode=importlib."""
+    a = testdir.mkdir('a')
+    b = testdir.mkdir('b')
+
+    pyfile = dedent("""
+        def f():
+            '''
+            >>> 1
+            1
+            '''
+    """)
+
+    a.join('testcode.py').write(pyfile)
+    b.join('testcode.py').write(pyfile)
+
+    reprec = testdir.inline_run(str(testdir), "--doctest-plus", 
f"--import-mode={import_mode}")
+    reprec.assertoutcome(**expected)
+
+
 def test_doctest_skip(testdir):
     testdir.makeini(
         """
@@ -1039,6 +1122,24 @@
     assert ("something()\nUNEXPECTED EXCEPTION: NameError" in 
report.longreprtext) is cont_on_fail
 
 
+def test_main(testdir):
+    pkg = testdir.mkdir('pkg')
+    code = dedent(
+        '''
+        def f():
+            raise RuntimeError("This is a CLI, do not execute module while 
doctesting")
+        
+        f()
+        '''
+    )
+    pkg.join('__init__.py').write_text("", "utf-8")
+    main_path = pkg.join('__main__.py')
+    main_path.write_text(code, "utf-8")
+
+    testdir.inline_run(pkg).assertoutcome(passed=0)
+    testdir.inline_run(pkg, '--doctest-plus').assertoutcome(passed=0)
+
+
 def test_ufunc(testdir):
     pytest.importorskip('numpy')
 
@@ -1144,6 +1245,88 @@
     result.assertoutcome(passed=2, failed=0)
 
 
+NORCURSEDIRS_INI = (
+    "makeini",
+    """
+    [pytest]
+    doctest_norecursedirs =
+        "bad_dir"
+        "*/bad_file.py"
+    """
+)
+NORCURSEDIRS_PYPROJECT = (
+    "makepyprojecttoml",
+    """
+    [tool.pytest.ini_options]
+    doctest_norecursedirs = [
+        "bad_dir",
+        "*/bad_file.py",
+    ]
+    """
+)
+
+
+@pytest.fixture()
+def norecursedirs_testdir(testdir, request):
+    if request.param[0] == 'makepyprojecttoml' and PYTEST_LT_6:
+        return None, None
+
+    config_file = getattr(testdir, request.param[0])(request.param[1])
+
+    bad_text = dedent("""
+        def f():
+            '''
+            This should fail doc testing
+            >>> 1
+            2
+            '''
+            pass
+    """)
+
+    good_text = dedent("""
+        def g():
+            '''
+            This should pass doc testing
+            >>> 1
+            1
+            '''
+            pass
+    """)
+
+    # Create a bad file that should be by its folder
+    bad_subdir = testdir.mkdir("bad_dir")
+    bad_file = bad_subdir.join("test_foobar.py")
+    bad_file.write_text(bad_text, "utf-8")
+
+    # Create a bad file that should be skipped by its name
+    okay_subdir1 = testdir.mkdir("okay_foo_dir")
+    bad_file = okay_subdir1.join("bad_file.py")
+    bad_file.write_text(bad_text, "utf-8")  
+    # Create a good file in that directory that doctest won't skip
+    good_file1 = okay_subdir1.join("good_file1.py")
+    good_file1.write_text(good_text, "utf-8")
+
+    # Create another bad file that should be skipped by its name
+    okay_subdir2 = testdir.mkdir("okay_bar_dir")
+    bad_file = okay_subdir2.join("bad_file.py")
+    bad_file.write_text(bad_text, "utf-8")  
+    # Create a good file in that directory that doctest won't skip
+    good_file2 = okay_subdir2.join("good_file2.py")
+    good_file2.write_text(good_text, "utf-8")
+
+    return config_file, testdir
+
+
+@pytest.mark.parametrize('norecursedirs_testdir', [NORCURSEDIRS_INI, 
NORCURSEDIRS_PYPROJECT], indirect=True)
+def test_doctest_norecursedirs(norecursedirs_testdir):
+    config_file, testdir = norecursedirs_testdir
+    if config_file is None:
+        pytest.skip("pyproject.toml not supported in pytest<6")
+
+    reprec = testdir.inline_run(str(testdir), f"-c={config_file}", 
"--doctest-plus")
+    reprec.assertoutcome(passed=2)
+
+
 def test_norecursedirs(testdir):
     testdir.makeini(
         """
@@ -1165,3 +1348,39 @@
     """, "utf-8")
     reprec = testdir.inline_run(str(testdir), "--doctest-plus")
     reprec.assertoutcome(failed=0, passed=0)
+
+
+def test_generate_diff_basic(testdir, capsys):
+    p = testdir.makepyfile("""
+        def f():
+            '''
+            >>> print(2)
+            4
+            >>> print(3)
+            5
+            '''
+            pass
+        """)
+    with open(p) as f:
+        original = f.read()
+
+    testdir.inline_run(p, "--doctest-plus-generate-diff")
+    diff = dedent("""
+         >>> print(2)
+    -    4
+    +    2
+         >>> print(3)
+    -    5
+    +    3
+    """)
+    captured = capsys.readouterr()
+    assert diff in captured.out
+
+    testdir.inline_run(p, "--doctest-plus-generate-diff=overwrite")
+    captured = capsys.readouterr()
+    assert "Applied fix to the following files" in captured.out
+
+    with open(p) as f:
+        result = f.read()
+
+    assert result == original.replace("4", "2").replace("5", "3")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/pytest-doctestplus-1.0.0/tox.ini 
new/pytest-doctestplus-1.1.0/tox.ini
--- old/pytest-doctestplus-1.0.0/tox.ini        2023-08-11 18:21:57.000000000 
+0200
+++ new/pytest-doctestplus-1.1.0/tox.ini        2023-12-13 19:12:44.000000000 
+0100
@@ -1,6 +1,6 @@
 [tox]
 envlist =
-    py{37,38,39,310,311,312}-test
+    py{38,39,310,311,312}-test
     codestyle
 requires =
     setuptools >= 30.3.0
@@ -14,7 +14,7 @@
     py312: PIP_EXTRA_INDEX_URL = 
https://pypi.anaconda.org/scientific-python-nightly-wheels/simple
 description = run tests
 deps =
-    pytest46: pytest==4.6.*
+    pytestoldest: pytest==4.6.0
     pytest50: pytest==5.0.*
     pytest51: pytest==5.1.*
     pytest52: pytest==5.2.*

Reply via email to