Skip to content

Commit 854f976

Browse files
committed
inspect: Implement a very basic signature function.
Signed-off-by: Damien George <[email protected]>
1 parent bdc4706 commit 854f976

File tree

3 files changed

+71
-1
lines changed

3 files changed

+71
-1
lines changed

python-stdlib/inspect/inspect.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,60 @@ def currentframe():
8080

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

python-stdlib/inspect/manifest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
metadata(version="0.1.3")
1+
metadata(version="0.2.0")
22

33
module("inspect.py")

python-stdlib/inspect/test_inspect.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import collections
12
import inspect
23
import unittest
34

@@ -58,3 +59,15 @@ def test_isclass(self):
5859

5960
def test_ismodule(self):
6061
self._test_is_helper(inspect.ismodule, entities[6])
62+
63+
def test_signature(self):
64+
self.assertEqual(inspect.signature(globals).parameters, collections.OrderedDict())
65+
self.assertEqual(len(inspect.signature(abs).parameters), 1)
66+
self.assertEqual(len(inspect.signature(hasattr).parameters), 2)
67+
self.assertEqual(len(inspect.signature(setattr).parameters), 3)
68+
self.assertEqual(len(inspect.signature(lambda: 0).parameters), 0)
69+
self.assertEqual(len(inspect.signature(lambda x: 0).parameters), 1)
70+
self.assertEqual(len(inspect.signature(lambda *, x: 0).parameters), 1)
71+
self.assertEqual(len(inspect.signature(lambda x, y: 0).parameters), 2)
72+
self.assertEqual(len(inspect.signature(lambda x, y, z: 0).parameters), 3)
73+
self.assertEqual(len(inspect.signature(lambda x, y, *, z: 0).parameters), 3)

0 commit comments

Comments
 (0)