I think it makes sense to specify what’s allowed here.
Even though my personal preference would be to disallow triple quoted strings for type annotations entirely in favor of parenthesized string segments split over multiple lines, that sort of preference feels more like a style guideline, so in the realm of linters.
I think pyright’s current behavior is definitely the most user-friendly, it’s not that hard to write a parser for it either, in fact just statically wrapping the expression in parentheses before parsing it should always result in a valid expression that can be parsed by the regular Python parser, but there’s of course other fairly simple algorithms to convert it to a single line annotation.
IMO multiline annotations should be supported. A collection of callable types that can be vertically aligned would be much more readable.
It seems a bit silly to differ here, but if standardization is hard, having a common line on what to do when you want multiline annotations seems good.
A simple “standard” would be “whitespace in annotation strings is not significant”, so normalization could just be re.sub("\w+", " ", annotation).
Since this is something that users will try, I think this should be standardized. pyright’s interpretation seems sensible to me, although I’d slightly prefer triple quoted to be just disallowed. Quoted annotations are a bit of a dated concept anyway, thanks to PEP 563 and its eventual successor, and the only mention of quotes in the typing spec is this sentence:
(Note that the type annotation must be enclosed in quotes, making it a “forward reference”, to hide the expensive_mod reference from the interpreter runtime. In the variable annotation no quotes are needed.)
Exactly the same as they would be in an unquoted annotation. Because quoting an annotation is “simply” a way to hide it from the runtime, which might not support the constructs being used. I say this, but I was unable to find the specification for what quoting annotations means - if someone can point me to the actual spec, I’ll read it and see if that changes my view. But in the absence of an explicit statement that quoted annotations behave differently, I’d expect exactly the same behaviour, quoted or not.
And even if there is something explicit, I’d question whether it’s the right thing to do - having special cases like that which violate reasonable user expectations are just another situation where we end up making typing rules harder than they need to be, for no particular user benefit.
If we standardise this, maybe we could specify this as follows:
Quoted type annotations should be parsed as if surrounded by parentheses.
My general inclination with the spec is to avoid forbidding things that are unambiguous and not too costly, even if somewhat niche (like this).
Exactly the same as they would be in an unquoted annotation.
Technically it’s not quite clear what this would mean. If you literally just removed the quotes in Eric’s example, you get a SyntaxError. It’s not unreasonable to view the quotes as parentheses-like in this context, which mirrors my proposed wording above.
If user’s expectations are for triple-quoted expressions to be treated exactly like if there were no quotes at all, then automatically wrapping doesn’t break anything, user can still additionally wrap their expression in parentheses. For other users, automatic parentheses are simply convenient.
I agree it’s good to standardize this, as it’s an area where type checkers are otherwise likely to diverge, but where users wouldn’t expect what they’re doing to only work on one type checker.
And pyright’s behavior of implicit parenthesization seems like the most sensible approach, so I would support standardizing to that behavior.
PEP 563/649 will definitely make quoted annotations less prevalent, but there will still be contexts where you need them, e.g. the argument to cast(). It’s a good general goal to make it so that quoted annotations are only rarely necessary, but for now, they’re here to stay, and we should specify their behavior well.