Skip to content

Feature: Implement GenericCallable[Vs, lambda <vs>: Ty] #21

@AliiiBenn

Description

@AliiiBenn

Description

Implement the GenericCallable[Vs, lambda <vs>: Ty] type as specified in PEP 827.

From the PEP:

GenericCallable[Vs, lambda <vs>: Ty]: A generic callable. Vs are a tuple type of unbound type variables and Ty should be a Callable, staticmethod, or classmethod that has access to the variables in Vs via the bound variables in <vs>.

For now, we restrict the use of GenericCallable to the type argument of Member, to disallow its use for locals, parameter types, return types, nested inside other types, etc.

Implementation Notes

Current State

The GenericCallable class is already defined in typing.py:

class GenericCallable:
    def __class_getitem__(cls, params):
        message = (
            "GenericCallable must be used as "
            "GenericCallable[tuple[TypeVar, ...], lambda <vs>: callable]."
        )
        if not isinstance(params, tuple) or len(params) != 2:
            raise TypeError(message)

        typevars, func = params
        if not callable(func):
            raise TypeError(message)

        return _GenericCallableGenericAlias(cls, (typevars, func))

However, there is no evaluator registered for it.

Approach

The evaluator would need to:

  1. Parse the typevars tuple to extract TypeVar instances
  2. Evaluate the lambda with the typevars bound
  3. Return the resulting callable type
@type_eval.register_evaluator(GenericCallable)
def _eval_GenericCallable(typevars, func, *, ctx):
    """Evaluate a GenericCallable type.
    
    Args:
        typevars: A tuple of TypeVar instances
        func: A lambda that uses the typevars
        
    Returns:
        A callable type with the typevars resolved
    """
    # This is complex because we need to:
    # 1. Extract the typevars from the tuple
    # 2. Create a closure that binds them
    # 3. Evaluate the lambda in that context
    # 4. Return the resulting type
    pass

Use Case

This is primarily used for generating method signatures that are generic over type variables, such as:

type InitFn[T] = typing.Member[
    Literal["__init__"],
    GenericCallable[
        tuple[T],
        lambda T: Callable[[Self, T], None]
    ],
    Literal["ClassVar"],
]

Test Cases

  • Basic GenericCallable with single TypeVar
  • GenericCallable with multiple TypeVars
  • Used within Member type argument

Status

  • Analyze existing GenericCallable implementation
  • Implement evaluator in _eval_operators.py
  • Add tests
  • Update documentation

Related PEP 827 Section: Generic Callable (lines 739-747)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions