@@ -80,3 +80,60 @@ def currentframe():
80
80
81
81
def getframeinfo (frame , context = 1 ):
82
82
return ("<unknown>" , - 1 , "<unknown>" , ["" ], 0 )
83
+
84
+
85
+ class Signature :
86
+ pass
87
+
88
+
89
+ # This `signature()` function is very limited. It's main purpose is to work out
90
+ # the arity of the given function, ie the number of arguments it takes.
91
+ #
92
+ # The return value is an instance of `Signature` with a `parameters` member which
93
+ # is an OrderedDict whose length is the number of arguments of `f`.
94
+ def signature (f ):
95
+ import collections
96
+ import uctypes
97
+
98
+ s = Signature ()
99
+ s .parameters = collections .OrderedDict ()
100
+
101
+ t = type (f )
102
+ if t is type (globals ):
103
+ # A zero-parameter built-in.
104
+ num_args = 0
105
+ elif t is type (abs ):
106
+ # A one-parameter built-in.
107
+ num_args = 1
108
+ elif t is type (hasattr ):
109
+ # A two-parameter built-in.
110
+ num_args = 2
111
+ elif t is type (setattr ):
112
+ # A three-parameter built-in.
113
+ num_args = 3
114
+ elif t is type (signature ):
115
+ # A bytecode function, work out the number of arguments by inspecting the bytecode data.
116
+ fun_obj = uctypes .struct (id (f ), (uctypes .ARRAY | 0 , uctypes .LONG | 4 ))
117
+ bytecode = uctypes .bytearray_at (fun_obj [3 ], 8 )
118
+ # See py/bc.h:MP_BC_PRELUDE_SIG_DECODE_INTO macro.
119
+ i = 0
120
+ z = bytecode [i ]
121
+ i += 1
122
+ A = z & 0x3
123
+ K = 0
124
+ n = 0
125
+ while z & 0x80 :
126
+ z = bytecode [i ]
127
+ i += 1
128
+ A |= (z & 0x4 ) << n
129
+ K |= ((z & 0x08 ) >> 3 ) << n
130
+ num_args = A + K
131
+ else :
132
+ raise NotImplementedError ("unsupported function type" )
133
+
134
+ # Add dummy arguments to the OrderedDict.
135
+ for i in range (num_args ):
136
+ a = "x{}" .format (i )
137
+ s .parameters [a ] = a
138
+
139
+ return s
0 commit comments