Skip to content
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

Update to the Overloads chapter #1839

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
bab532e
First draft of an update to the Overloads chapter.
erictraut Aug 13, 2024
de81026
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 13, 2024
5ca254e
Updated draft based on initial round of feedback.
erictraut Aug 16, 2024
33c819f
Merge branch 'overloads' of https://github.com/erictraut/typing into …
erictraut Aug 16, 2024
f993b28
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Aug 16, 2024
660295c
Fixed reference.
erictraut Aug 16, 2024
06c86f1
Merge branch 'overloads' of https://github.com/erictraut/typing into …
erictraut Aug 16, 2024
831945b
Fixed reference.
erictraut Aug 16, 2024
3906a12
Another reference fix.
erictraut Aug 16, 2024
bb8fe09
Incorporated PR feedback.
erictraut Aug 23, 2024
cce3879
Made changes to proposed overload chapter based on reviewer feedback.
erictraut Aug 28, 2024
7591a4d
Incorporated additional feedback from reviewers.
erictraut Aug 28, 2024
91d4adc
Incorporated more feedback.
erictraut Aug 29, 2024
69d6d4a
Fixed typo in code sample.
erictraut Dec 13, 2024
e13dbbe
Update docs/spec/overload.rst
erictraut Dec 16, 2024
eed0815
Merge branch 'main' into overloads
carljm Jan 8, 2025
57495db
(very) initial steps on conformance tests
carljm Jan 9, 2025
27f1c79
fix abstractmethod without implementation check
carljm Jan 10, 2025
535075f
split overloads_invalid.py from overloads_basic.py
carljm Jan 10, 2025
8875a4a
add test for final with overload
carljm Jan 10, 2025
cb04dd6
add tests for correct usage of override with an overload
carljm Jan 10, 2025
5eabe53
add test for wrong use of override with overload
carljm Jan 10, 2025
484b03c
rename overloads_invalid to overloads_definitions
carljm Jan 10, 2025
ac3b70e
add support for stub test files, add overloads_definitions_stub.pyi
carljm Jan 10, 2025
87377ed
add initial overloads_consistency tests
carljm Jan 10, 2025
f7bf384
add tests for mixed async-def
carljm Jan 11, 2025
4936ac1
add tests for signature-transforming decorators
carljm Jan 11, 2025
e0e0b8a
add test for partially overlapping overloads
carljm Jan 11, 2025
cc748d3
add test for fully overlapping overloads
carljm Jan 11, 2025
17d3e15
add tests for step-1 of overload evaluation
carljm Jan 11, 2025
02f0652
add tests for steps 2 and 3 of overload evaluation
carljm Jan 11, 2025
f5bee93
add tests for bool expansion (no checker does this)
carljm Jan 11, 2025
169fa58
add tests for enum and tuple expansion
carljm Jan 11, 2025
c041484
add test for type[A | B] expansion
carljm Jan 11, 2025
c10a72d
add test for step 4 in overload matching
carljm Jan 11, 2025
8a98eae
add test for steps 5/6 in overload matching
carljm Jan 11, 2025
5d22e8d
no expectation of return type if there are call errors
carljm Jan 13, 2025
98f36e8
improve variadic test to not use overlapping overloads
carljm Jan 13, 2025
67c1675
Merge branch 'main' into overloads
erictraut Jan 25, 2025
d414386
Apply suggestions from code review
JelleZijlstra Feb 14, 2025
f4293e8
Update conformance/tests/overloads_consistency.py
AlexWaygood Feb 14, 2025
e835221
Removed section on overlapping overloads. We're struggling to get agr…
erictraut Feb 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions conformance/results/mypy/overloads_basic.toml
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
conformant = "Pass"
output = """
overloads_basic.py:37: error: No overload variant of "__getitem__" of "Bytes" matches argument type "str" [call-overload]
overloads_basic.py:37: note: Possible overload variants:
overloads_basic.py:37: note: def __getitem__(self, int, /) -> int
overloads_basic.py:37: note: def __getitem__(self, slice[Any, Any, Any], /) -> bytes
overloads_basic.py:62: error: Single overload definition, multiple required [misc]
overloads_basic.py:74: error: An overloaded function outside a stub file must have an implementation [no-overload-impl]
overloads_basic.py:39: error: No overload variant of "__getitem__" of "Bytes" matches argument type "str" [call-overload]
overloads_basic.py:39: note: Possible overload variants:
overloads_basic.py:39: note: def __getitem__(self, int, /) -> int
overloads_basic.py:39: note: def __getitem__(self, slice[Any, Any, Any], /) -> bytes
"""
conformance_automated = "Pass"
errors_diff = """
Expand Down
24 changes: 24 additions & 0 deletions conformance/results/mypy/overloads_definitions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
conformant = "Partial"
conformance_automated = "Fail"
notes = """
Does not allow an overload with no implementation in an abstract base class.
Allows @override to be on all overloads and implementation, instead of just implementation.
"""
errors_diff = """
Line 245: Expected 1 errors
Line 49: Unexpected errors ['overloads_definitions.py:49: error: An overloaded function outside a stub file must have an implementation [no-overload-impl]']
"""
output = """
overloads_definitions.py:14: error: Single overload definition, multiple required [misc]
overloads_definitions.py:26: error: An overloaded function outside a stub file must have an implementation [no-overload-impl]
overloads_definitions.py:49: error: An overloaded function outside a stub file must have an implementation [no-overload-impl]
overloads_definitions.py:63: error: An overloaded function outside a stub file must have an implementation [no-overload-impl]
overloads_definitions.py:78: error: Overload does not consistently use the "@staticmethod" decorator on all function signatures. [misc]
overloads_definitions.py:88: error: Overloaded function implementation does not accept all possible arguments of signature 1 [misc]
overloads_definitions.py:88: error: Overloaded function implementation does not accept all possible arguments of signature 2 [misc]
overloads_definitions.py:91: error: Overload does not consistently use the "@classmethod" decorator on all function signatures. [misc]
overloads_definitions.py:133: error: @final should be applied only to overload implementation [misc]
overloads_definitions.py:148: error: @final should be applied only to overload implementation [misc]
overloads_definitions.py:196: error: Cannot override final attribute "final_method" (previously declared in base class "Base") [misc]
overloads_definitions.py:211: error: Method "bad_override" is marked as an override, but no base method was found with this name [misc]
"""
18 changes: 18 additions & 0 deletions conformance/results/mypy/overloads_definitions_stub.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
conformant = "Partial"
notes = """
Allows @override to appear in a stub file not on the first overload.
"""
conformance_automated = "Fail"
errors_diff = """
Line 168: Expected 1 errors
"""
output = """
overloads_definitions_stub.pyi:13: error: Single overload definition, multiple required [misc]
overloads_definitions_stub.pyi:37: error: Overload does not consistently use the "@staticmethod" decorator on all function signatures. [misc]
overloads_definitions_stub.pyi:38: error: Self argument missing for a non-static method (or an invalid type for self) [misc]
overloads_definitions_stub.pyi:46: error: Overload does not consistently use the "@classmethod" decorator on all function signatures. [misc]
overloads_definitions_stub.pyi:85: error: In a stub file @final must be applied only to the first overload [misc]
overloads_definitions_stub.pyi:101: error: In a stub file @final must be applied only to the first overload [misc]
overloads_definitions_stub.pyi:128: error: Cannot override final attribute "final_method" (previously declared in base class "Base") [misc]
overloads_definitions_stub.pyi:140: error: Method "bad_override" is marked as an override, but no base method was found with this name [misc]
"""
4 changes: 2 additions & 2 deletions conformance/results/mypy/version.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version = "mypy 1.14.0"
test_duration = 1.6
version = "mypy 1.14.1"
test_duration = 1.7
6 changes: 1 addition & 5 deletions conformance/results/pyre/overloads_basic.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
conformant = "Pass"
notes = """
"""
output = """
overloads_basic.py:37:2 Incompatible parameter type [6]: In call `Bytes.__getitem__`, for 1st positional argument, expected `int` but got `str`.
overloads_basic.py:63:0 Incompatible overload [43]: At least two overload signatures must be present.
overloads_basic.py:75:0 Missing overload implementation [42]: Overloaded function `func2` must have an implementation.
overloads_basic.py:39:2 Incompatible parameter type [6]: In call `Bytes.__getitem__`, for 1st positional argument, expected `int` but got `str`.
"""
conformance_automated = "Pass"
errors_diff = """
Expand Down
32 changes: 32 additions & 0 deletions conformance/results/pyre/overloads_definitions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
conformant = "Partial"
conformance_automated = "Fail"
notes = """
Does not allow an overload with no implementation in a Protocol or an abstract base class.
Expects @final/@override on all overloads and implementation, instead of implementation only.
"""
errors_diff = """
Line 245: Expected 1 errors
Lines 148, 150: Expected error (tag 'invalid_final_2')
Line 40: Unexpected errors ['overloads_definitions.py:40:4 Missing overload implementation [42]: Overloaded function `MyProto.func3` must have an implementation.']
Line 51: Unexpected errors ['overloads_definitions.py:51:4 Missing overload implementation [42]: Overloaded function `MyAbstractBase.func4` must have an implementation.']
Line 128: Unexpected errors ['overloads_definitions.py:128:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).']
Line 239: Unexpected errors ['overloads_definitions.py:239:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).']
"""
output = """
overloads_definitions.py:15:0 Incompatible overload [43]: At least two overload signatures must be present.
overloads_definitions.py:27:0 Missing overload implementation [42]: Overloaded function `func2` must have an implementation.
overloads_definitions.py:40:4 Missing overload implementation [42]: Overloaded function `MyProto.func3` must have an implementation.
overloads_definitions.py:51:4 Missing overload implementation [42]: Overloaded function `MyAbstractBase.func4` must have an implementation.
overloads_definitions.py:64:4 Missing overload implementation [42]: Overloaded function `MyAbstractBase.not_abstract` must have an implementation.
overloads_definitions.py:80:4 Incompatible overload [43]: The implementation of `C.func5` does not accept all possible arguments of overload defined on line `80`.
overloads_definitions.py:85:4 Incompatible overload [43]: The implementation of `C.func5` does not accept all possible arguments of overload defined on line `85`.
overloads_definitions.py:88:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
overloads_definitions.py:97:4 Incompatible overload [43]: The implementation of `C.func6` does not accept all possible arguments of overload defined on line `97`.
overloads_definitions.py:97:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
overloads_definitions.py:128:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
overloads_definitions.py:139:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
overloads_definitions.py:204:4 Invalid override [40]: `overloads_definitions.Child.final_method` cannot override final method defined in `Base`.
overloads_definitions.py:220:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
overloads_definitions.py:220:4 Invalid override [40]: `overloads_definitions.Child.bad_override` is decorated with @override, but no method of the same name exists in superclasses of `Child`.
overloads_definitions.py:239:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
"""
27 changes: 27 additions & 0 deletions conformance/results/pyre/overloads_definitions_stub.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
conformant = "Partial"
notes = """
Expects @final and @override to be present on all overloads, not just first.
"""
conformance_automated = "Fail"
errors_diff = """
Line 168: Expected 1 errors
Lines 80, 82, 85, 87: Expected error (tag 'invalid_final')
Lines 96, 98, 101: Expected error (tag 'invalid_final_2')
Lines 122, 128, 129, 133: Expected error (tag 'override-final')
Line 75: Unexpected errors ['overloads_definitions_stub.pyi:75:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).']
Line 91: Unexpected errors ['overloads_definitions_stub.pyi:91:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).']
Line 146: Unexpected errors ['overloads_definitions_stub.pyi:146:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).']
Line 162: Unexpected errors ['overloads_definitions_stub.pyi:162:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).']
Line 174: Unexpected errors ['overloads_definitions_stub.pyi:174:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).']
"""
output = """
overloads_definitions_stub.pyi:14:0 Incompatible overload [43]: At least two overload signatures must be present.
overloads_definitions_stub.pyi:43:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
overloads_definitions_stub.pyi:52:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
overloads_definitions_stub.pyi:75:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
overloads_definitions_stub.pyi:91:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
overloads_definitions_stub.pyi:142:4 Invalid override [40]: `overloads_definitions_stub.Child.bad_override` is decorated with @override, but no method of the same name exists in superclasses of `Child`.
overloads_definitions_stub.pyi:146:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
overloads_definitions_stub.pyi:162:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
overloads_definitions_stub.pyi:174:4 Incompatible overload [43]: This definition does not have the same decorators as the preceding overload(s).
"""
2 changes: 1 addition & 1 deletion conformance/results/pyre/version.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version = "pyre 0.9.23"
test_duration = 7.3
test_duration = 6.7
8 changes: 4 additions & 4 deletions conformance/results/pyright/overloads_basic.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
conformant = "Pass"
notes = """
"""
output = """
overloads_basic.py:37:1 - error: No overloads for "__getitem__" match the provided arguments (reportCallIssue)
overloads_basic.py:37:1 - error: Argument of type "Literal['']" cannot be assigned to parameter "__s" of type "slice[Any, Any, Any]" in function "__getitem__"
overloads_basic.py:39:1 - error: No overloads for "__getitem__" match the provided arguments (reportCallIssue)
overloads_basic.py:39:1 - error: Argument of type "Literal['']" cannot be assigned to parameter "__s" of type "slice[Any, Any, Any]" in function "__getitem__"
  "Literal['']" is not assignable to "slice[Any, Any, Any]" (reportArgumentType)
overloads_basic.py:63:5 - error: "func1" is marked as overload, but additional overloads are missing (reportInconsistentOverload)
overloads_basic.py:75:5 - error: "func2" is marked as overload, but no implementation is provided (reportNoOverloadImplementation)
"""
conformance_automated = "Pass"
errors_diff = """
Expand Down
32 changes: 32 additions & 0 deletions conformance/results/pyright/overloads_definitions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
conformant = "Partial"
notes = """
Allows @final/@override on all overloads and implementation; should be implementation-only.
"""
conformance_automated = "Fail"
errors_diff = """
Line 245: Expected 1 errors
Lines 148, 150: Expected error (tag 'invalid_final_2')
"""
output = """
overloads_definitions.py:15:5 - error: "func1" is marked as overload, but additional overloads are missing (reportInconsistentOverload)
overloads_definitions.py:27:5 - error: "func2" is marked as overload, but no implementation is provided (reportNoOverloadImplementation)
overloads_definitions.py:64:9 - error: "not_abstract" is marked as overload, but no implementation is provided (reportNoOverloadImplementation)
overloads_definitions.py:80:9 - error: Overloads for "func5" use @staticmethod inconsistently (reportInconsistentOverload)
overloads_definitions.py:88:9 - error: Overloaded implementation is not consistent with signature of overload 1
  Type "(self: Self@C, x: int | str) -> (int | str)" is not assignable to type "(x: int) -> int"
    Parameter name mismatch: "x" versus "self"
    Parameter 1: type "int" is incompatible with type "Self@C"
      Type "int" is not assignable to type "Self@C"
    Extra parameter "x" (reportInconsistentOverload)
