1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

"""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. 

 

""" 

from __future__ import division, absolute_import, print_function 

 

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) + ')'