Skip to content

proper type for the properties on ReifiedGeneric #39

Open
@github-actions

Description

@github-actions

ReifiedGenericCopy._can_do_instance_and_subclass_checks_without_generics = ( # pylint:disable=protected-access

# TODO: proper type

    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

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions