mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-19 10:01:15 +00:00
Support classes that implement __call__
(#13580)
## Summary This looked straightforward and removes some TODOs.
This commit is contained in:
parent
043fba7a57
commit
edba60106b
2 changed files with 45 additions and 2 deletions
|
@ -609,8 +609,20 @@ impl<'db> Type<'db> {
|
|||
})
|
||||
}
|
||||
|
||||
// TODO: handle classes which implement the `__call__` protocol
|
||||
Type::Instance(_instance_ty) => CallOutcome::callable(Type::Todo),
|
||||
Type::Instance(class) => {
|
||||
// Since `__call__` is a dunder, we need to access it as an attribute on the class
|
||||
// rather than the instance (matching runtime semantics).
|
||||
let meta_ty = Type::Class(class);
|
||||
let dunder_call_method = meta_ty.member(db, "__call__");
|
||||
if dunder_call_method.is_unbound() {
|
||||
CallOutcome::not_callable(self)
|
||||
} else {
|
||||
let args = std::iter::once(self)
|
||||
.chain(arg_types.iter().copied())
|
||||
.collect::<Vec<_>>();
|
||||
dunder_call_method.call(db, &args)
|
||||
}
|
||||
}
|
||||
|
||||
// `Any` is callable, and its return type is also `Any`.
|
||||
Type::Any => CallOutcome::callable(Type::Any),
|
||||
|
|
|
@ -6723,6 +6723,37 @@ mod tests {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dunder_call() -> anyhow::Result<()> {
|
||||
let mut db = setup_db();
|
||||
|
||||
db.write_dedented(
|
||||
"/src/a.py",
|
||||
"
|
||||
class Multiplier:
|
||||
def __init__(self, factor: float):
|
||||
self.factor = factor
|
||||
|
||||
def __call__(self, number: float) -> float:
|
||||
return number * self.factor
|
||||
|
||||
a = Multiplier(2.0)(3.0)
|
||||
|
||||
class Unit:
|
||||
...
|
||||
|
||||
b = Unit()(3.0)
|
||||
",
|
||||
)?;
|
||||
|
||||
assert_public_ty(&db, "/src/a.py", "a", "float");
|
||||
assert_public_ty(&db, "/src/a.py", "b", "Unknown");
|
||||
|
||||
assert_file_diagnostics(&db, "src/a.py", &["Object of type 'Unit' is not callable."]);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn boolean_or_expression() -> anyhow::Result<()> {
|
||||
let mut db = setup_db();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue