1"""Subset of inspect module from upstream python
2
3We use this instead of upstream because upstream inspect is slow to import, and
4significantly contributes to numpy import times. Importing this copy has almost
5no overhead.
6
7"""
8import types
9
10__all__ = ['getargspec', 'formatargspec']
11
12# ----------------------------------------------------------- type-checking
13def ismethod(object):
14 """Return true if the object is an instance method.
15
16 Instance method objects provide these attributes:
17 __doc__ documentation string
18 __name__ name with which this method was defined
19 im_class class object in which this method belongs
20 im_func function object containing implementation of method
21 im_self instance to which this method is bound, or None
22
23 """
24 return isinstance(object, types.MethodType)
25
26def isfunction(object):
27 """Return true if the object is a user-defined function.
28
29 Function objects provide these attributes:
30 __doc__ documentation string
31 __name__ name with which this function was defined
32 func_code code object containing compiled function bytecode
33 func_defaults tuple of any default values for arguments
34 func_doc (same as __doc__)
35 func_globals global namespace in which this function was defined
36 func_name (same as __name__)
37
38 """
39 return isinstance(object, types.FunctionType)
40
41def iscode(object):
42 """Return true if the object is a code object.
43
44 Code objects provide these attributes:
45 co_argcount number of arguments (not including * or ** args)
46 co_code string of raw compiled bytecode
47 co_consts tuple of constants used in the bytecode
48 co_filename name of file in which this code object was created
49 co_firstlineno number of first line in Python source code
50 co_flags bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg
51 co_lnotab encoded mapping of line numbers to bytecode indices
52 co_name name with which this code object was defined
53 co_names tuple of names of local variables
54 co_nlocals number of local variables
55 co_stacksize virtual machine stack space required
56 co_varnames tuple of names of arguments and local variables
57
58 """
59 return isinstance(object, types.CodeType)
60
61
62# ------------------------------------------------ argument list extraction
63# These constants are from Python's compile.h.
64CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8
65
66def getargs(co):
67 """Get information about the arguments accepted by a code object.
68
69 Three things are returned: (args, varargs, varkw), where 'args' is
70 a list of argument names (possibly containing nested lists), and
71 'varargs' and 'varkw' are the names of the * and ** arguments or None.
72
73 """
74
75 if not iscode(co):
76 raise TypeError('arg is not a code object')
77
78 nargs = co.co_argcount
79 names = co.co_varnames
80 args = list(names[:nargs])
81
82 # The following acrobatics are for anonymous (tuple) arguments.
83 # Which we do not need to support, so remove to avoid importing
84 # the dis module.
85 for i in range(nargs):
86 if args[i][:1] in ['', '.']:
87 raise TypeError("tuple function arguments are not supported")
88 varargs = None
89 if co.co_flags & CO_VARARGS:
90 varargs = co.co_varnames[nargs]
91 nargs = nargs + 1
92 varkw = None
93 if co.co_flags & CO_VARKEYWORDS:
94 varkw = co.co_varnames[nargs]
95 return args, varargs, varkw
96
97def getargspec(func):
98 """Get the names and default values of a function's arguments.
99
100 A tuple of four things is returned: (args, varargs, varkw, defaults).
101 'args' is a list of the argument names (it may contain nested lists).
102 'varargs' and 'varkw' are the names of the * and ** arguments or None.
103 'defaults' is an n-tuple of the default values of the last n arguments.
104
105 """
106
107 if ismethod(func):
108 func = func.__func__
109 if not isfunction(func):
110 raise TypeError('arg is not a Python function')
111 args, varargs, varkw = getargs(func.__code__)
112 return args, varargs, varkw, func.__defaults__
113
114def getargvalues(frame):
115 """Get information about arguments passed into a particular frame.
116
117 A tuple of four things is returned: (args, varargs, varkw, locals).
118 'args' is a list of the argument names (it may contain nested lists).
119 'varargs' and 'varkw' are the names of the * and ** arguments or None.
120 'locals' is the locals dictionary of the given frame.
121
122 """
123 args, varargs, varkw = getargs(frame.f_code)
124 return args, varargs, varkw, frame.f_locals
125
126def joinseq(seq):
127 if len(seq) == 1:
128 return '(' + seq[0] + ',)'
129 else:
130 return '(' + ', '.join(seq) + ')'
131
132def strseq(object, convert, join=joinseq):
133 """Recursively walk a sequence, stringifying each element.
134
135 """
136 if type(object) in [list, tuple]:
137 return join([strseq(_o, convert, join) for _o in object])
138 else:
139 return convert(object)
140
141def formatargspec(args, varargs=None, varkw=None, defaults=None,
142 formatarg=str,
143 formatvarargs=lambda name: '*' + name,
144 formatvarkw=lambda name: '**' + name,
145 formatvalue=lambda value: '=' + repr(value),
146 join=joinseq):
147 """Format an argument spec from the 4 values returned by getargspec.
148
149 The first four arguments are (args, varargs, varkw, defaults). The
150 other four arguments are the corresponding optional formatting functions
151 that are called to turn names and values into strings. The ninth
152 argument is an optional function to format the sequence of arguments.
153
154 """
155 specs = []
156 if defaults:
157 firstdefault = len(args) - len(defaults)
158 for i in range(len(args)):
159 spec = strseq(args[i], formatarg, join)
160 if defaults and i >= firstdefault:
161 spec = spec + formatvalue(defaults[i - firstdefault])
162 specs.append(spec)
163 if varargs is not None:
164 specs.append(formatvarargs(varargs))
165 if varkw is not None:
166 specs.append(formatvarkw(varkw))
167 return '(' + ', '.join(specs) + ')'
168
169def formatargvalues(args, varargs, varkw, locals,
170 formatarg=str,
171 formatvarargs=lambda name: '*' + name,
172 formatvarkw=lambda name: '**' + name,
173 formatvalue=lambda value: '=' + repr(value),
174 join=joinseq):
175 """Format an argument spec from the 4 values returned by getargvalues.
176
177 The first four arguments are (args, varargs, varkw, locals). The
178 next four arguments are the corresponding optional formatting functions
179 that are called to turn names and values into strings. The ninth
180 argument is an optional function to format the sequence of arguments.
181
182 """
183 def convert(name, locals=locals,
184 formatarg=formatarg, formatvalue=formatvalue):
185 return formatarg(name) + formatvalue(locals[name])
186 specs = [strseq(arg, convert, join) for arg in args]
187
188 if varargs:
189 specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))
190 if varkw:
191 specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))
192 return '(' + ', '.join(specs) + ')'