Skip to content

Commit

Permalink
Merge pull request #3 from epsy/unbound
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
aliles committed Oct 16, 2013
2 parents 59ab8ac + 50d63cb commit 769506e
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 3 deletions.
16 changes: 13 additions & 3 deletions funcsigs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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=(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__
Expand Down
18 changes: 18 additions & 0 deletions tests/test_funcsigs.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import unittest

import doctest
import sys

import funcsigs as inspect

Expand Down Expand Up @@ -70,6 +71,23 @@ def test_has_version(self):
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()

0 comments on commit 769506e

Please sign in to comment.