[flake8-type-checking] Improve flexibility of runtime-evaluated-decorators (#15204)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
David Salvisberg 2024-12-31 17:28:10 +01:00 committed by GitHub
parent 7ca3f9515c
commit 1ef0f615f1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 192 additions and 10 deletions

View file

@ -24,6 +24,7 @@ is-macro = { workspace = true }
rustc-hash = { workspace = true }
schemars = { workspace = true, optional = true }
serde = { workspace = true, optional = true }
smallvec = { workspace = true }
[dev-dependencies]
ruff_python_parser = { workspace = true }

View file

@ -11,6 +11,7 @@ use ruff_python_stdlib::typing::{
is_typed_dict, is_typed_dict_member,
};
use ruff_text_size::Ranged;
use smallvec::{smallvec, SmallVec};
use crate::analyze::type_inference::{NumberLike, PythonType, ResolvedPythonType};
use crate::model::SemanticModel;
@ -983,23 +984,43 @@ fn find_parameter<'a>(
/// ```
///
/// This function will return `["asyncio", "get_running_loop"]` for the `loop` binding.
///
/// This function will also automatically expand attribute accesses, so given:
/// ```python
/// from module import AppContainer
///
/// container = AppContainer()
/// container.app.get(...)
/// ```
///
/// This function will return `["module", "AppContainer", "app", "get"]` for the
/// attribute access `container.app.get`.
pub fn resolve_assignment<'a>(
expr: &'a Expr,
semantic: &'a SemanticModel<'a>,
) -> Option<QualifiedName<'a>> {
let name = expr.as_name_expr()?;
// Resolve any attribute chain.
let mut head_expr = expr;
let mut reversed_tail: SmallVec<[_; 4]> = smallvec![];
while let Expr::Attribute(ast::ExprAttribute { value, attr, .. }) = head_expr {
head_expr = value;
reversed_tail.push(attr.as_str());
}
// Resolve the left-most name, e.g. `foo` in `foo.bar.baz` to a qualified name,
// then append the attributes.
let name = head_expr.as_name_expr()?;
let binding_id = semantic.resolve_name(name)?;
let statement = semantic.binding(binding_id).statement(semantic)?;
match statement {
Stmt::Assign(ast::StmtAssign { value, .. }) => {
let ast::ExprCall { func, .. } = value.as_call_expr()?;
semantic.resolve_qualified_name(func)
}
Stmt::AnnAssign(ast::StmtAnnAssign {
Stmt::Assign(ast::StmtAssign { value, .. })
| Stmt::AnnAssign(ast::StmtAnnAssign {
value: Some(value), ..
}) => {
let ast::ExprCall { func, .. } = value.as_call_expr()?;
semantic.resolve_qualified_name(func)
let qualified_name = semantic.resolve_qualified_name(func)?;
Some(qualified_name.extend_members(reversed_tail.into_iter().rev()))
}
_ => None,
}