overloads_definitions.py:88:9 - error: Overloaded implementation is not consistent with signature of overload 2
  Type "(self: Self@C, x: int | str) -> (int | str)" is not assignable to type "(x: str) -> str"
    Parameter name mismatch: "x" versus "self"
    Parameter 1: type "str" is incompatible with type "Self@C"
      Type "str" is not assignable to type "Self@C"
    Extra parameter "x" (reportInconsistentOverload)
overloads_definitions.py:93:9 - error: Overloads for "func6" use @classmethod inconsistently (reportInconsistentOverload)
overloads_definitions.py:97:15 - warning: Instance methods should take a "self" parameter (reportSelfClsParameterName)
overloads_definitions.py:135:9 - error: Overload for "invalid_final" is marked @final but implementation is not (reportInconsistentOverload)
overloads_definitions.py:204:9 - error: Method "final_method" cannot override final method defined in class "Base" (reportIncompatibleMethodOverride)
overloads_definitions.py:220:9 - error: Method "bad_override" is marked as override, but no base method of same name is present (reportGeneralTypeIssues)
"""
20 changes: 20 additions & 0 deletions conformance/results/pyright/overloads_definitions_stub.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
conformant = "Partial"
notes = """
Does not enforce that @final/@override in a stub should be only on first overload.
Does not enforce @override when correctly used with an overloaded method in a stub file.
"""
conformance_automated = "Fail"
errors_diff = """
Line 168: Expected 1 errors
Lines 80, 82, 85, 87: Expected error (tag 'invalid_final')
Lines 96, 98, 101: Expected error (tag 'invalid_final_2')
Lines 140, 142: Expected error (tag 'bad_override')
"""
output = """
overloads_definitions_stub.pyi:14:5 - error: "func1" is marked as overload, but additional overloads are missing (reportInconsistentOverload)
overloads_definitions_stub.pyi:38:9 - error: Overloads for "func5" use @staticmethod inconsistently (reportInconsistentOverload)
overloads_definitions_stub.pyi:38:15 - warning: Instance methods should take a "self" parameter (reportSelfClsParameterName)
overloads_definitions_stub.pyi:48:9 - error: Overloads for "func6" use @classmethod inconsistently (reportInconsistentOverload)
overloads_definitions_stub.pyi:52:15 - warning: Instance methods should take a "self" parameter (reportSelfClsParameterName)
overloads_definitions_stub.pyi:133:9 - error: Method "final_method" cannot override final method defined in class "Base" (reportIncompatibleMethodOverride)
"""
2 changes: 1 addition & 1 deletion conformance/results/pyright/version.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
version = "pyright 1.1.391"
test_duration = 1.2
test_duration = 1.5
14 changes: 5 additions & 9 deletions conformance/results/pytype/overloads_basic.toml
Original file line number Diff line number Diff line change
@@ -1,29 +1,25 @@
conformant = "Partial"
notes = """
Does not reject a function with a single @overload signature.
Does not reject a function with @overload signature but no implementation.
"""
output = """
overloads_basic.py:31:20: \u001b[1m\u001b[31merror\u001b[39m\u001b[0m: in __getitem__: bad return type [bad-return-type]
overloads_basic.py:33:20: \u001b[1m\u001b[31merror\u001b[39m\u001b[0m: in __getitem__: bad return type [bad-return-type]

return b""
\u001b[1m\u001b[31m~~~\u001b[39m\u001b[0m

overloads_basic.py:37:1: \u001b[1m\u001b[31merror\u001b[39m\u001b[0m: in <module>: unsupported operand type(s) for item retrieval: Bytes and str [unsupported-operands]
overloads_basic.py:39:1: \u001b[1m\u001b[31merror\u001b[39m\u001b[0m: in <module>: unsupported operand type(s) for item retrieval: Bytes and str [unsupported-operands]

b[""] # E: no matching overload
\u001b[1m\u001b[31m~~~~~\u001b[39m\u001b[0m

overloads_basic.py:58:5: \u001b[1m\u001b[31merror\u001b[39m\u001b[0m: in map: bad return type [bad-return-type]
overloads_basic.py:60:5: \u001b[1m\u001b[31merror\u001b[39m\u001b[0m: in map: bad return type [bad-return-type]

pass
\u001b[1m\u001b[31m~~~~\u001b[39m\u001b[0m

"""
conformance_automated = "Fail"
errors_diff = """
Lines 62, 63: Expected error (tag 'func1')
Lines 74, 75: Expected error (tag 'func2')
Line 31: Unexpected errors ['overloads_basic.py:31:20: \\x1b[1m\\x1b[31merror\\x1b[39m\\x1b[0m: in __getitem__: bad return type [bad-return-type]']
Line 58: Unexpected errors ['overloads_basic.py:58:5: \\x1b[1m\\x1b[31merror\\x1b[39m\\x1b[0m: in map: bad return type [bad-return-type]']
Line 33: Unexpected errors ['overloads_basic.py:33:20: \\x1b[1m\\x1b[31merror\\x1b[39m\\x1b[0m: in __getitem__: bad return type [bad-return-type]']
Line 60: Unexpected errors ['overloads_basic.py:60:5: \\x1b[1m\\x1b[31merror\\x1b[39m\\x1b[0m: in map: bad return type [bad-return-type]']
"""
Loading
Loading