7272We also support protocols. It has the same limitation as ``Generic`` types.
7373It is also dispatched after all regular instances are checked.
7474
75- To work with protocols, one needs to pass ``is_protocol`` flag to instance:
75+ To work with protocols, one needs
76+ to pass ``protocol`` named argument to instance:
7677
7778.. code:: python
7879
7980 >>> from typing import Sequence
8081
81- >>> @example.instance(Sequence, is_protocol=True )
82+ >>> @example.instance(protocol=Sequence )
8283 ... def _sequence_example(instance: Sequence) -> str:
8384 ... return ','.join(str(item) for item in instance)
8485
99100 >>> class CustomProtocol(Protocol):
100101 ... field: str
101102
102- >>> @example.instance(CustomProtocol, is_protocol=True )
103+ >>> @example.instance(protocol=CustomProtocol )
103104 ... def _custom_protocol_example(instance: CustomProtocol) -> str:
104105 ... return instance.field
105106
131132from typing_extensions import TypeGuard , final
132133
133134from classes ._registry import (
135+ DefaultValue ,
134136 TypeRegistry ,
135137 choose_registry ,
136138 default_implementation ,
@@ -313,7 +315,7 @@ class _TypeClass( # noqa: WPS214
313315
314316 # Registry:
315317 '_delegates' ,
316- '_instances ' ,
318+ '_exact_types ' ,
317319 '_protocols' ,
318320
319321 # Cache:
@@ -362,7 +364,7 @@ def __init__(
362364
363365 # Registries:
364366 self ._delegates : TypeRegistry = {}
365- self ._instances : TypeRegistry = {}
367+ self ._exact_types : TypeRegistry = {}
366368 self ._protocols : TypeRegistry = {}
367369
368370 # Cache parts:
@@ -382,8 +384,9 @@ def __call__(
382384
383385 The resolution order is the following:
384386
385- 1. Exact types that are passed as ``.instance`` arguments
386- 2. Protocols that are passed with ``is_protocol=True``
387+ 1. Delegates passed with ``delegate=``
388+ 2. Exact types that are passed as ``.instance`` arguments
389+ 3. Protocols that are passed with ``protocol=``
387390
388391 We don't guarantee the order of types inside groups.
389392 Use correct types, do not rely on our order.
@@ -480,7 +483,7 @@ def supports(
480483
481484 >>> from typing import Sized
482485
483- >>> @example.instance(Sized, is_protocol=True )
486+ >>> @example.instance(protocol=Sized )
484487 ... def _example_sized(instance: Sized) -> str:
485488 ... return 'Size is {0}'.format(len(instance))
486489
@@ -523,18 +526,16 @@ def supports(
523526
524527 def instance (
525528 self ,
526- type_argument : Optional [_NewInstanceType ],
529+ exact_type : Optional [_NewInstanceType ] = DefaultValue , # type: ignore
527530 * ,
528- # TODO: at one point I would like to remove `is_protocol`
529- # and make this function decide whether this type is protocol or not.
530- is_protocol : bool = False ,
531- delegate : Optional [type ] = None ,
531+ protocol : type = DefaultValue ,
532+ delegate : type = DefaultValue ,
532533 ) -> '_TypeClassInstanceDef[_NewInstanceType, _TypeClassType]' :
533534 """
534535 We use this method to store implementation for each specific type.
535536
536537 Args:
537- is_protocol : required when passing protocols.
538+ protocol : required when passing protocols.
538539 delegate: required when using delegate types, for example,
539540 when working with concrete generics like ``List[str]``.
540541
@@ -543,7 +544,8 @@ def instance(
543544
544545 .. note::
545546
546- ``is_protocol`` and ``delegate`` are mutually exclusive.
547+ ``exact_type``, ``protocol``, and ``delegate``
548+ are mutually exclusive. Only one argument can be passed.
547549
548550 We don't use ``@overload`` decorator here
549551 (which makes our ``mypy`` plugin even more complex)
@@ -558,7 +560,14 @@ def instance(
558560 # Then, we have a regular `type_argument`. It is used for most types.
559561 # Lastly, we have `type(None)` to handle cases
560562 # when we want to register `None` as a type / singleton value.
561- typ = delegate or type_argument or type (None )
563+ registry , typ = choose_registry (
564+ exact_type = exact_type ,
565+ protocol = protocol ,
566+ delegate = delegate ,
567+ exact_types = self ._exact_types ,
568+ protocols = self ._protocols ,
569+ delegates = self ._delegates ,
570+ )
562571
563572 # That's how we check for generics,
564573 # generics that look like `List[int]` or `set[T]` will fail this check,
@@ -567,19 +576,9 @@ def instance(
567576 isinstance (object (), typ )
568577
569578 def decorator (implementation ):
570- container = choose_registry (
571- typ = typ ,
572- is_protocol = is_protocol ,
573- delegate = delegate ,
574- delegates = self ._delegates ,
575- instances = self ._instances ,
576- protocols = self ._protocols ,
577- )
578- container [typ ] = implementation
579-
579+ registry [typ ] = implementation
580580 self ._dispatch_cache .clear ()
581581 return implementation
582-
583582 return decorator
584583
585584 def _dispatch (self , instance , instance_type : type ) -> Optional [Callable ]:
@@ -591,15 +590,15 @@ def _dispatch(self, instance, instance_type: type) -> Optional[Callable]:
591590 2. By matching protocols
592591 3. By its ``mro``
593592 """
594- implementation = self ._instances .get (instance_type , None )
593+ implementation = self ._exact_types .get (instance_type , None )
595594 if implementation is not None :
596595 return implementation
597596
598597 for protocol , callback in self ._protocols .items ():
599598 if isinstance (instance , protocol ):
600599 return callback
601600
602- return _find_impl (instance_type , self ._instances )
601+ return _find_impl (instance_type , self ._exact_types )
603602
604603 def _dispatch_delegate (self , instance ) -> Optional [Callable ]:
605604 for delegate , callback in self ._delegates .items ():
0 commit comments