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