117
117
118
118
from abc import get_cache_token
119
119
from functools import _find_impl # type: ignore # noqa: WPS450
120
+ from types import MethodType
120
121
from typing import ( # noqa: WPS235
121
122
TYPE_CHECKING ,
122
123
Callable ,
@@ -499,6 +500,8 @@ def instance(
499
500
self ,
500
501
type_argument : Optional [_NewInstanceType ],
501
502
* ,
503
+ # TODO: at one point I would like to remove `is_protocol`
504
+ # and make this function decide whether this type is protocol or not.
502
505
is_protocol : bool = False ,
503
506
) -> '_TypeClassInstanceDef[_NewInstanceType, _TypeClassType]' :
504
507
"""
@@ -507,21 +510,26 @@ def instance(
507
510
The only setting we provide is ``is_protocol`` which is required
508
511
when passing protocols. See our ``mypy`` plugin for that.
509
512
"""
510
- if type_argument is None : # `None` is a special case
511
- type_argument = type (None ) # type: ignore
513
+ typ = type_argument or type (None ) # `None` is a special case
512
514
513
515
# That's how we check for generics,
514
516
# generics that look like `List[int]` or `set[T]` will fail this check,
515
517
# because they are `_GenericAlias` instance,
516
518
# which raises an exception for `__isinstancecheck__`
517
- isinstance (object (), type_argument ) # type: ignore
519
+ isinstance (object (), typ )
518
520
519
521
def decorator (implementation ):
520
522
container = self ._protocols if is_protocol else self ._instances
521
- container [type_argument ] = implementation # type: ignore
523
+ container [typ ] = implementation
524
+
525
+ if isinstance (getattr (typ , '__instancecheck__' , None ), MethodType ):
526
+ # This means that this type has `__instancecheck__` defined,
527
+ # which allows dynamic checks of what `isinstance` of this type.
528
+ # That's why we also treat this type as a protocol.
529
+ self ._protocols [typ ] = implementation
522
530
523
531
if self ._cache_token is None : # pragma: no cover
524
- if getattr (type_argument , '__abstractmethods__' , None ):
532
+ if getattr (typ , '__abstractmethods__' , None ):
525
533
self ._cache_token = get_cache_token ()
526
534
527
535
self ._dispatch_cache .clear ()
0 commit comments