LibCST icon indicating copy to clipboard operation
LibCST copied to clipboard

`FlattenSentinel` can't be used as return type annotation

Open Viicos opened this issue 1 year ago • 1 comments

Consider the following code:

MATCHER = m.FunctionDef(name=m.Name("__init__"))

class MyVisitor(...):
    ...
    @m.leave(MATCHER)
    def mutate_init(
        self,
        original_node: cst.FunctionDef,
        updated_node: cst.FunctionDef
    ) -> cst.FlattenSentinel[cst.FunctionDef]:
        ...

This raises the following exception: TypeError: issubclass() arg 1 must be a class

https://github.com/Instagram/LibCST/blob/43a27b1222993f29086748ef6a08a57801c536aa/libcst/matchers/_visitors.py#L155-L157

Here, ret is cst.FlattenSentinel[cst.FunctionDef] (an instance of GenericAlias), annotation is libcst._nodes.statement.BaseStatement.

~~Works as expected without parametrizing the class~~

Edit: Fails at runtime as well without parametrizing the class:

libcst.matchers._visitors.MatchDecoratorMismatch: Invalid function signature for ForwardRelationOverloadCodemod.mutate_ManyToManyField_FunctionDef: @leave decorated function cannot return the type FlattenSentinel.

Tbh this runtime check of the return annotation is a bit surprising: type hints are not supposed to alter the run time behavior (except when explicitly advertised as is, e.g. like pydantic). It might be worth adding a try..except on this check, and only reraise if the exception is an instance of MatchDecoratorMismatch.

Viicos avatar Dec 24 '23 15:12 Viicos