diff --git a/python-stdlib/inspect/inspect.py b/python-stdlib/inspect/inspect.py index 9074549bb..f6b7d3c89 100644 --- a/python-stdlib/inspect/inspect.py +++ b/python-stdlib/inspect/inspect.py @@ -1,7 +1,10 @@ import sys +# Generator function. _g = lambda: (yield) +# Closure type. +_ct = type((lambda x: (lambda: x))(None)) def getmembers(obj, pred=None): res = [] @@ -111,9 +114,16 @@ def signature(f): elif t is type(setattr): # A three-parameter built-in. num_args = 3 - elif t is type(signature): + elif t is type(signature) or t is type(_g) or t is _ct: # 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)) + fun_ptr = id(f) + num_closed_over = 0 + if t is _ct: + # A closure, the function is the second word. + clo_ptr = uctypes.struct(fun_ptr, (uctypes.ARRAY | 0, uctypes.LONG | 3)) + fun_ptr = clo_ptr[1] + num_closed_over = clo_ptr[2] + fun_obj = uctypes.struct(fun_ptr, (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 @@ -127,7 +137,7 @@ def signature(f): i += 1 A |= (z & 0x4) << n K |= ((z & 0x08) >> 3) << n - num_args = A + K + num_args = A + K - num_closed_over else: raise NotImplementedError("unsupported function type") diff --git a/python-stdlib/inspect/manifest.py b/python-stdlib/inspect/manifest.py index 119237c45..03ede9f0a 100644 --- a/python-stdlib/inspect/manifest.py +++ b/python-stdlib/inspect/manifest.py @@ -1,3 +1,3 @@ -metadata(version="0.2.0") +metadata(version="0.2.1") module("inspect.py") diff --git a/python-stdlib/inspect/test_inspect.py b/python-stdlib/inspect/test_inspect.py index f5110de70..31650040b 100644 --- a/python-stdlib/inspect/test_inspect.py +++ b/python-stdlib/inspect/test_inspect.py @@ -11,6 +11,22 @@ def gen(): yield 1 +def make_closure(): + a = 1 + b = 2 + def closure(x): + return a + b + x + return closure + + +def make_gen_closure(): + a = 1 + b = 2 + def gen_closure(x): + yield a + b + x + return gen_closure + + class Class: def meth(self): pass @@ -71,3 +87,6 @@ def test_signature(self): 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) + self.assertEqual(len(inspect.signature(gen).parameters), 0) + self.assertEqual(len(inspect.signature(make_closure()).parameters), 1) + self.assertEqual(len(inspect.signature(make_gen_closure()).parameters), 1)