193 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
		
		
			
		
	
	
			193 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| 
								 | 
							
								"""Subset of inspect module from upstream python
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								We use this instead of upstream because upstream inspect is slow to import, and
							 | 
						||
| 
								 | 
							
								significantly contributes to numpy import times. Importing this copy has almost
							 | 
						||
| 
								 | 
							
								no overhead.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								import types
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								__all__ = ['getargspec', 'formatargspec']
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# ----------------------------------------------------------- type-checking
							 | 
						||
| 
								 | 
							
								def ismethod(object):
							 | 
						||
| 
								 | 
							
								    """Return true if the object is an instance method.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Instance method objects provide these attributes:
							 | 
						||
| 
								 | 
							
								        __doc__         documentation string
							 | 
						||
| 
								 | 
							
								        __name__        name with which this method was defined
							 | 
						||
| 
								 | 
							
								        im_class        class object in which this method belongs
							 | 
						||
| 
								 | 
							
								        im_func         function object containing implementation of method
							 | 
						||
| 
								 | 
							
								        im_self         instance to which this method is bound, or None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    return isinstance(object, types.MethodType)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def isfunction(object):
							 | 
						||
| 
								 | 
							
								    """Return true if the object is a user-defined function.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Function objects provide these attributes:
							 | 
						||
| 
								 | 
							
								        __doc__         documentation string
							 | 
						||
| 
								 | 
							
								        __name__        name with which this function was defined
							 | 
						||
| 
								 | 
							
								        func_code       code object containing compiled function bytecode
							 | 
						||
| 
								 | 
							
								        func_defaults   tuple of any default values for arguments
							 | 
						||
| 
								 | 
							
								        func_doc        (same as __doc__)
							 | 
						||
| 
								 | 
							
								        func_globals    global namespace in which this function was defined
							 | 
						||
| 
								 | 
							
								        func_name       (same as __name__)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    return isinstance(object, types.FunctionType)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def iscode(object):
							 | 
						||
| 
								 | 
							
								    """Return true if the object is a code object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Code objects provide these attributes:
							 | 
						||
| 
								 | 
							
								        co_argcount     number of arguments (not including * or ** args)
							 | 
						||
| 
								 | 
							
								        co_code         string of raw compiled bytecode
							 | 
						||
| 
								 | 
							
								        co_consts       tuple of constants used in the bytecode
							 | 
						||
| 
								 | 
							
								        co_filename     name of file in which this code object was created
							 | 
						||
| 
								 | 
							
								        co_firstlineno  number of first line in Python source code
							 | 
						||
| 
								 | 
							
								        co_flags        bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg
							 | 
						||
| 
								 | 
							
								        co_lnotab       encoded mapping of line numbers to bytecode indices
							 | 
						||
| 
								 | 
							
								        co_name         name with which this code object was defined
							 | 
						||
| 
								 | 
							
								        co_names        tuple of names of local variables
							 | 
						||
| 
								 | 
							
								        co_nlocals      number of local variables
							 | 
						||
| 
								 | 
							
								        co_stacksize    virtual machine stack space required
							 | 
						||
| 
								 | 
							
								        co_varnames     tuple of names of arguments and local variables
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    return isinstance(object, types.CodeType)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# ------------------------------------------------ argument list extraction
							 | 
						||
| 
								 | 
							
								# These constants are from Python's compile.h.
							 | 
						||
| 
								 | 
							
								CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def getargs(co):
							 | 
						||
| 
								 | 
							
								    """Get information about the arguments accepted by a code object.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Three things are returned: (args, varargs, varkw), where 'args' is
							 | 
						||
| 
								 | 
							
								    a list of argument names (possibly containing nested lists), and
							 | 
						||
| 
								 | 
							
								    'varargs' and 'varkw' are the names of the * and ** arguments or None.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if not iscode(co):
							 | 
						||
| 
								 | 
							
								        raise TypeError('arg is not a code object')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    nargs = co.co_argcount
							 | 
						||
| 
								 | 
							
								    names = co.co_varnames
							 | 
						||
| 
								 | 
							
								    args = list(names[:nargs])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # The following acrobatics are for anonymous (tuple) arguments.
							 | 
						||
| 
								 | 
							
								    # Which we do not need to support, so remove to avoid importing
							 | 
						||
| 
								 | 
							
								    # the dis module.
							 | 
						||
| 
								 | 
							
								    for i in range(nargs):
							 | 
						||
| 
								 | 
							
								        if args[i][:1] in ['', '.']:
							 | 
						||
| 
								 | 
							
								            raise TypeError("tuple function arguments are not supported")
							 | 
						||
| 
								 | 
							
								    varargs = None
							 | 
						||
| 
								 | 
							
								    if co.co_flags & CO_VARARGS:
							 | 
						||
| 
								 | 
							
								        varargs = co.co_varnames[nargs]
							 | 
						||
| 
								 | 
							
								        nargs = nargs + 1
							 | 
						||
| 
								 | 
							
								    varkw = None
							 | 
						||
| 
								 | 
							
								    if co.co_flags & CO_VARKEYWORDS:
							 | 
						||
| 
								 | 
							
								        varkw = co.co_varnames[nargs]
							 | 
						||
| 
								 | 
							
								    return args, varargs, varkw
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def getargspec(func):
							 | 
						||
| 
								 | 
							
								    """Get the names and default values of a function's arguments.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    A tuple of four things is returned: (args, varargs, varkw, defaults).
							 | 
						||
