Skip to content

Commit 78a50ee

Browse files
gh-76007: pydoc: Catch DeprecationWarning for stdlib module __version__ attributes (#139997)
1 parent 04da416 commit 78a50ee

File tree

3 files changed

+65
-18
lines changed

3 files changed

+65
-18
lines changed

Lib/pydoc.py

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,7 @@ class Doc:
450450
PYTHONDOCS = os.environ.get("PYTHONDOCS",
451451
"https://docs.python.org/%d.%d/library"
452452
% sys.version_info[:2])
453+
STDLIB_DIR = sysconfig.get_path('stdlib')
453454

454455
def document(self, object, name=None, *args):
455456
"""Generate documentation for an object."""
@@ -475,23 +476,12 @@ def fail(self, object, name=None, *args):
475476

476477
docmodule = docclass = docroutine = docother = docproperty = docdata = fail
477478

478-
def getdocloc(self, object, basedir=sysconfig.get_path('stdlib')):
479+
def getdocloc(self, object, basedir=None):
479480
"""Return the location of module docs or None"""
480-
481-
try:
482-
file = inspect.getabsfile(object)
483-
except TypeError:
484-
file = '(built-in)'
485-
481+
basedir = self.STDLIB_DIR if basedir is None else basedir
486482
docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
487483

488-
basedir = os.path.normcase(basedir)
489-
if (isinstance(object, type(os)) and
490-
(object.__name__ in ('errno', 'exceptions', 'gc',
491-
'marshal', 'posix', 'signal', 'sys',
492-
'_thread', 'zipimport') or
493-
(file.startswith(basedir) and
494-
not file.startswith(os.path.join(basedir, 'site-packages')))) and
484+
if (self._is_stdlib_module(object, basedir) and
495485
object.__name__ not in ('xml.etree', 'test.test_pydoc.pydoc_mod')):
496486
if docloc.startswith(("http://", "https://")):
497487
docloc = "{}/{}.html".format(docloc.rstrip("/"), object.__name__.lower())
@@ -501,6 +491,36 @@ def getdocloc(self, object, basedir=sysconfig.get_path('stdlib')):
501491
docloc = None
502492
return docloc
503493

494+
def _get_version(self, object):
495+
if self._is_stdlib_module(object):
496+
with warnings.catch_warnings():
497+
warnings.simplefilter("ignore", DeprecationWarning)
498+
version = getattr(object, '__version__', None)
499+
else:
500+
version = getattr(object, '__version__', None)
501+
return '' if version is None else str(version)
502+
503+
def _is_stdlib_module(self, object, basedir=None):
504+
basedir = self.STDLIB_DIR if basedir is None else basedir
505+
506+
try:
507+
file = inspect.getabsfile(object)
508+
except TypeError:
509+
file = '(built-in)'
510+
511+
if sysconfig.is_python_build():
512+
srcdir = sysconfig.get_config_var('srcdir')
513+
if srcdir:
514+
basedir = os.path.join(srcdir, 'Lib')
515+
516+
basedir = os.path.normcase(basedir)
517+
return (isinstance(object, type(os)) and
518+
(object.__name__ in ('errno', 'exceptions', 'gc',
519+
'marshal', 'posix', 'signal', 'sys',
520+
'_thread', 'zipimport')
521+
or (file.startswith(basedir) and
522+
not file.startswith(os.path.join(basedir, 'site-packages')))))
523+
504524
# -------------------------------------------- HTML documentation generator
505525

506526
class HTMLRepr(Repr):
@@ -760,8 +780,8 @@ def docmodule(self, object, name=None, mod=None, *ignored):
760780
except TypeError:
761781
filelink = '(built-in)'
762782
info = []
763-
if hasattr(object, '__version__'):
764-
version = str(object.__version__)
783+
784+
if version := self._get_version(object):
765785
if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
766786
version = version[11:-1].strip()
767787
info.append('version %s' % self.escape(version))
@@ -1296,8 +1316,7 @@ def docmodule(self, object, name=None, mod=None, *ignored):
12961316
contents.append(self.docother(value, key, name, maxlen=70))
12971317
result = result + self.section('DATA', '\n'.join(contents))
12981318

1299-
if hasattr(object, '__version__'):
1300-
version = str(object.__version__)
1319+
if version := self._get_version(object):
13011320
if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
13021321
version = version[11:-1].strip()
13031322
result = result + self.section('VERSION', version)

Lib/test/test_pydoc/test_pydoc.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2305,6 +2305,32 @@ def test_sys_path_adjustment_when_curdir_already_included(self):
23052305
trailing_argv0dir = trailing_curdir + [self.argv0dir]
23062306
self.assertIsNone(self._get_revised_path(trailing_argv0dir))
23072307

2308+
def test__get_version(self):
2309+
import json
2310+
import warnings
2311+
2312+
class MyModule:
2313+
__name__ = 'my_module'
2314+
2315+
@property
2316+
def __version__(self):
2317+
warnings._deprecated("__version__", remove=(3, 20))
2318+
return "1.2.3"
2319+
2320+
module = MyModule()
2321+
doc = pydoc.Doc()
2322+
with warnings.catch_warnings(record=True) as w: # TODO: remove in 3.20
2323+
warnings.simplefilter("always")
2324+
version = doc._get_version(json)
2325+
self.assertEqual(version, "2.0.9")
2326+
self.assertEqual(len(w), 0)
2327+
2328+
with warnings.catch_warnings(record=True) as w:
2329+
warnings.simplefilter("always")
2330+
version = doc._get_version(module)
2331+
self.assertEqual(version, "1.2.3")
2332+
self.assertEqual(len(w), 1)
2333+
23082334

23092335
def setUpModule():
23102336
thread_info = threading_helper.threading_setup()
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:mod:`pydoc`: Fix :exc:`DeprecationWarning` being raised when generating doc for
2+
:term:`stdlib` modules.

0 commit comments

Comments
 (0)