From 6511ba63edc00887b4fb8ab06e89fef19e53276f Mon Sep 17 00:00:00 2001 From: Tim Mitchell Date: Wed, 22 Sep 2021 14:53:05 +1200 Subject: [PATCH] #83: Add special handling for __call__ to interface_only(). --- pure_interface.py | 2 ++ tests/test_adaption.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/pure_interface.py b/pure_interface.py index be09b8b..237f1a0 100644 --- a/pure_interface.py +++ b/pure_interface.py @@ -629,6 +629,8 @@ def interface_only(cls, implementation): if cls._pi.impl_wrapper_type is None: type_name = '_{}Only'.format(cls.__name__) attributes = {'__module__': cls.__module__} + if '__call__' in cls._pi.interface_names: + attributes['__call__'] = getattr(implementation, '__call__') cls._pi.impl_wrapper_type = type(type_name, (_ImplementationWrapper,), attributes) abc.ABCMeta.register(cls, cls._pi.impl_wrapper_type) return cls._pi.impl_wrapper_type(implementation, cls) diff --git a/tests/test_adaption.py b/tests/test_adaption.py index bea4d45..b53b859 100644 --- a/tests/test_adaption.py +++ b/tests/test_adaption.py @@ -114,6 +114,23 @@ def speak(self, volume): super(SleepTalker, self).speak(volume) +class DunderInterface(pure_interface.Interface): + def __call__(self, a): + pass + + def __len__(self): + pass + + +class DunderClass(DunderInterface, object): + + def __call__(self, a): + super().__call__(a) + + def __len__(self): + return 5 + + class TestAdaption(unittest.TestCase): @classmethod def setUpClass(cls): @@ -350,3 +367,16 @@ def test_adapt_interface_only(self): ISpeaker.adapt(talker_only) except: self.fail('adaption of interface only failed.') + + def test_adapt_callable_is_callable(self): + dunder = DunderClass() + dunder_only = DunderInterface.adapt(dunder) + try: + dunder_only(1) + except TypeError: + self.fail('calling interface only failed') + + try: + len(dunder) + except: + self.fail('len() interface only failed')