Merge pull request #3 from epsy/unbound
Fixed unbound methods getting their first parameter curried
Ensures the the 'self' argument of methods on un-instantiated classes appear in the function signature on both Python2 and Python3. Also ensures self is identified correctly as a positional-only parameter.
diff --git a/funcsigs/__init__.py b/funcsigs/__init__.py
index b9ba326..fd2f47b 100644
--- a/funcsigs/__init__.py
+++ b/funcsigs/__init__.py
@@ -59,10 +59,20 @@
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=(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..eecc0a8 100644
--- a/tests/test_funcsigs.py
+++ b/tests/test_funcsigs.py
@@ -6,6 +6,7 @@
import unittest
import doctest
+import sys
import funcsigs as inspect
@@ -70,6 +71,23 @@
def test_readme(self):
doctest.testfile('../README.rst')
+ def test_unbound_method(self):
+ if sys.version_info < (3,):
+ self_kind = "positional_only"
+ else:
+ self_kind = "positional_or_keyword"
+ class Test(object):
+ def method(self):
+ pass
+ def method_with_args(self, a):
+ pass
+ self.assertEqual(self.signature(Test.method),
+ (((('self', Ellipsis, Ellipsis, self_kind)),), Ellipsis))
+ self.assertEqual(self.signature(Test.method_with_args), ((
+ ('self', Ellipsis, Ellipsis, self_kind),
+ ('a', Ellipsis, Ellipsis, "positional_or_keyword"),
+ ), Ellipsis))
+
if __name__ == "__main__":
unittest.begin()