-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[flake8-type-checking
] Add a fix for runtime-string-union
(TC010
)
#15222
base: main
Are you sure you want to change the base?
Conversation
As a side note: I'm not quite sure why some of these fixes are marked as unsafe, even though the union expression doesn't overlap a comment. Do we perhaps have a off-by-one error here? |
|
/// Traverses the type expression and checks if the expression can safely | ||
/// be unquoted | ||
fn quotes_are_removable(semantic: &SemanticModel, expr: &Expr, settings: &LinterSettings) -> bool { | ||
match expr { | ||
Expr::BinOp(ast::ExprBinOp { | ||
left, right, op, .. | ||
}) => { | ||
match op { | ||
Operator::BitOr => { | ||
if settings.target_version < PythonVersion::Py310 { | ||
return false; | ||
} | ||
quotes_are_removable(semantic, left, settings) | ||
&& quotes_are_removable(semantic, right, settings) | ||
} | ||
// for now we'll treat uses of other operators as unremovable quotes | ||
// since that would make it an invalid type expression anyways. We skip | ||
// walking subscript | ||
_ => false, | ||
} | ||
} | ||
Expr::Starred(ast::ExprStarred { | ||
value, | ||
ctx: ExprContext::Load, | ||
.. | ||
}) => quotes_are_removable(semantic, value, settings), | ||
// Subscript or attribute accesses that are valid type expressions may fail | ||
// at runtime, so we have to assume that they do, to keep code working. | ||
Expr::Subscript(_) | Expr::Attribute(_) => false, | ||
Expr::List(ast::ExprList { elts, .. }) | Expr::Tuple(ast::ExprTuple { elts, .. }) => { | ||
for elt in elts { | ||
if !quotes_are_removable(semantic, elt, settings) { | ||
return false; | ||
} | ||
} | ||
true | ||
} | ||
Expr::Name(name) => { | ||
semantic.lookup_symbol(name.id.as_str()).is_none() | ||
|| semantic | ||
.simulate_runtime_load(name, TypingOnlyBindingsStatus::Disallowed) | ||
.is_some() | ||
} | ||
_ => true, | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While there is some code duplication between this and quotes_are_unremovable
, this version is simplified for lookups from a runtime context and needs to use lookup_symbol
instead of resolve_name
since the forward reference has not been traversed yet by the checker.
So I'm torn about whether to merge this with quotes_are_unremovable
into a common function in helpers.rs
and leveraging an enum with two variants to determine whether we can use resolve_name
or need to use lookup_symbol
instead. Alternatively we could try passing in a closure. But both approaches seem kind of messy to me.
We could also say we're fine with the additional overhead of lookup_symbol
over resolve_name
and just always use that.
This is still a work in progress to some degrees. I'm pretty happy with how this behaves, but there's a bit of code duplication, which could potentially be reduced by refactoring after #15201 and #15180 have been merged.
There's also a chance that the fix strategy is currently too opinionated and we should instead rely on the
quote-annotations
(or rather the upcomingquote-type-expressions
) setting to guide us towards which fix strategy we choose and only emit a fix when we know that strategy can be applied safely and otherwise choose to not emit a fix.I'm also not stoked about the complexity of having to parse forward references without the cache in the checker and needing to rely on
lookup_symbol
rather thanresolve_name
, which makes it more difficult to merge the two versions ofquotes_are_removable
back together.Perhaps we can move this check to a different checker stage in order to address some of these problems, although it would become more difficult to merge related fixes.
Perhaps the fix should also only be available in preview because of this.
\cc @MichaReiser
Summary
This adds a fix for
TC010
which removes quotes whenever they can be removed safely and otherwise extends the quotes to the entire union.This also disables
TC010
explicitly in stubs, rather than rely on the execution context, which can still be runtime in stub files for a small set of type expressions.Test Plan
cargo nextest run