aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/pydoc.py
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2023-08-11 20:51:36 +0300
committerGitHub <noreply@github.com>2023-08-11 20:51:36 +0300
commita39f0a350662f1978104ee1136472d784aa6f29c (patch)
treea13f5ab25aa3b11743d7d146524887dee88c1805 /Lib/pydoc.py
parent5f7d4ecf301ef12eb1d1d347add054f4fcd8fc5c (diff)
downloadcpython-a39f0a350662f1978104ee1136472d784aa6f29c.tar.gz
cpython-a39f0a350662f1978104ee1136472d784aa6f29c.zip
gh-107782: Pydoc: fall back to __text_signature__ if inspect.signature() fails (GH-107786)
It allows to show signatures which are not representable in Python, e.g. for getattr and dict.pop.
Diffstat (limited to 'Lib/pydoc.py')
-rwxr-xr-xLib/pydoc.py78
1 files changed, 38 insertions, 40 deletions
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
index 185f09e603d..c9a55799b39 100755
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -197,6 +197,24 @@ def splitdoc(doc):
return lines[0], '\n'.join(lines[2:])
return '', '\n'.join(lines)
+def _getargspec(object):
+ try:
+ signature = inspect.signature(object)
+ if signature:
+ return str(signature)
+ except (ValueError, TypeError):
+ argspec = getattr(object, '__text_signature__', None)
+ if argspec:
+ if argspec[:2] == '($':
+ argspec = '(' + argspec[2:]
+ if getattr(object, '__self__', None) is not None:
+ # Strip the bound argument.
+ m = re.match(r'\(\w+(?:(?=\))|,\s*(?:/(?:(?=\))|,\s*))?)', argspec)
+ if m:
+ argspec = '(' + argspec[m.end():]
+ return argspec
+ return None
+
def classname(object, modname):
"""Get a class name and qualify it with a module name if necessary."""
name = object.__name__
@@ -1003,14 +1021,9 @@ class HTMLDoc(Doc):
title = title + '(%s)' % ', '.join(parents)
decl = ''
- try:
- signature = inspect.signature(object)
- except (ValueError, TypeError):
- signature = None
- if signature:
- argspec = str(signature)
- if argspec and argspec != '()':
- decl = name + self.escape(argspec) + '\n\n'
+ argspec = _getargspec(object)
+ if argspec and argspec != '()':
+ decl = name + self.escape(argspec) + '\n\n'
doc = getdoc(object)
if decl:
@@ -1063,18 +1076,13 @@ class HTMLDoc(Doc):
anchor, name, reallink)
argspec = None
if inspect.isroutine(object):
- try:
- signature = inspect.signature(object)
- except (ValueError, TypeError):
- signature = None
- if signature:
- argspec = str(signature)
- if realname == '<lambda>':
- title = '<strong>%s</strong> <em>lambda</em> ' % name
- # XXX lambda's won't usually have func_annotations['return']
- # since the syntax doesn't support but it is possible.
- # So removing parentheses isn't truly safe.
- argspec = argspec[1:-1] # remove parentheses
+ argspec = _getargspec(object)
+ if argspec and realname == '<lambda>':
+ title = '<strong>%s</strong> <em>lambda</em> ' % name
+ # XXX lambda's won't usually have func_annotations['return']
+ # since the syntax doesn't support but it is possible.
+ # So removing parentheses isn't truly safe.
+ argspec = argspec[1:-1] # remove parentheses
if not argspec:
argspec = '(...)'
@@ -1321,14 +1329,9 @@ location listed above.
contents = []
push = contents.append
- try:
- signature = inspect.signature(object)
- except (ValueError, TypeError):
- signature = None
- if signature:
- argspec = str(signature)
- if argspec and argspec != '()':
- push(name + argspec + '\n')
+ argspec = _getargspec(object)
+ if argspec and argspec != '()':
+ push(name + argspec + '\n')
doc = getdoc(object)
if doc:
@@ -1492,18 +1495,13 @@ location listed above.
argspec = None
if inspect.isroutine(object):
- try:
- signature = inspect.signature(object)
- except (ValueError, TypeError):
- signature = None
- if signature:
- argspec = str(signature)
- if realname == '<lambda>':
- title = self.bold(name) + ' lambda '
- # XXX lambda's won't usually have func_annotations['return']
- # since the syntax doesn't support but it is possible.
- # So removing parentheses isn't truly safe.
- argspec = argspec[1:-1] # remove parentheses
+ argspec = _getargspec(object)
+ if argspec and realname == '<lambda>':
+ title = self.bold(name) + ' lambda '
+ # XXX lambda's won't usually have func_annotations['return']
+ # since the syntax doesn't support but it is possible.
+ # So removing parentheses isn't truly safe.
+ argspec = argspec[1:-1] # remove parentheses
if not argspec:
argspec = '(...)'
decl = asyncqualifier + title + argspec + note