astral-sh / ruff

An extremely fast Python linter and code formatter, written in Rust.

Home Page:https://docs.astral.sh/ruff

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Ruff unconditionally assumes any string in a type parameter is a forward annotation

lanzz opened this issue · comments

I have an alias for Annotated, to be used in a container class:

class Container:
    # class that inspects its type annotations at runtime and does stuff with them

Field = typing.Annotated

class MyContainer(Container):
    foo_field: Field[int, 'metadata']    # ruff raises F281 "Undefined name `metadata` here
    bar_field: Field[str, 'not a valid identifier']   # ruff raises F722 "Syntax error in forward annotation" here
    foo_ann: typing.Annotated[int, 'metadata']    # no complaints here
    bar_ann: typing.Annotated[str, 'not a valid identifier']   # no complaints here either

Ultimately, the Field alias is just sugar to make the definitions of subclasses of Container better self-documenting. I understand this is a pretty niche use and it's very likely not feasible for Ruff to figure out that Field is alias for Annotated (especially since in practice that alias definition is in a completely different module), but is there a way to explicitly instruct Ruff to treat those instances of Field the same way it treats actual Annotated type definitions, without having to suppress the rule explicitly on every single line that uses Field? If I could define ignores by line regex that would work (e.g. ignore F281, F722 for lines matching :\s+Field\[), but I don't think Ruff supports that, or at least I could not find it in the docs.

I don't know that we have a great workaround here right now. If we can't resolve a symbol, and it's subscripted in an annotation, we do assume that any strings within the subscript are forward annotations, since they're almost always generics.

I suspect this will eventually "just work" as we're doing a lot of foundational work right now to make Ruff capable of this kind of inference. But in the interim, struggling to think of anything other than adding # ruff: noqa: F281, F722 to the file.