diff options
-rw-r--r-- | funcsigs/__init__.py | 16 | ||||
-rw-r--r-- | tests/test_funcsigs.py | 13 |
2 files changed, 26 insertions, 3 deletions
diff --git a/funcsigs/__init__.py b/funcsigs/__init__.py index b9ba326..7dbe0dc 100644 --- a/funcsigs/__init__.py +++ b/funcsigs/__init__.py @@ -59,10 +59,20 @@ def signature(obj): raise TypeError('{0!r} is not a callable object'.format(obj)) if isinstance(obj, types.MethodType): - # In this case we skip the first parameter of the underlying - # function (usually `self` or `cls`). sig = signature(obj.__func__) - return sig.replace(parameters=tuple(sig.parameters.values())[1:]) + if obj.__self__ is None: + # Unbound method: the first parameter becomes positional-only + if sig.parameters: + first = sig.parameters.values()[0].replace( + kind=_POSITIONAL_ONLY) + return sig.replace(parameters=itertools.chain( + (first,), tuple(sig.parameters.values())[1:])) + else: + return sig + else: + # In this case we skip the first parameter of the underlying + # function (usually `self` or `cls`). + return sig.replace(parameters=tuple(sig.parameters.values())[1:]) try: sig = obj.__signature__ diff --git a/tests/test_funcsigs.py b/tests/test_funcsigs.py index c904caf..227131f 100644 --- a/tests/test_funcsigs.py +++ b/tests/test_funcsigs.py @@ -70,6 +70,19 @@ class TestFunctionSignatures(unittest.TestCase): def test_readme(self): doctest.testfile('../README.rst') + def test_unbound_method(self): + class Test(object): + def method(self): + pass + def method_with_args(self, a): + pass + self.assertEqual(self.signature(Test.method), + (((('self', Ellipsis, Ellipsis, "positional_only")),), Ellipsis)) + self.assertEqual(self.signature(Test.method_with_args), (( + ('self', Ellipsis, Ellipsis, "positional_only"), + ('a', Ellipsis, Ellipsis, "positional_or_keyword"), + ), Ellipsis)) + if __name__ == "__main__": unittest.begin() |