From 05f6995d7715edee1d355fcafe330b196a0a5244 Mon Sep 17 00:00:00 2001 From: LaBatata101 Date: Wed, 30 Apr 2025 17:15:39 -0300 Subject: [PATCH 1/2] [red-knot] Add tests for classes that have incompatible `__new__` and `__init__` methods --- .../resources/mdtest/call/constructor.md | 54 +++++++++++++++++++ 1 file changed, 54 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 56a49fc13f97c..292f8b0e09b9c 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/call/constructor.md +++ b/crates/red_knot_python_semantic/resources/mdtest/call/constructor.md @@ -323,3 +323,57 @@ reveal_type(Foo(1)) # revealed: Foo # error: [too-many-positional-arguments] "Too many positional arguments to bound method `__init__`: expected 1, got 2" 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 +``` From 6d5000c922145bed20ec089cb2c782f199aa11fb Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Wed, 30 Apr 2025 13:37:25 -0700 Subject: [PATCH 2/2] pre-commit --- .../resources/mdtest/call/constructor.md | 4 ++++ 1 file changed, 4 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 d0f92f50b8cc9..db20ce4a962a4 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/call/constructor.md +++ b/crates/red_knot_python_semantic/resources/mdtest/call/constructor.md @@ -351,6 +351,7 @@ import abc class Foo: def __new__(cls) -> "Foo": return object.__new__(cls) + def __init__(self, x): self.x = 42 @@ -363,6 +364,7 @@ reveal_type(Foo(42)) # revealed: Foo class Foo2: def __new__(cls, x) -> "Foo2": return object.__new__(cls) + def __init__(self): pass @@ -375,6 +377,7 @@ 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 @@ -387,6 +390,7 @@ reveal_type(Foo3(42)) # revealed: Foo3 class Foo4(metaclass=abc.ABCMeta): def __new__(cls, x) -> "Foo4": return object.__new__(cls) + def __init__(self): pass