1"""Subset of inspect module from upstream python

2

3 We use this instead of upstream because upstream inspect is slow to import, and

4 significantly contributes to numpy import times. Importing this copy has almost

5 no overhead.

6

7"""

8 import types

9

10__all__ = ['getargspec', 'formatargspec']

11

12# ----------------------------------------------------------- type-checking

13 def 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

26 def 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

41 def 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# ------------------------------------------------ argument list extraction

62# These constants are from Python's compile.h.

63 CO_OPTIMIZED, CO_NEWLOCALS, CO_VARARGS, CO_VARKEYWORDS = 1, 2, 4, 8

64

65 def getargs(co):

66 """Get information about the arguments accepted by a code object.

67

68 Three things are returned: (args, varargs, varkw), where 'args' is

69 a list of argument names (possibly containing nested lists), and

70 'varargs' and 'varkw' are the names of the * and ** arguments or None.

71

72 """

73

74 if not iscode(co):

75 raise TypeError('arg is not a code object')

76

77 nargs = co.co_argcount

78 names = co.co_varnames

79 args = list(names[:nargs])

80

81 # The following acrobatics are for anonymous (tuple) arguments.

82 # Which we do not need to support, so remove to avoid importing

83 # the dis module.

84 for i in range(nargs):

85 if args[i][:1] in ['', '.']:

86 raise TypeError("tuple function arguments are not supported")

87 varargs = None

88 if co.co_flags & CO_VARARGS:

89 varargs = co.co_varnames[nargs]

90 nargs = nargs + 1

91 varkw = None

92 if co.co_flags & CO_VARKEYWORDS:

93 varkw = co.co_varnames[nargs]

94 return args, varargs, varkw

95

96 def getargspec(func):

97 """Get the names and default values of a function's arguments.

98

99 A tuple of four things is returned: (args, varargs, varkw, defaults).

100 'args' is a list of the argument names (it may contain nested lists).

101 'varargs' and 'varkw' are the names of the * and ** arguments or None.

102 'defaults' is an n-tuple of the default values of the last n arguments.

103

104 """

105

106 if ismethod(func):

107 func = func.__func__

108 if not isfunction(func):

109 raise TypeError('arg is not a Python function')

110 args, varargs, varkw = getargs(func.__code__)

111 return args, varargs, varkw, func.__defaults__

112

113 def getargvalues(frame):

114 """Get information about arguments passed into a particular frame.

115

116 A tuple of four things is returned: (args, varargs, varkw, locals).

117 'args' is a list of the argument names (it may contain nested lists).

118 'varargs' and 'varkw' are the names of the * and ** arguments or None.

119 'locals' is the locals dictionary of the given frame.

120

121 """

122 args, varargs, varkw = getargs(frame.f_code)

123 return args, varargs, varkw, frame.f_locals

124

125 def joinseq(seq):

126 if len(seq) == 1:

127 return '(' + seq[0] + ',)'

128 else:

129 return '(' + ', '.join(seq) + ')'

130

131 def strseq(object, convert, join=joinseq):

132 """Recursively walk a sequence, stringifying each element.

133

134 """

135 if type(object) in [list, tuple]:

136 return join([strseq(_o, convert, join) for _o in object])

137 else:

138 return convert(object)

139

140 def formatargspec(args, varargs=None, varkw=None, defaults=None,

141 formatarg=str,

142 formatvarargs=lambda name: '*' + name,

143 formatvarkw=lambda name: '**' + name,

144 formatvalue=lambda value: '=' + repr(value),

145 join=joinseq):

146 """Format an argument spec from the 4 values returned by getargspec.

147

148 The first four arguments are (args, varargs, varkw, defaults). The

149 other four arguments are the corresponding optional formatting functions

150 that are called to turn names and values into strings. The ninth

151 argument is an optional function to format the sequence of arguments.

152

153 """

154 specs = []

155 if defaults:

156 firstdefault = len(args) - len(defaults)

157 for i in range(len(args)):

158 spec = strseq(args[i], formatarg, join)

159 if defaults and i >= firstdefault:

160 spec = spec + formatvalue(defaults[i - firstdefault])

161 specs.append(spec)

162 if varargs is not None:

163 specs.append(formatvarargs(varargs))

164 if varkw is not None:

165 specs.append(formatvarkw(varkw))

166 return '(' + ', '.join(specs) + ')'

167

168 def formatargvalues(args, varargs, varkw, locals,

169 formatarg=str,

170 formatvarargs=lambda name: '*' + name,

171 formatvarkw=lambda name: '**' + name,

172 formatvalue=lambda value: '=' + repr(value),

173 join=joinseq):

174 """Format an argument spec from the 4 values returned by getargvalues.

175

176 The first four arguments are (args, varargs, varkw, locals). The

177 next four arguments are the corresponding optional formatting functions

178 that are called to turn names and values into strings. The ninth

179 argument is an optional function to format the sequence of arguments.

180

181 """

182 def convert(name, locals=locals,

183 formatarg=formatarg, formatvalue=formatvalue):

184 return formatarg(name) + formatvalue(locals[name])

185 specs = [strseq(arg, convert, join) for arg in args]

186

187 if varargs:

188 specs.append(formatvarargs(varargs) + formatvalue(locals[varargs]))

189 if varkw:

190 specs.append(formatvarkw(varkw) + formatvalue(locals[varkw]))

191 return '(' + ', '.join(specs) + ')'