@@ -80,3 +80,60 @@ def currentframe():
8080
8181def getframeinfo (frame , context = 1 ):
8282 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