KotlinIsland / KotlinIsland/basedtyping
proper type for the properties on `ReifiedGeneric`
- Dominant language
- Python
- Stars
- 12
- Forks
- 2
- PR merge metrics
- No merged PRs in 30d
Description
ReifiedGenericCopy._can_do_instance_and_subclass_checks_without_generics = ( # pylint:disable=protected-access
https://github.com/KotlinIsland/basedtyping/blob/3945f0c5680f7e35feb1fb1587c0f9a9c7daeb9d/basedtyping/__init__.py#L295
```python
is tracked [here](https://github.com/KotlinIsland/basedmypy/issues/5)
"""
__reified_generics__: tuple[type, ...]
"""Should be a generic but cant due to https://github.com/KotlinIsland/basedmypy/issues/142"""
__type_vars__: tuple[TypeVar, ...]
"""``TypeVar``\\s that have not yet been reified. so this tuple should always be empty by the time the ``ReifiedGeneric`` is instantiated"""
@_tp_cache # type: ignore[name-defined,misc]
def __class_getitem__( # type: ignore[misc]
cls, item: GenericItems
) -> type[ReifiedGeneric[T]]:
# when defining the generic (ie. `class Foo(ReifiedGeneric[T]):`) we want the normal behavior
if cls is ReifiedGeneric:
# https://github.com/KotlinIsland/basedtypeshed/issues/7
return super().__class_getitem__(item) # type: ignore[misc,no-any-return]
items = item if isinstance(item, tuple) else (item,)
# if we're subtyping a class that already has reified generics:
superclass_reified_generics = tuple(
generic
for generic in (
cls.__reified_generics__ if hasattr(cls, "__reified_generics__") else ()
)
if not isinstance(generic, TypeVar) # type: ignore[misc]
)
# normal generics use __parameters__, we use __type_vars__ because the Generic base class deletes properties
# named __parameters__ when copying to a new class
orig_type_vars = (
cls.__type_vars__
if hasattr(cls, "__type_vars__")
else cast(
tuple[TypeVar, ...], cls.__parameters__ # type: ignore[attr-defined]
)
)
# add any reified generics from the superclass if there is one
items = superclass_reified_generics + items
expected_length = len(orig_type_vars)
actual_length = len(items) - len(superclass_reified_generics)
if expected_length != len(items) - len(superclass_reified_generics):
raise NotEnoughTypeParametersError(
"Incorrect number of type parameters specified. expected length:"
f" {expected_length}, actual length {actual_length}"
)
ReifiedGenericCopy: type[ReifiedGeneric[T]] = type(
cls.__name__,
(
cls, # make the copied class extend the original so normal instance checks work
),
# TODO: proper type
dict[str, object](
__reified_generics__=tuple(
_type_convert(t) for t in items # type: ignore[name-defined,misc]
),
_orig_type_vars=orig_type_vars,
__type_vars__=_collect_type_vars( # type: ignore[name-defined,misc]
items, cast(type, TypeVar)
),
),
)
# can't set it in the dict above otherwise __init_subclass__ overwrites it
ReifiedGenericCopy._can_do_instance_and_subclass_checks_without_generics = ( # pylint:disable=protected-access
False
)
return ReifiedGenericCopy
def __init_subclass__(cls) -> None: # pylint:disable=arguments-differ
cls._can_do_instance_and_subclass_checks_without_generics = True
super().__init_subclass__()
# TODO: make this work with any "form", not just unions
```
Contributor guide
No contributing guide indexed for this repository
Research direction
Start in basedtyping/__init__.py around the linked line, where ReifiedGeneric.__class_getitem__ constructs ReifiedGenericCopy with type(). Inspect the class namespace passed to type() and determine the proper type for the currently marked TODO. Done means the construction is accurately typed without that TODO, with the surrounding type-checking expectations still satisfied.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- tooling
- Issue type
- Refactor
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100