Skip to content

Commit

Permalink
Fixes #104.
Browse files Browse the repository at this point in the history
  • Loading branch information
tim-mitchell committed Apr 28, 2024
1 parent cecc6d8 commit f55402e
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 5 deletions.
2 changes: 1 addition & 1 deletion pure_interface/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@
from .adaption import adapts, register_adapter, AdapterTracker, adapt_args
from .delegation import Delegate

__version__ = '8.0.1'
__version__ = '8.0.2'
2 changes: 1 addition & 1 deletion pure_interface/adaption.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import warnings

from .errors import InterfaceError, AdaptionError
from .interface import AnInterface, Interface, InterfaceType, AnInterfaceType, type_is_interface
from .interface import AnInterface, Interface, InterfaceType, type_is_interface
from .interface import get_type_interfaces, get_pi_attribute


Expand Down
14 changes: 11 additions & 3 deletions pure_interface/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from abc import abstractclassmethod, abstractmethod, abstractstaticmethod
import collections
import dis
import functools
import inspect
from inspect import Parameter, signature, Signature
import sys
Expand Down Expand Up @@ -382,16 +383,21 @@ def _ensure_everything_is_abstract(attributes):
func = value.__func__
functions.append(func)
interface_method_signatures[name] = signature(func)
value = abstractstaticmethod(func)
value = staticmethod(abstractmethod(func))
elif isinstance(value, classmethod):
func = value.__func__
interface_method_signatures[name] = signature(func)
functions.append(func)
value = abstractclassmethod(func)
value = classmethod(abstractmethod(func))
elif isinstance(value, types.FunctionType):
functions.append(value)
interface_method_signatures[name] = signature(value)
value = abstractmethod(value)
elif isinstance(value, functools.singledispatchmethod):
func = value.func
functions.append(func)
interface_method_signatures[name] = signature(func)
value = func # ignore the singledispatchmethod decorator
elif isinstance(value, property):
interface_attribute_names.append(name)
functions.extend([value.fget, value.fset, value.fdel]) # may contain Nones
Expand Down Expand Up @@ -422,13 +428,15 @@ def _check_method_signatures(attributes, clsname, interface_method_signatures):
if name not in attributes:
continue
value = attributes[name]
if not isinstance(value, (staticmethod, classmethod, types.FunctionType)):
if not isinstance(value, (staticmethod, classmethod, types.FunctionType, functools.singledispatchmethod)):
if _is_descriptor(value):
continue
else:
raise InterfaceError('Interface method over-ridden with non-method')
if isinstance(value, (staticmethod, classmethod)):
func = value.__func__
elif isinstance(value, functools.singledispatchmethod):
func = value.func
else:
func = value
func_sig = signature(func)
Expand Down
28 changes: 28 additions & 0 deletions tests/test_singledispatch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from functools import singledispatchmethod
from typing import Any
import unittest

import pure_interface


class TestSingleDispatch(unittest.TestCase):
def test_single_dispatch_allowed(self):
class IPerson(pure_interface.Interface):
@singledispatchmethod
def greet(self, other_person: Any) -> str:
pass

self.assertSetEqual(pure_interface.get_interface_method_names(IPerson), {'greet'})

def test_single_dispatch_checked(self):
class IPerson(pure_interface.Interface):
def greet(self) -> str:
pass

pure_interface.set_is_development(True)
with self.assertRaises(pure_interface.InterfaceError):
class Person(IPerson):
@singledispatchmethod
def greet(self, other_person: Any) -> str:
pass

0 comments on commit f55402e

Please sign in to comment.