1818 cast ,
1919)
2020
21- from typing_extensions import Final , TypeAlias , TypeGuard
21+ from typing_extensions import Final , Self , TypeAlias , TypeGuard
2222
2323from basedtyping .runtime_only import OldUnionType
2424
@@ -42,6 +42,7 @@ def __repr__(self):
4242 def __getitem__ (self , item ):
4343 if self ._name == "Intersection" :
4444 return _IntersectionGenericAlias (self , item )
45+ return None
4546
4647
4748if TYPE_CHECKING :
@@ -60,7 +61,7 @@ def __getitem__(self, item):
6061
6162T = TypeVar ("T" )
6263T_co = TypeVar ("T_co" , covariant = True )
63- T_cont = TypeVar ("T_cont " , contravariant = True )
64+ T_contra = TypeVar ("T_contra " , contravariant = True )
6465Fn = TypeVar ("Fn" , bound = Function )
6566
6667
@@ -108,7 +109,7 @@ class NotEnoughTypeParametersError(ReifiedGenericError):
108109 """
109110
110111
111- class _ReifiedGenericMetaclass (type ):
112+ class _ReifiedGenericMetaclass (type , Generic [ T ] ):
112113 # these should really only be on the class not the metaclass, but since it needs to be accessible from both instances and the class itself, its duplicated here
113114
114115 __reified_generics__ : Tuple [type , ...]
@@ -124,7 +125,7 @@ class _ReifiedGenericMetaclass(type):
124125 _can_do_instance_and_subclass_checks_without_generics : bool
125126 """Used internally for ``isinstance`` and ``issubclass`` checks, ``True`` when the class can currenty be used in said checks without generics in them"""
126127
127- def _orig_class (cls ) -> _ReifiedGenericMetaclass :
128+ def _orig_class (cls ) -> _ReifiedGenericMetaclass [ T ] :
128129 """Gets the original class that ``ReifiedGeneric.__class_getitem__`` copied from
129130 """
130131 result = cls .__bases__ [0 ]
@@ -174,20 +175,20 @@ def _check_generics_reified(cls) -> None:
174175 if not cls ._generics_are_reified () or cls ._has_non_reified_type_vars ():
175176 cls ._raise_generics_not_reified ()
176177
177- def _is_subclass (cls , subclass : object ) -> TypeGuard [_ReifiedGenericMetaclass ]:
178+ def _is_subclass (cls , subclass : object ) -> TypeGuard [_ReifiedGenericMetaclass [ T ] ]:
178179 """For ``__instancecheck__`` and ``__subclasscheck__``. checks whether the
179180 "origin" type (ie. without the generics) is a subclass of this reified generic
180181 """
181182 # could be any random instance, check it's a reified generic first:
182- return type .__instancecheck__ ( # type: ignore[no-any-expr]
183- _ReifiedGenericMetaclass , # type: ignore[no-any-expr]
183+ return type .__instancecheck__ (
184+ _ReifiedGenericMetaclass ,
184185 subclass ,
185186 # then check that the instance is an instance of this particular reified generic:
186- ) and type .__subclasscheck__ ( # type: ignore[no-any-expr]
187+ ) and type .__subclasscheck__ (
187188 cls ._orig_class (),
188189 # https://github.com/python/mypy/issues/11671
189190 cast ( # pylint:disable=protected-access
190- _ReifiedGenericMetaclass , subclass
191+ _ReifiedGenericMetaclass [ T ] , subclass
191192 )._orig_class (),
192193 )
193194
@@ -219,7 +220,7 @@ def __instancecheck__(cls, instance: object) -> bool:
219220 cast (ReifiedGeneric [object ], instance ).__reified_generics__
220221 )
221222
222- def __call__ (cls , * args : object , ** kwargs : object ) -> object :
223+ def __call__ (cls , * args : object , ** kwargs : object ) -> T :
223224 """A placeholder ``__call__`` method that gets called when the class is
224225 instantiated directly, instead of first supplying the type parameters.
225226 """
@@ -240,22 +241,27 @@ def __call__(cls, *args: object, **kwargs: object) -> object:
240241 "foo = Foo[int]() # correct"
241242 )
242243 cls ._check_generics_reified ()
243- return super ().__call__ (* args , ** kwargs ) # type: ignore[no-any-expr]
244+ return cast ( T , super ().__call__ (* args , ** kwargs ))
244245
245246
246247GenericItems : TypeAlias = Union [type , TypeVar , Tuple [Union [type , TypeVar ], ...]]
247248"""The ``items`` argument passed to ``__class_getitem__`` when creating or using a ``Generic``"""
248249
249250
250- class ReifiedGeneric (Generic [T ], metaclass = _ReifiedGenericMetaclass ):
251+ class ReifiedGeneric (
252+ Generic [T ],
253+ # mypy doesn't support metaclasses with generics but for pyright we need to correctly type the `__call__`
254+ # return type, otherwise all instances of `ReifiedGeneric` will have the wrong type
255+ metaclass = _ReifiedGenericMetaclass [Self ], # type:ignore[misc]
256+ ):
251257 """A ``Generic`` where the type parameters are available at runtime and is
252258 usable in ``isinstance`` and ``issubclass`` checks.
253259
254260 For example:
255261
256262 >>> class Foo(ReifiedGeneric[T]):
257263 ... def create_instance(self) -> T:
258- ... cls = self.__orig_class__.__args__ [0]
264+ ... cls = self.__reified_generics__ [0]
259265 ... return cls()
260266 ...
261267 ... foo: Foo[int] = Foo() # error: generic cannot be reified
@@ -310,9 +316,7 @@ def __class_getitem__( # type: ignore[no-any-decorated]
310316 orig_type_vars = (
311317 cls .__type_vars__
312318 if hasattr (cls , "__type_vars__" )
313- else cast (
314- Tuple [TypeVar , ...], cls .__parameters__ # type: ignore[attr-defined]
315- )
319+ else cast (Tuple [TypeVar , ...], cls .__parameters__ )
316320 )
317321
318322 # add any reified generics from the superclass if there is one
@@ -330,13 +334,13 @@ def __class_getitem__( # type: ignore[no-any-decorated]
330334 cls , # make the copied class extend the original so normal instance checks work
331335 ),
332336 # TODO: proper type
333- dict ( # type: ignore[no-any-expr]
334- __reified_generics__ = tuple ( # type: ignore[no-any-expr]
337+ { # type: ignore[no-any-expr]
338+ " __reified_generics__" : tuple ( # type: ignore[no-any-expr]
335339 _type_convert (t ) for t in items # type: ignore[unused-ignore, no-any-expr]
336340 ),
337- _orig_type_vars = orig_type_vars ,
338- __type_vars__ = _collect_parameters (items ), # type: ignore[name-defined]
339- ) ,
341+ " _orig_type_vars" : orig_type_vars ,
342+ " __type_vars__" : _collect_parameters (items ), # type: ignore[name-defined]
343+ } ,
340344 )
341345 # can't set it in the dict above otherwise __init_subclass__ overwrites it
342346 ReifiedGenericCopy ._can_do_instance_and_subclass_checks_without_generics = ( # pylint:disable=protected-access
@@ -358,6 +362,7 @@ def __init_subclass__(cls) -> None: # pylint:disable=arguments-differ
358362 _UnionTypes = (OldUnionType ,)
359363 _Forms : TypeAlias = Union [type , _SpecialForm ]
360364
365+
361366# TODO: make this work with any "form", not just unions
362367# should be (form: TypeForm, forminfo: TypeForm)
363368# TODO: form/forminfo can include _UnionGenericAlias
@@ -416,7 +421,8 @@ def Untyped(self: _SpecialForm, parameters: object) -> NoReturn:
416421 raise TypeError (f"{ self } is not subscriptable" )
417422
418423 else :
419- Untyped : Final = _BasedSpecialForm (
424+ # old version had the doc argument
425+ Untyped : Final = _BasedSpecialForm ( # pylint:disable=unexpected-keyword-arg
420426 "Untyped" ,
421427 doc = (
422428 "Special type indicating that something isn't typed.\n This is more"
@@ -427,8 +433,8 @@ def Untyped(self: _SpecialForm, parameters: object) -> NoReturn:
427433if not TYPE_CHECKING :
428434
429435 class _IntersectionGenericAlias (_GenericAlias , _root = True ):
430- def copy_with (self , params ):
431- return Intersection [params ]
436+ def copy_with (self , args ):
437+ return Intersection [args ]
432438
433439 def __eq__ (self , other ):
434440 if not isinstance (other , _IntersectionGenericAlias ):
@@ -445,9 +451,10 @@ def __subclasscheck__(self, cls):
445451 for arg in self .__args__ :
446452 if issubclass (cls , arg ):
447453 return True
454+ return False
448455
449456 def __reduce__ (self ):
450- func , (origin , args ) = super ().__reduce__ ()
457+ func , (_ , args ) = super ().__reduce__ ()
451458 return func , (Intersection , args )
452459
453460 if sys .version_info > (3 , 9 ):
@@ -494,6 +501,9 @@ def Intersection(self, parameters):
494501 return _IntersectionGenericAlias (self , parameters )
495502
496503 else :
497- Intersection = _BasedSpecialForm ("Intersection" , doc = "" )
504+ # old version had the doc argument
505+ Intersection = _BasedSpecialForm ( # pylint:disable=unexpected-keyword-arg
506+ "Intersection" , doc = ""
507+ )
498508else :
499509 Intersection : _SpecialForm
0 commit comments