| 
								 | 
							
								    '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.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ismethod(func):
							 | 
						||
| 
								 | 
							
								        func = func.__func__
							 | 
						||
| 
								 | 
							
								    if not isfunction(func):
							 | 
						||
| 
								 | 
							
								        raise TypeError('arg is not a Python function')
							 | 
						||
| 
								 | 
							
								    args, varargs, varkw = getargs(func.__code__)
							 | 
						||
| 
								 | 
							
								    return args, varargs, varkw, func.__defaults__
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def getargvalues(frame):
							 | 
						||
| 
								 | 
							
								    """Get information about arguments passed into a particular frame.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    A tuple of four things is returned: (args, varargs, varkw, locals).
							 | 
						||
| 
								 | 
							
								    '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.
							 | 
						||
| 
								 | 
							
								    'locals' is the locals dictionary of the given frame.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    args, varargs, varkw = getargs(frame.f_code)
							 | 
						||
| 
								 | 
							
								    return args, varargs, varkw, frame.f_locals
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def joinseq(seq):
							 | 
						||
| 
								 | 
							
								    if len(seq) == 1:
							 | 
						||
| 
								 | 
							
								        return '(' + seq[0] + ',)'
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return '(' + ', '.join(seq) + ')'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def strseq(object, convert, join=joinseq):
							 | 
						||
| 
								 | 
							
								    """Recursively walk a sequence, stringifying each element.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    if type(object) in [list, tuple]:
							 | 
						||
| 
								 | 
							
								        return join([strseq(_o, convert, join) for _o in object])
							 | 
						||
| 
								 | 
							
								    else:
							 | 
						||
| 
								 | 
							
								        return convert(object)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def formatargspec(args, varargs=None, varkw=None, defaults=None,
							 | 
						||
| 
								 | 
							
								                  formatarg=str,
							 | 
						||
| 
								 | 
							
								                  formatvarargs=lambda name: '*' + name,
							 | 
						||
| 
								 | 
							
								                  formatvarkw=lambda name: '**' + name,
							 | 
						||
| 
								 | 
							
								                  formatvalue=lambda value: '=' + repr(value),
							 | 
						||
| 
								 | 
							
								                  join=joinseq):
							 | 
						||
| 
								 | 
							
								    """Format an argument spec from the 4 values returned by getargspec.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The first four arguments are (args, varargs, varkw, defaults).  The
							 | 
						||
| 
								 | 
							
								    other four arguments are the corresponding optional formatting functions
							 | 
						||
| 
								 | 
							
								    that are called to turn names and values into strings.  The ninth
							 | 
						||
| 
								 | 
							
								    argument is an optional function to format the sequence of arguments.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    specs = []
							 | 
						||
| 
								 | 
							
								    if defaults:
							 | 
						||
| 
								 | 
							
								        firstdefault = len(args) - len(defaults)
							 | 
						||
| 
								 | 
							
								    for i in range(len(args)):
							 | 
						||
| 
								 | 
							
								        spec = strseq(args[i], formatarg, join)
							 | 
						||
| 
								 | 
							
								        if defaults and i >= firstdefault:
							 | 
						||
| 
								 | 
							
								            spec = spec + formatvalue(defaults[i - firstdefault])
							 | 
						||
| 
								 | 
							
								        specs.append(spec)
							 | 
						||
| 
								 | 
							
								    if varargs is not None:
							 | 
						||
| 
								 | 
							
								        specs.append(formatvarargs(varargs))
							 | 
						||
| 
								 | 
							
								    if varkw is not None:
							 | 
						||
| 
								 | 
							
								        specs.append(formatvarkw(varkw))
							 | 
						||
| 
								 | 
							
								    return '(' + ', '.join(specs) + ')'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def formatargvalues(args, varargs, varkw, locals,
							 | 
						||
| 
								 | 
							
								                    formatarg=str,
							 | 
						||
| 
								 | 
							
								                    formatvarargs=lambda name: '*' + name,
							 | 
						||
| 
								 | 
							
								                    formatvarkw=lambda name: '**' + name,
							 | 
						||
| 
								 | 
							
								                    formatvalue=lambda value: '=' + repr(value),
							 | 
						||
| 
								 | 
							
								                    join=joinseq):
							 | 
						||
| 
								 | 
							
								    """Format an argument spec from the 4 values returned by getargvalues.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The first four arguments are (args, varargs, varkw, locals).  The
							 | 
						||
| 
								 | 
							
								    next four arguments are the corresponding optional formatting functions
							 | 
						||
| 
								 | 
							
								    that are called to turn names and values into strings.  The ninth
							 | 
						||
| 
								 | 
							
								    argument is an optional function to format the sequence of arguments.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    def convert(name, locals=locals,
							 | 
						||
| 
								 | 
							
								                formatarg=formatarg, formatvalue=formatvalue):
							 | 
						||
| 
								 | 
							
								        return formatarg(name) + formatvalue(locals[name])
							 | 
						||
| 
								 | 
							
								    specs = [strseq(arg, convert, join) for arg in args]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if varargs:
							 | 
						||
| 
								 | 
							
								        specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))
							 | 
						||
| 
								 | 
							
								    if varkw:
							 | 
						||
| 
								 | 
							
								        specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))
							 | 
						||
| 
								 | 
							
								    return '(' + ', '.join(specs) + ')'
							 |