diff --git a/Lib/inspect.py b/Lib/inspect.py
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -1572,13 +1572,19 @@
_partial_kwarg=_partial_kwarg)
def __str__(self):
+ return self.render()
+
+ def render(self,
+ formatvalue=lambda value: '=' +repr(value),
+ formatpositional=lambda value: '<{}>'.format(value),
+ formatannotation=formatannotation):
kind = self.kind
formatted = self._name
if kind == _POSITIONAL_ONLY:
if formatted is None:
formatted = ''
- formatted = '<{}>'.format(formatted)
+ formatted = formatpositional(formatted)
# Add annotation and default value
if self._annotation is not _empty:
@@ -1586,7 +1592,7 @@
formatannotation(self._annotation))
if self._default is not _empty:
- formatted = '{}={}'.format(formatted, repr(self._default))
+ formatted = '{}{}'.format(formatted, formatvalue(self._default))
if kind == _VAR_POSITIONAL:
formatted = '*' + formatted
@@ -2043,10 +2049,18 @@
return __bind_self._bind(args, kwargs, partial=True)
def __str__(self):
+ return self.render()
+
+ def render(self,
+ formatvalue=lambda value:'=' + str(value),
+ formatannotation=formatannotation,
+ formatpositional=lambda value: '<{}>'.format(value),
+ islambda=False):
+
result = []
render_kw_only_separator = True
for idx, param in enumerate(self.parameters.values()):
- formatted = str(param)
+ formatted = param.render(formatvalue, formatpositional, formatannotation)
kind = param.kind
if kind == _VAR_POSITIONAL:
@@ -2070,4 +2084,7 @@
anno = formatannotation(self.return_annotation)
rendered += ' -> {}'.format(anno)
+ elif islambda:
+ rendered = rendered[1:-1]
+
return rendered
diff --git a/Lib/pydoc.py b/Lib/pydoc.py
--- a/Lib/pydoc.py
+++ b/Lib/pydoc.py
@@ -913,21 +913,18 @@
reallink = realname
title = '%s = %s' % (
anchor, name, reallink)
- if inspect.isfunction(object):
- args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann = \
- inspect.getfullargspec(object)
- argspec = inspect.formatargspec(
- args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann,
- formatvalue=self.formatvalue,
- formatannotation=inspect.formatannotationrelativeto(object))
- if realname == '':
- title = '%s lambda ' % 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
- else:
- argspec = '(...)'
+
+ try:
+ signature = inspect.signature(object)
+ except ValueError:
+ signature = '(...)'
+ argspec = signature.render(formatvalue=self.formatvalue,
+ formatannotation=inspect.formatannotationrelativeto(object),
+ formatpositional=lambda nm: '<{}>'.format(nm),
+ islambda=(inspect.isfunction(object) and realname == ''))
+ if inspect.isfunction(object) and realname == '':
+ title = '%s lambda ' % name
+
decl = title + argspec + (note and self.grey(
'%s' % note))
@@ -1309,21 +1306,18 @@
cl.__dict__[realname] is object):
skipdocs = 1
title = self.bold(name) + ' = ' + realname
- if inspect.isfunction(object):
- args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann = \
- inspect.getfullargspec(object)
- argspec = inspect.formatargspec(
- args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann,
- formatvalue=self.formatvalue,
- formatannotation=inspect.formatannotationrelativeto(object))
- if realname == '':
- 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
- else:
+
+ try:
+ signature = inspect.signature(object)
+ argspec = signature.render(formatvalue=self.formatvalue,
+ formatannotation=inspect.formatannotationrelativeto(object),
+ islambda=(inspect.isfunction(object) and realname == ''))
+ except ValueError:
argspec = '(...)'
+ if inspect.isfunction(object) and realname == '':
+ title = title + ' '
+
+
decl = title + argspec + note
if skipdocs:
diff --git a/Lib/test/test_pydoc.py b/Lib/test/test_pydoc.py
--- a/Lib/test/test_pydoc.py
+++ b/Lib/test/test_pydoc.py
@@ -395,6 +395,36 @@
synopsis = pydoc.synopsis(TESTFN, {})
self.assertEqual(synopsis, 'line 1: h\xe9')
+ @unittest.skipIf(sys.flags.optimize >= 2,
+ "Docstrings are omitted with -O2 and above")
+ def test_function_like_signature(self):
+ class Function:
+ def __init__(self):
+ self._func = lambda a=3, b=4: a*b
+
+ def __call__(self, *args, **kwds):
+ return self._func(*args, **kwds)
+
+ @property
+ def __name__(self):
+ return '$function$'
+
+ @property
+ def __signature__(self):
+ return inspect.signature(self._func)
+
+ def __get__(self, a, b):
+ return self
+
+ function = Function()
+ self.assertEqual(function(), 12)
+
+ doc = pydoc.TextDoc()
+ result = doc.document(function)
+
+ self.maxDiff = None
+ self.assertEqual(result, '''$\x08$f\x08fu\x08un\x08nc\x08ct\x08ti\x08io\x08on\x08n$\x08$(a=3, b=4)\n''')
+
class PydocImportTest(unittest.TestCase):