]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-76007: `pydoc`: Catch `DeprecationWarning` for stdlib module `__version__` attribu...
authorStan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
Sun, 14 Dec 2025 12:59:05 +0000 (12:59 +0000)
committerGitHub <noreply@github.com>
Sun, 14 Dec 2025 12:59:05 +0000 (14:59 +0200)
Lib/pydoc.py
Lib/test/test_pydoc/test_pydoc.py
Misc/NEWS.d/next/Library/2025-10-12-12-43-56.gh-issue-76007.PyGM14.rst [new file with mode: 0644]

index ee4457d9d3a9329139f453da995037a33ac0ba35..c8d4aa7a88325b2c0ab855ad9a04c4cfd257cecf 100644 (file)
@@ -450,6 +450,7 @@ class Doc:
     PYTHONDOCS = os.environ.get("PYTHONDOCS",
                                 "https://docs.python.org/%d.%d/library"
                                 % sys.version_info[:2])
+    STDLIB_DIR = sysconfig.get_path('stdlib')
 
     def document(self, object, name=None, *args):
         """Generate documentation for an object."""
@@ -475,23 +476,12 @@ class Doc:
 
     docmodule = docclass = docroutine = docother = docproperty = docdata = fail
 
-    def getdocloc(self, object, basedir=sysconfig.get_path('stdlib')):
+    def getdocloc(self, object, basedir=None):
         """Return the location of module docs or None"""
-
-        try:
-            file = inspect.getabsfile(object)
-        except TypeError:
-            file = '(built-in)'
-
+        basedir = self.STDLIB_DIR if basedir is None else basedir
         docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
 
-        basedir = os.path.normcase(basedir)
-        if (isinstance(object, type(os)) and
-            (object.__name__ in ('errno', 'exceptions', 'gc',
-                                 'marshal', 'posix', 'signal', 'sys',
-                                 '_thread', 'zipimport') or
-             (file.startswith(basedir) and
-              not file.startswith(os.path.join(basedir, 'site-packages')))) and
+        if (self._is_stdlib_module(object, basedir) and
             object.__name__ not in ('xml.etree', 'test.test_pydoc.pydoc_mod')):
             if docloc.startswith(("http://", "https://")):
                 docloc = "{}/{}.html".format(docloc.rstrip("/"), object.__name__.lower())
@@ -501,6 +491,36 @@ class Doc:
             docloc = None
         return docloc
 
+    def _get_version(self, object):
+        if self._is_stdlib_module(object):
+            with warnings.catch_warnings():
+                warnings.simplefilter("ignore", DeprecationWarning)
+                version = getattr(object, '__version__', None)
+        else:
+            version = getattr(object, '__version__', None)
+        return '' if version is None else str(version)
+
+    def _is_stdlib_module(self, object, basedir=None):
+        basedir = self.STDLIB_DIR if basedir is None else basedir
+
+        try:
+            file = inspect.getabsfile(object)
+        except TypeError:
+            file = '(built-in)'
+
+        if sysconfig.is_python_build():
+            srcdir = sysconfig.get_config_var('srcdir')
+            if srcdir:
+                basedir = os.path.join(srcdir, 'Lib')
+
+        basedir = os.path.normcase(basedir)
+        return (isinstance(object, type(os)) and
+                (object.__name__ in ('errno', 'exceptions', 'gc',
+                                     'marshal', 'posix', 'signal', 'sys',
+                                     '_thread', 'zipimport')
+                or (file.startswith(basedir) and
+                 not file.startswith(os.path.join(basedir, 'site-packages')))))
+
 # -------------------------------------------- HTML documentation generator
 
 class HTMLRepr(Repr):
@@ -760,8 +780,8 @@ class HTMLDoc(Doc):
         except TypeError:
             filelink = '(built-in)'
         info = []
-        if hasattr(object, '__version__'):
-            version = str(object.__version__)
+
+        if version := self._get_version(object):
             if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
                 version = version[11:-1].strip()
             info.append('version %s' % self.escape(version))
@@ -1296,8 +1316,7 @@ location listed above.
                 contents.append(self.docother(value, key, name, maxlen=70))
             result = result + self.section('DATA', '\n'.join(contents))
 
-        if hasattr(object, '__version__'):
-            version = str(object.__version__)
+        if version := self._get_version(object):
             if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
                 version = version[11:-1].strip()
             result = result + self.section('VERSION', version)
index c640416327efbff9340dc35b8ecc954e29c6a532..89480423d32bc72a75111852a2b00b5bcc89123e 100644 (file)
@@ -2305,6 +2305,32 @@ class TestInternalUtilities(unittest.TestCase):
                 trailing_argv0dir = trailing_curdir + [self.argv0dir]
                 self.assertIsNone(self._get_revised_path(trailing_argv0dir))
 
+    def test__get_version(self):
+        import json
+        import warnings
+
+        class MyModule:
+            __name__ = 'my_module'
+
+            @property
+            def __version__(self):
+                warnings._deprecated("__version__", remove=(3, 20))
+                return "1.2.3"
+
+        module = MyModule()
+        doc = pydoc.Doc()
+        with warnings.catch_warnings(record=True) as w: # TODO: remove in 3.20
+            warnings.simplefilter("always")
+            version = doc._get_version(json)
+            self.assertEqual(version, "2.0.9")
+            self.assertEqual(len(w), 0)
+
+        with warnings.catch_warnings(record=True) as w:
+            warnings.simplefilter("always")
+            version = doc._get_version(module)
+            self.assertEqual(version, "1.2.3")
+            self.assertEqual(len(w), 1)
+
 
 def setUpModule():
     thread_info = threading_helper.threading_setup()
diff --git a/Misc/NEWS.d/next/Library/2025-10-12-12-43-56.gh-issue-76007.PyGM14.rst b/Misc/NEWS.d/next/Library/2025-10-12-12-43-56.gh-issue-76007.PyGM14.rst
new file mode 100644 (file)
index 0000000..3a0914f
--- /dev/null
@@ -0,0 +1,2 @@
+:mod:`pydoc`: Fix :exc:`DeprecationWarning` being raised when generating doc for
+:term:`stdlib` modules.