mirror of
https://github.com/python/cpython.git
synced 2025-09-19 15:10:58 +00:00
Final part of SF# 1607548 by Tony Lownds: fix pydoc and inspect.
This commit is contained in:
parent
4b7f3179ea
commit
2e65f892c2
2 changed files with 109 additions and 19 deletions
108
Lib/inspect.py
108
Lib/inspect.py
|
@ -17,6 +17,7 @@ Here are some of the useful functions provided by this module:
|
||||||
getclasstree() - arrange classes so as to represent their hierarchy
|
getclasstree() - arrange classes so as to represent their hierarchy
|
||||||
|
|
||||||
getargspec(), getargvalues() - get info about function arguments
|
getargspec(), getargvalues() - get info about function arguments
|
||||||
|
getfullargspec() - same, with support for Python-3000 features
|
||||||
formatargspec(), formatargvalues() - format an argument spec
|
formatargspec(), formatargvalues() - format an argument spec
|
||||||
getouterframes(), getinnerframes() - get info about frames
|
getouterframes(), getinnerframes() - get info about frames
|
||||||
currentframe() - get the current stack frame
|
currentframe() - get the current stack frame
|
||||||
|
@ -672,9 +673,20 @@ CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8
|
||||||
def getargs(co):
|
def getargs(co):
|
||||||
"""Get information about the arguments accepted by a code object.
|
"""Get information about the arguments accepted by a code object.
|
||||||
|
|
||||||
Three things are returned: (args, varargs, varkw), where 'args' is
|
Three things are returned: (args, varargs, varkw), where
|
||||||
a list of argument names (possibly containing nested lists), and
|
'args' is the list of argument names, possibly containing nested
|
||||||
'varargs' and 'varkw' are the names of the * and ** arguments or None."""
|
lists. Keyword-only arguments are appended. 'varargs' and 'varkw'
|
||||||
|
are the names of the * and ** arguments or None."""
|
||||||
|
args, varargs, kwonlyargs, varkw = _getfullargs(co)
|
||||||
|
return args + kwonlyargs, varargs, varkw
|
||||||
|
|
||||||
|
def _getfullargs(co):
|
||||||
|
"""Get information about the arguments accepted by a code object.
|
||||||
|
|
||||||
|
Four things are returned: (args, varargs, kwonlyargs, varkw), where
|
||||||
|
'args' and 'kwonlyargs' are lists of argument names (with 'args'
|
||||||
|
possibly containing nested lists), and 'varargs' and 'varkw' are the
|
||||||
|
names of the * and ** arguments or None."""
|
||||||
|
|
||||||
if not iscode(co):
|
if not iscode(co):
|
||||||
raise TypeError('arg is not a code object')
|
raise TypeError('arg is not a code object')
|
||||||
|
@ -682,7 +694,9 @@ def getargs(co):
|
||||||
code = co.co_code
|
code = co.co_code
|
||||||
nargs = co.co_argcount
|
nargs = co.co_argcount
|
||||||
names = co.co_varnames
|
names = co.co_varnames
|
||||||
|
nkwargs = co.co_kwonlyargcount
|
||||||
args = list(names[:nargs])
|
args = list(names[:nargs])
|
||||||
|
kwonlyargs = list(names[nargs:nargs+nkwargs])
|
||||||
step = 0
|
step = 0
|
||||||
|
|
||||||
# The following acrobatics are for anonymous (tuple) arguments.
|
# The following acrobatics are for anonymous (tuple) arguments.
|
||||||
|
@ -719,6 +733,7 @@ def getargs(co):
|
||||||
if not remain: break
|
if not remain: break
|
||||||
args[i] = stack[0]
|
args[i] = stack[0]
|
||||||
|
|
||||||
|
nargs += nkwargs
|
||||||
varargs = None
|
varargs = None
|
||||||
if co.co_flags & CO_VARARGS:
|
if co.co_flags & CO_VARARGS:
|
||||||
varargs = co.co_varnames[nargs]
|
varargs = co.co_varnames[nargs]
|
||||||
|
@ -726,23 +741,51 @@ def getargs(co):
|
||||||
varkw = None
|
varkw = None
|
||||||
if co.co_flags & CO_VARKEYWORDS:
|
if co.co_flags & CO_VARKEYWORDS:
|
||||||
varkw = co.co_varnames[nargs]
|
varkw = co.co_varnames[nargs]
|
||||||
return args, varargs, varkw
|
return args, varargs, kwonlyargs, varkw
|
||||||
|
|
||||||
def getargspec(func):
|
def getargspec(func):
|
||||||
"""Get the names and default values of a function's arguments.
|
"""Get the names and default values of a function's arguments.
|
||||||
|
|
||||||
A tuple of four things is returned: (args, varargs, varkw, defaults).
|
A tuple of four things is returned: (args, varargs, varkw, defaults).
|
||||||
'args' is a list of the argument names (it may contain nested lists).
|
'args' is a list of the argument names (it may contain nested lists).
|
||||||
|
'args' will include keyword-only argument names.
|
||||||
'varargs' and 'varkw' are the names of the * and ** arguments or None.
|
'varargs' and 'varkw' are the names of the * and ** arguments or None.
|
||||||
'defaults' is an n-tuple of the default values of the last n arguments.
|
'defaults' is an n-tuple of the default values of the last n arguments.
|
||||||
|
|
||||||
|
Use the getfullargspec() API for Python-3000 code, as annotations
|
||||||
|
and keyword arguments are supported. getargspec() will raise ValueError
|
||||||
|
if the func has either annotations or keyword arguments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, ann = \
|
||||||
|
getfullargspec(func)
|
||||||
|
if kwonlyargs or ann:
|
||||||
|
raise ValueError, ("Function has keyword-only arguments or annotations"
|
||||||
|
", use getfullargspec() API which can support them")
|
||||||
|
return (args, varargs, varkw, defaults)
|
||||||
|
|
||||||
|
def getfullargspec(func):
|
||||||
|
"""Get the names and default values of a function's arguments.
|
||||||
|
|
||||||
|
A tuple of seven things is returned: (args, varargs, kwonlyargs,
|
||||||
|
kwonlydefaults, varkw, defaults, annotations).
|
||||||
|
'args' is a list of the argument names (it may contain nested lists).
|
||||||
|
'varargs' and 'varkw' are the names of the * and ** arguments or None.
|
||||||
|
'defaults' is an n-tuple of the default values of the last n arguments.
|
||||||
|
'kwonlyargs' is a list of keyword-only argument names.
|
||||||
|
'kwonlydefaults' is a dictionary mapping names from kwonlyargs to defaults.
|
||||||
|
'annotations' is a dictionary mapping argument names to annotations.
|
||||||
|
|
||||||
|
The first four items in the tuple correspond to getargspec().
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if ismethod(func):
|
if ismethod(func):
|
||||||
func = func.im_func
|
func = func.im_func
|
||||||
if not isfunction(func):
|
if not isfunction(func):
|
||||||
raise TypeError('arg is not a Python function')
|
raise TypeError('arg is not a Python function')
|
||||||
args, varargs, varkw = getargs(func.__code__)
|
args, varargs, kwonlyargs, varkw = _getfullargs(func.__code__)
|
||||||
return args, varargs, varkw, func.__defaults__
|
return (args, varargs, varkw, func.__defaults__,
|
||||||
|
kwonlyargs, func.__kwdefaults__, func.__annotations__)
|
||||||
|
|
||||||
def getargvalues(frame):
|
def getargvalues(frame):
|
||||||
"""Get information about arguments passed into a particular frame.
|
"""Get information about arguments passed into a particular frame.
|
||||||
|
@ -767,31 +810,66 @@ def strseq(object, convert, join=joinseq):
|
||||||
else:
|
else:
|
||||||
return convert(object)
|
return convert(object)
|
||||||
|
|
||||||
|
def formatannotation(annotation, base_module=None):
|
||||||
|
if isinstance(annotation, type):
|
||||||
|
if annotation.__module__ in ('__builtin__', base_module):
|
||||||
|
return annotation.__name__
|
||||||
|
return annotation.__module__+'.'+annotation.__name__
|
||||||
|
return repr(annotation)
|
||||||
|
|
||||||
|
def formatannotationrelativeto(object):
|
||||||
|
module = getattr(object, '__module__', None)
|
||||||
|
def _formatannotation(annotation):
|
||||||
|
return formatannotation(annotation, module)
|
||||||
|
return _formatannotation
|
||||||
|
|
||||||
def formatargspec(args, varargs=None, varkw=None, defaults=None,
|
def formatargspec(args, varargs=None, varkw=None, defaults=None,
|
||||||
|
kwonlyargs=(), kwonlydefaults={}, annotations={},
|
||||||
formatarg=str,
|
formatarg=str,
|
||||||
formatvarargs=lambda name: '*' + name,
|
formatvarargs=lambda name: '*' + name,
|
||||||
formatvarkw=lambda name: '**' + name,
|
formatvarkw=lambda name: '**' + name,
|
||||||
formatvalue=lambda value: '=' + repr(value),
|
formatvalue=lambda value: '=' + repr(value),
|
||||||
|
formatreturns=lambda text: ' -> ' + text,
|
||||||
|
formatannotation=formatannotation,
|
||||||
join=joinseq):
|
join=joinseq):
|
||||||
"""Format an argument spec from the 4 values returned by getargspec.
|
"""Format an argument spec from the values returned by getargspec
|
||||||
|
or getfullargspec.
|
||||||
|
|
||||||
The first four arguments are (args, varargs, varkw, defaults). The
|
The first seven arguments are (args, varargs, varkw, defaults,
|
||||||
other four arguments are the corresponding optional formatting functions
|
kwonlyargs, kwonlydefaults, annotations). The other five arguments
|
||||||
that are called to turn names and values into strings. The ninth
|
are the corresponding optional formatting functions that are called to
|
||||||
argument is an optional function to format the sequence of arguments."""
|
turn names and values into strings. The last argument is an optional
|
||||||
|
function to format the sequence of arguments."""
|
||||||
|
def formatargandannotation(arg):
|
||||||
|
result = formatarg(arg)
|
||||||
|
if arg in annotations:
|
||||||
|
result += ': ' + formatannotation(annotations[arg])
|
||||||
|
return result
|
||||||
specs = []
|
specs = []
|
||||||
if defaults:
|
if defaults:
|
||||||
firstdefault = len(args) - len(defaults)
|
firstdefault = len(args) - len(defaults)
|
||||||
for i in range(len(args)):
|
for i in range(len(args)):
|
||||||
spec = strseq(args[i], formatarg, join)
|
spec = strseq(args[i], formatargandannotation, join)
|
||||||
if defaults and i >= firstdefault:
|
if defaults and i >= firstdefault:
|
||||||
spec = spec + formatvalue(defaults[i - firstdefault])
|
spec = spec + formatvalue(defaults[i - firstdefault])
|
||||||
specs.append(spec)
|
specs.append(spec)
|
||||||
if varargs is not None:
|
if varargs is not None:
|
||||||
specs.append(formatvarargs(varargs))
|
specs.append(formatvarargs(formatargandannotation(varargs)))
|
||||||
|
else:
|
||||||
|
if kwonlyargs:
|
||||||
|
specs.append('*')
|
||||||
|
if kwonlyargs:
|
||||||
|
for kwonlyarg in kwonlyargs:
|
||||||
|
spec = formatargandannotation(kwonlyarg)
|
||||||
|
if kwonlyarg in kwonlydefaults:
|
||||||
|
spec += formatvalue(kwonlydefaults[kwonlyarg])
|
||||||
|
specs.append(spec)
|
||||||
if varkw is not None:
|
if varkw is not None:
|
||||||
specs.append(formatvarkw(varkw))
|
specs.append(formatvarkw(formatargandannotation(varkw)))
|
||||||
return '(' + string.join(specs, ', ') + ')'
|
result = '(' + string.join(specs, ', ') + ')'
|
||||||
|
if 'return' in annotations:
|
||||||
|
result += formatreturns(formatannotation(annotations['return']))
|
||||||
|
return result
|
||||||
|
|
||||||
def formatargvalues(args, varargs, varkw, locals,
|
def formatargvalues(args, varargs, varkw, locals,
|
||||||
formatarg=str,
|
formatarg=str,
|
||||||
|
|
20
Lib/pydoc.py
20
Lib/pydoc.py
|
@ -875,11 +875,17 @@ class HTMLDoc(Doc):
|
||||||
title = '<a name="%s"><strong>%s</strong></a> = %s' % (
|
title = '<a name="%s"><strong>%s</strong></a> = %s' % (
|
||||||
anchor, name, reallink)
|
anchor, name, reallink)
|
||||||
if inspect.isfunction(object):
|
if inspect.isfunction(object):
|
||||||
args, varargs, varkw, defaults = inspect.getargspec(object)
|
args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann = \
|
||||||
|
inspect.getfullargspec(object)
|
||||||
argspec = inspect.formatargspec(
|
argspec = inspect.formatargspec(
|
||||||
args, varargs, varkw, defaults, formatvalue=self.formatvalue)
|
args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann,
|
||||||
|
formatvalue=self.formatvalue,
|
||||||
|
formatannotation=inspect.formatannotationrelativeto(object))
|
||||||
if realname == '<lambda>':
|
if realname == '<lambda>':
|
||||||
title = '<strong>%s</strong> <em>lambda</em> ' % name
|
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 = argspec[1:-1] # remove parentheses
|
||||||
else:
|
else:
|
||||||
argspec = '(...)'
|
argspec = '(...)'
|
||||||
|
@ -1241,11 +1247,17 @@ class TextDoc(Doc):
|
||||||
skipdocs = 1
|
skipdocs = 1
|
||||||
title = self.bold(name) + ' = ' + realname
|
title = self.bold(name) + ' = ' + realname
|
||||||
if inspect.isfunction(object):
|
if inspect.isfunction(object):
|
||||||
args, varargs, varkw, defaults = inspect.getargspec(object)
|
args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann = \
|
||||||
|
inspect.getfullargspec(object)
|
||||||
argspec = inspect.formatargspec(
|
argspec = inspect.formatargspec(
|
||||||
args, varargs, varkw, defaults, formatvalue=self.formatvalue)
|
args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann,
|
||||||
|
formatvalue=self.formatvalue,
|
||||||
|
formatannotation=inspect.formatannotationrelativeto(object))
|
||||||
if realname == '<lambda>':
|
if realname == '<lambda>':
|
||||||
title = self.bold(name) + ' 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 = argspec[1:-1] # remove parentheses
|
||||||
else:
|
else:
|
||||||
argspec = '(...)'
|
argspec = '(...)'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue