From d33a50368644c0bd98d4d66d0b9b5dbbaa5f89db Mon Sep 17 00:00:00 2001 From: Victor Hugo Gomes Date: Wed, 30 Apr 2025 17:40:16 -0300 Subject: [PATCH] [red-knot] Add tests for classes that have incompatible `__new__` and `__init__` methods (#17747) Closes #17737 --- .../resources/mdtest/call/constructor.md | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/crates/red_knot_python_semantic/resources/mdtest/call/constructor.md b/crates/red_knot_python_semantic/resources/mdtest/call/constructor.md index 83ca0093ee..db20ce4a96 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/call/constructor.md +++ b/crates/red_knot_python_semantic/resources/mdtest/call/constructor.md @@ -343,6 +343,64 @@ reveal_type(Foo(1)) # revealed: Foo reveal_type(Foo(1, 2)) # revealed: Foo ``` +### Incompatible signatures + +```py +import abc + +class Foo: + def __new__(cls) -> "Foo": + return object.__new__(cls) + + def __init__(self, x): + self.x = 42 + +# error: [missing-argument] "No argument provided for required parameter `x` of bound method `__init__`" +reveal_type(Foo()) # revealed: Foo + +# error: [too-many-positional-arguments] "Too many positional arguments to function `__new__`: expected 0, got 1" +reveal_type(Foo(42)) # revealed: Foo + +class Foo2: + def __new__(cls, x) -> "Foo2": + return object.__new__(cls) + + def __init__(self): + pass + +# error: [missing-argument] "No argument provided for required parameter `x` of function `__new__`" +reveal_type(Foo2()) # revealed: Foo2 + +# error: [too-many-positional-arguments] "Too many positional arguments to bound method `__init__`: expected 0, got 1" +reveal_type(Foo2(42)) # revealed: Foo2 + +class Foo3(metaclass=abc.ABCMeta): + def __new__(cls) -> "Foo3": + return object.__new__(cls) + + def __init__(self, x): + self.x = 42 + +# error: [missing-argument] "No argument provided for required parameter `x` of bound method `__init__`" +reveal_type(Foo3()) # revealed: Foo3 + +# error: [too-many-positional-arguments] "Too many positional arguments to function `__new__`: expected 0, got 1" +reveal_type(Foo3(42)) # revealed: Foo3 + +class Foo4(metaclass=abc.ABCMeta): + def __new__(cls, x) -> "Foo4": + return object.__new__(cls) + + def __init__(self): + pass + +# error: [missing-argument] "No argument provided for required parameter `x` of function `__new__`" +reveal_type(Foo4()) # revealed: Foo4 + +# error: [too-many-positional-arguments] "Too many positional arguments to bound method `__init__`: expected 0, got 1" +reveal_type(Foo4(42)) # revealed: Foo4 +``` + ### Lookup of `__new__` The `__new__` method is always invoked on the class itself, never on the metaclass. This is