Skip to content

Commit

Permalink
Merge pull request #95 from seequent/91-be-pep-561-compliant
Browse files Browse the repository at this point in the history
91 be pep 561 compliant
  • Loading branch information
tim-mitchell authored May 11, 2023
2 parents bf50078 + e0f0bf3 commit cd60c9d
Show file tree
Hide file tree
Showing 11 changed files with 97 additions and 93 deletions.
2 changes: 1 addition & 1 deletion pure_interface/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@
except ImportError:
pass

__version__ = '7.1.0'
__version__ = '7.2.0'
20 changes: 9 additions & 11 deletions pure_interface/adaption.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,16 @@
import functools
import inspect
import types
from typing import Any, Type, Callable
from typing import Any, Type, Callable, Optional
import typing
import warnings

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


def adapts(from_type, to_interface=None):
# type: (Any, Type[PI]) -> Callable[[Any], Any]
def adapts(from_type: Any, to_interface: Optional[Type[AnInterface]] = None) -> Callable[[Any], Any]:
"""Class or function decorator for declaring an adapter from a type to an interface.
E.g.
@adapts(MyClass, MyInterface)
Expand Down Expand Up @@ -47,8 +46,7 @@ def decorator(cls):
return decorator


def register_adapter(adapter, from_type, to_interface):
# type: (Callable, Any, Type[Interface]) -> None
def register_adapter(adapter: Callable, from_type: Type, to_interface: AnInterfaceType) -> None:
""" Registers adapter to convert instances of from_type to objects that provide to_interface
for the to_interface.adapt() method.
Expand Down Expand Up @@ -79,25 +77,25 @@ def __init__(self, mapping_factory=dict):
self._factory = mapping_factory
self._adapters = mapping_factory()

def adapt(self, obj, interface):
def adapt(self, obj: Any, interface: Type[AnInterface]) -> AnInterface:
""" Adapts `obj` to `interface`"""
try:
return self._adapters[interface][obj]
except KeyError:
return self._adapt(obj, interface)

def adapt_or_none(self, obj, interface):
def adapt_or_none(self, obj: Any, interface: Type[AnInterface]) -> Optional[AnInterface]:
""" Adapt obj to interface returning None on failure."""
try:
return self.adapt(obj, interface)
except ValueError:
return None

def clear(self):
def clear(self) -> None:
""" Clears the cached adapters."""
self._adapters = self._factory()

def _adapt(self, obj, interface):
def _adapt(self, obj: Any, interface: Type[AnInterface]) -> AnInterface:
adapted = interface.adapt(obj)
try:
adapters = self._adapters[interface]
Expand All @@ -107,7 +105,7 @@ def _adapt(self, obj, interface):
return adapted


def _interface_from_anno(annotation):
def _interface_from_anno(annotation: Any) -> Optional[AnInterfaceType]:
""" Typically the annotation is the interface, but if a default value of None is given the annotation is
a typing.Union[interface, None] a.k.a. Optional[interface]. Lets be nice and support those too.
"""
Expand Down
2 changes: 1 addition & 1 deletion pure_interface/data_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def _get_interface_annotions(cls):
'match_args', 'kw_only', 'slots', 'weakref_slot')


def dataclass(_cls=None, **kwargs):
def dataclass(_cls: typing.Union[type, None] = None, **kwargs):
"""Returns the same class as was passed in, with dunder methods
added based on the fields defined in the class.
"""
Expand Down
20 changes: 10 additions & 10 deletions pure_interface/delegation.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from __future__ import division, absolute_import, print_function

import operator
from typing import Dict, Union, Sequence, Type, Set, Tuple, Any

import pure_interface
from .errors import InterfaceError
from .interface import get_interface_names, type_is_interface, get_type_interfaces, InterfaceType
from .interface import get_interface_names, type_is_interface, get_type_interfaces, AnInterfaceType, AnInterface

_composed_types_map = {}
_composed_types_map: Dict[Tuple[Type, ...], Type] = {}
_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'


class _Delegated:
def __init__(self, dotted_name):
def __init__(self, dotted_name: str):
self._getter = operator.attrgetter(dotted_name)
self._impl_name, self._attr_name = dotted_name.rsplit('.', 1)

Expand Down Expand Up @@ -111,14 +111,14 @@ def __init__(self, impl):
"""
pi_attr_fallback = None
pi_attr_delegates = {}
pi_attr_mapping = {}
pi_attr_delegates: Dict[str, Union[str, type]] = {}
pi_attr_mapping: Dict[str, Sequence[str]] = {}

def __init_subclass__(cls, **kwargs):
# get non-interface base class ignoring abc.ABC and object.
non_interface_bases = [base for base in cls.mro()[:-2] if not type_is_interface(base)]

def i_have_attribute(attrib):
def i_have_attribute(attrib: str) -> bool:
for klass in non_interface_bases:
if attrib in klass.__dict__:
return True
Expand Down Expand Up @@ -149,7 +149,7 @@ def i_have_attribute(attrib):
setattr(cls, attr, _Delegated(dotted_name))

@classmethod
def provided_by(cls, obj):
def provided_by(cls, obj: Any):
if not hasattr(cls, 'pi_composed_interfaces'):
raise InterfaceError('provided_by() can only be called on composed types')
if isinstance(obj, cls):
Expand All @@ -169,7 +169,7 @@ def __composed_init__(self, *args):
setattr(self, attr, impl)


def composed_type(*interface_types: InterfaceType) -> type:
def composed_type(*interface_types: AnInterfaceType) -> type:
"""Returns a new class which implements all the passed interfaces.
If the interfaces have duplicate attribute or method names, the first enountered implementation is used.
Instances of the returned type are passed implementations of the given interfaces in the same order.
Expand Down Expand Up @@ -200,7 +200,7 @@ class B(IB, object):
if c_type is not None:
return c_type
delegates = {}
all_names = set()
all_names: Set[str] = set()
for i, interface in enumerate(interface_types):
if not type_is_interface(interface):
raise ValueError('all arguments to composed_type must be Interface classes')
Expand Down
Loading

0 comments on commit cd60c9d

Please sign in to comment.