kopia lustrzana https://github.com/micropython/micropython-lib
inspect: Implement a very basic signature function.
This implements a very basic `inspect.signature()` function.
At the moment it returns only a simple `Signature` instance with a
`parameters` attribute that holds an `OrderedDict` whose length matches the
arity of the input function (the number of arguments it takes).
So, the following code works and is compatible with CPython:
def f(a, b, *, c):
pass
print(len(inspect.signature(f).parameters))
That should print 3.
Signed-off-by: Damien George <damien@micropython.org>
pull/1043/head
rodzic
bdc4706cc7
commit
b4565b41ea
|
|
@ -80,3 +80,60 @@ def currentframe():
|
|||
|
||||
def getframeinfo(frame, context=1):
|
||||
return ("<unknown>", -1, "<unknown>", [""], 0)
|
||||
|
||||
|
||||
class Signature:
|
||||
pass
|
||||
|
||||
|
||||
# This `signature()` function is very limited. It's main purpose is to work out
|
||||
# the arity of the given function, ie the number of arguments it takes.
|
||||
#
|
||||
# The return value is an instance of `Signature` with a `parameters` member which
|
||||
# is an OrderedDict whose length is the number of arguments of `f`.
|
||||
def signature(f):
|
||||
import collections
|
||||
import uctypes
|
||||
|
||||
s = Signature()
|
||||
s.parameters = collections.OrderedDict()
|
||||
|
||||
t = type(f)
|
||||
if t is type(globals):
|
||||
# A zero-parameter built-in.
|
||||
num_args = 0
|
||||
elif t is type(abs):
|
||||
# A one-parameter built-in.
|
||||
num_args = 1
|
||||
elif t is type(hasattr):
|
||||
# A two-parameter built-in.
|
||||
num_args = 2
|
||||
elif t is type(setattr):
|
||||
# A three-parameter built-in.
|
||||
num_args = 3
|
||||
elif t is type(signature):
|
||||
# A bytecode function, work out the number of arguments by inspecting the bytecode data.
|
||||
fun_obj = uctypes.struct(id(f), (uctypes.ARRAY | 0, uctypes.LONG | 4))
|
||||
bytecode = uctypes.bytearray_at(fun_obj[3], 8)
|
||||
# See py/bc.h:MP_BC_PRELUDE_SIG_DECODE_INTO macro.
|
||||
i = 0
|
||||
z = bytecode[i]
|
||||
i += 1
|
||||
A = z & 0x3
|
||||
K = 0
|
||||
n = 0
|
||||
while z & 0x80:
|
||||
z = bytecode[i]
|
||||
i += 1
|
||||
A |= (z & 0x4) << n
|
||||
K |= ((z & 0x08) >> 3) << n
|
||||
num_args = A + K
|
||||
else:
|
||||
raise NotImplementedError("unsupported function type")
|
||||
|
||||
# Add dummy arguments to the OrderedDict.
|
||||
for i in range(num_args):
|
||||
a = "x{}".format(i)
|
||||
s.parameters[a] = a
|
||||
|
||||
return s
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
metadata(version="0.1.3")
|
||||
metadata(version="0.2.0")
|
||||
|
||||
module("inspect.py")
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import collections
|
||||
import inspect
|
||||
import unittest
|
||||
|
||||
|
|
@ -58,3 +59,15 @@ class TestInspect(unittest.TestCase):
|
|||
|
||||
def test_ismodule(self):
|
||||
self._test_is_helper(inspect.ismodule, entities[6])
|
||||
|
||||
def test_signature(self):
|
||||
self.assertEqual(inspect.signature(globals).parameters, collections.OrderedDict())
|
||||
self.assertEqual(len(inspect.signature(abs).parameters), 1)
|
||||
self.assertEqual(len(inspect.signature(hasattr).parameters), 2)
|
||||
self.assertEqual(len(inspect.signature(setattr).parameters), 3)
|
||||
self.assertEqual(len(inspect.signature(lambda: 0).parameters), 0)
|
||||
self.assertEqual(len(inspect.signature(lambda x: 0).parameters), 1)
|
||||
self.assertEqual(len(inspect.signature(lambda *, x: 0).parameters), 1)
|
||||
self.assertEqual(len(inspect.signature(lambda x, y: 0).parameters), 2)
|
||||
self.assertEqual(len(inspect.signature(lambda x, y, z: 0).parameters), 3)
|
||||
self.assertEqual(len(inspect.signature(lambda x, y, *, z: 0).parameters), 3)
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue