From 36cb1199cc9222b1794012dceb076f33738effeb Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sat, 19 Oct 2024 15:57:06 +0100 Subject: [PATCH] [red-knot] Autoformat `mdtest` Python snippets using `blacken-docs` (#13809) --- .pre-commit-config.yaml | 9 ++ .../mdtest/assignment/annotations.md | 5 +- .../resources/mdtest/assignment/unbound.md | 3 + .../resources/mdtest/attributes.md | 4 + .../resources/mdtest/binary/integers.md | 4 +- .../mdtest/call/callable_instance.md | 3 + .../resources/mdtest/call/constructor.md | 1 + .../resources/mdtest/call/function.md | 8 +- .../resources/mdtest/call/union.md | 21 +++- .../resources/mdtest/comparison/integers.md | 1 + .../mdtest/comparison/non_boolean_returns.md | 3 + .../resources/mdtest/comparison/strings.md | 1 + .../resources/mdtest/comparison/tuples.md | 5 +- .../resources/mdtest/declaration/error.md | 2 +- .../resources/mdtest/exception/basic.md | 1 + .../mdtest/exception/control_flow.md | 95 ++++++++++++++----- .../resources/mdtest/exception/except_star.md | 2 +- .../resources/mdtest/expression/boolean.md | 25 +++-- .../resources/mdtest/generics.md | 32 ++++--- .../resources/mdtest/import/basic.md | 12 ++- .../resources/mdtest/import/builtins.md | 4 +- .../resources/mdtest/import/conditional.md | 5 + .../resources/mdtest/import/errors.md | 7 +- .../resources/mdtest/import/relative.md | 10 ++ .../resources/mdtest/import/stubs.md | 2 + .../mdtest/literal/collections/tuple.md | 4 +- .../resources/mdtest/literal/f_string.md | 20 ++-- .../resources/mdtest/literal/string.md | 11 ++- .../resources/mdtest/loops/async_for_loops.md | 2 +- .../resources/mdtest/loops/for_loop.md | 19 +++- .../resources/mdtest/loops/iterators.md | 5 +- .../mdtest/narrow/conditionals_is.md | 4 +- .../resources/mdtest/scopes/builtin.md | 4 + .../resources/mdtest/shadowing/class.md | 8 +- .../resources/mdtest/shadowing/function.md | 8 +- .../mdtest/shadowing/variable_declaration.md | 2 +- .../resources/mdtest/stubs/class.md | 2 + .../resources/mdtest/subscript/bytes.md | 8 +- .../resources/mdtest/subscript/class.md | 68 ++++++++----- .../resources/mdtest/subscript/instance.md | 11 ++- .../resources/mdtest/subscript/string.md | 7 +- .../resources/mdtest/subscript/tuple.md | 2 +- .../resources/mdtest/unary/integers.md | 2 +- .../resources/mdtest/unary/not.md | 5 +- .../resources/mdtest/unpacking.md | 6 +- 45 files changed, 331 insertions(+), 132 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d7d119af9c..bbecfdf8c7 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -45,6 +45,15 @@ repos: | docs/\w+\.md )$ + - repo: https://github.com/adamchainz/blacken-docs + rev: 1.19.0 + hooks: + - id: blacken-docs + args: ["--line-length", "130"] + files: '^crates/.*/resources/mdtest/.*\.md' + additional_dependencies: + - black==24.10.0 + - repo: https://github.com/crate-ci/typos rev: v1.25.0 hooks: diff --git a/crates/red_knot_python_semantic/resources/mdtest/assignment/annotations.md b/crates/red_knot_python_semantic/resources/mdtest/assignment/annotations.md index bbac55c29a..1e912f7f24 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/assignment/annotations.md +++ b/crates/red_knot_python_semantic/resources/mdtest/assignment/annotations.md @@ -13,13 +13,12 @@ reveal_type(y) # revealed: Literal[1] ## Violates own annotation ```py -x: int = 'foo' # error: [invalid-assignment] "Object of type `Literal["foo"]` is not assignable to `int`" - +x: int = "foo" # error: [invalid-assignment] "Object of type `Literal["foo"]` is not assignable to `int`" ``` ## Violates previous annotation ```py x: int -x = 'foo' # error: [invalid-assignment] "Object of type `Literal["foo"]` is not assignable to `int`" +x = "foo" # error: [invalid-assignment] "Object of type `Literal["foo"]` is not assignable to `int`" ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/assignment/unbound.md b/crates/red_knot_python_semantic/resources/mdtest/assignment/unbound.md index 7c8bdda4a2..0a71ad55f2 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/assignment/unbound.md +++ b/crates/red_knot_python_semantic/resources/mdtest/assignment/unbound.md @@ -14,11 +14,14 @@ Name lookups within a class scope fall back to globals, but lookups of class att ```py x = 1 + + class C: y = x if flag: x = 2 + reveal_type(C.x) # revealed: Literal[2] reveal_type(C.y) # revealed: Literal[1] ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/attributes.md b/crates/red_knot_python_semantic/resources/mdtest/attributes.md index 367cae61bb..a5ee9bf01c 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/attributes.md +++ b/crates/red_knot_python_semantic/resources/mdtest/attributes.md @@ -4,11 +4,15 @@ ```py if flag: + class C: x = 1 + else: + class C: x = 2 + reveal_type(C.x) # revealed: Literal[1, 2] ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/binary/integers.md b/crates/red_knot_python_semantic/resources/mdtest/binary/integers.md index 54655e5575..746e8d7f4a 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/binary/integers.md +++ b/crates/red_knot_python_semantic/resources/mdtest/binary/integers.md @@ -42,7 +42,9 @@ e = 1.0 / 0 # error: "Cannot divide object of type `float` by zero" # TODO should be float reveal_type(e) # revealed: @Todo -class MyInt(int): pass + +class MyInt(int): ... + # No error for a subclass of int # TODO should be float diff --git a/crates/red_knot_python_semantic/resources/mdtest/call/callable_instance.md b/crates/red_knot_python_semantic/resources/mdtest/call/callable_instance.md index 1719601372..38a31e2315 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/call/callable_instance.md +++ b/crates/red_knot_python_semantic/resources/mdtest/call/callable_instance.md @@ -10,11 +10,14 @@ class Multiplier: def __call__(self, number: float) -> float: return number * self.factor + a = Multiplier(2.0)(3.0) reveal_type(a) # revealed: float + class Unit: ... + b = Unit()(3.0) # error: "Object of type `Unit` is not callable" reveal_type(b) # revealed: Unknown ``` 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 b9927fe086..4877792b59 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/call/constructor.md +++ b/crates/red_knot_python_semantic/resources/mdtest/call/constructor.md @@ -3,5 +3,6 @@ ```py class Foo: ... + reveal_type(Foo()) # revealed: Foo ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/call/function.md b/crates/red_knot_python_semantic/resources/mdtest/call/function.md index eaa6d143fd..d8e92d1779 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/call/function.md +++ b/crates/red_knot_python_semantic/resources/mdtest/call/function.md @@ -6,6 +6,7 @@ def get_int() -> int: return 42 + reveal_type(get_int()) # revealed: int ``` @@ -15,6 +16,7 @@ reveal_type(get_int()) # revealed: int async def get_int_async() -> int: return 42 + # TODO: we don't yet support `types.CoroutineType`, should be generic `Coroutine[Any, Any, int]` reveal_type(get_int_async()) # revealed: @Todo ``` @@ -24,15 +26,19 @@ reveal_type(get_int_async()) # revealed: @Todo ```py from typing import Callable + def foo() -> int: return 42 + def decorator(func) -> Callable[[], int]: return foo + @decorator def bar() -> str: - return 'bar' + return "bar" + # TODO: should reveal `int`, as the decorator replaces `bar` with `foo` reveal_type(bar()) # revealed: @Todo diff --git a/crates/red_knot_python_semantic/resources/mdtest/call/union.md b/crates/red_knot_python_semantic/resources/mdtest/call/union.md index f91aad0375..f5115cb97f 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/call/union.md +++ b/crates/red_knot_python_semantic/resources/mdtest/call/union.md @@ -4,11 +4,15 @@ ```py if flag: + def f() -> int: return 1 + else: + def f() -> str: - return 'foo' + return "foo" + reveal_type(f()) # revealed: int | str ``` @@ -19,9 +23,11 @@ reveal_type(f()) # revealed: int | str from nonexistent import f # error: [unresolved-import] "Cannot resolve import `nonexistent`" if flag: + def f() -> int: return 1 + reveal_type(f()) # revealed: Unknown | int ``` @@ -33,9 +39,11 @@ Calling a union with a non-callable element should emit a diagnostic. if flag: f = 1 else: + def f() -> int: return 1 + x = f() # error: "Object of type `Literal[1] | Literal[f]` is not callable (due to union element `Literal[1]`)" reveal_type(x) # revealed: Unknown | int ``` @@ -48,13 +56,16 @@ Calling a union with multiple non-callable elements should mention all of them i if flag: f = 1 elif flag2: - f = 'foo' + f = "foo" else: + def f() -> int: return 1 -x = f() # error: "Object of type `Literal[1] | Literal["foo"] | Literal[f]` is not callable (due to union elements Literal[1], Literal["foo"])" -reveal_type(x) # revealed: Unknown | int + +# error: "Object of type `Literal[1] | Literal["foo"] | Literal[f]` is not callable (due to union elements Literal[1], Literal["foo"])" +# revealed: Unknown | int +reveal_type(f()) ``` ## All non-callable union elements @@ -65,7 +76,7 @@ Calling a union with no callable elements can emit a simpler diagnostic. if flag: f = 1 else: - f = 'foo' + f = "foo" x = f() # error: "Object of type `Literal[1] | Literal["foo"]` is not callable" reveal_type(x) # revealed: Unknown diff --git a/crates/red_knot_python_semantic/resources/mdtest/comparison/integers.md b/crates/red_knot_python_semantic/resources/mdtest/comparison/integers.md index 748b94eda3..01f53b3fef 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/comparison/integers.md +++ b/crates/red_knot_python_semantic/resources/mdtest/comparison/integers.md @@ -21,6 +21,7 @@ reveal_type(1 <= "" and 0 < 1) # revealed: @Todo | Literal[True] # TODO: implement lookup of `__eq__` on typeshed `int` stub. def int_instance() -> int: ... + reveal_type(1 == int_instance()) # revealed: @Todo reveal_type(9 < int_instance()) # revealed: bool reveal_type(int_instance() < int_instance()) # revealed: bool diff --git a/crates/red_knot_python_semantic/resources/mdtest/comparison/non_boolean_returns.md b/crates/red_knot_python_semantic/resources/mdtest/comparison/non_boolean_returns.md index e42203edd5..60a5ee1619 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/comparison/non_boolean_returns.md +++ b/crates/red_knot_python_semantic/resources/mdtest/comparison/non_boolean_returns.md @@ -20,6 +20,8 @@ Walking through examples: ```py from __future__ import annotations + + class A: def __lt__(self, other) -> A: ... class B: @@ -27,6 +29,7 @@ class B: class C: def __lt__(self, other) -> C: ... + x = A() < B() < C() reveal_type(x) # revealed: A | B diff --git a/crates/red_knot_python_semantic/resources/mdtest/comparison/strings.md b/crates/red_knot_python_semantic/resources/mdtest/comparison/strings.md index 04cfc6771e..3951a20c02 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/comparison/strings.md +++ b/crates/red_knot_python_semantic/resources/mdtest/comparison/strings.md @@ -5,6 +5,7 @@ ```py def str_instance() -> str: ... + reveal_type("abc" == "abc") # revealed: Literal[True] reveal_type("ab_cd" <= "ab_ce") # revealed: Literal[True] reveal_type("abc" in "ab cd") # revealed: Literal[False] diff --git a/crates/red_knot_python_semantic/resources/mdtest/comparison/tuples.md b/crates/red_knot_python_semantic/resources/mdtest/comparison/tuples.md index 808f76f317..5b3fc43e0c 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/comparison/tuples.md +++ b/crates/red_knot_python_semantic/resources/mdtest/comparison/tuples.md @@ -61,6 +61,7 @@ reveal_type(c >= d) # revealed: Literal[True] def bool_instance() -> bool: ... def int_instance() -> int: ... + a = (bool_instance(),) b = (int_instance(),) @@ -135,7 +136,7 @@ reveal_type(c >= c) # revealed: Literal[True] #### Non Boolean Rich Comparisons ```py -class A(): +class A: def __eq__(self, o) -> str: ... def __ne__(self, o) -> int: ... def __lt__(self, o) -> float: ... @@ -143,6 +144,7 @@ class A(): def __gt__(self, o) -> tuple: ... def __ge__(self, o) -> list: ... + a = (A(), A()) # TODO: All @Todo should be bool @@ -161,6 +163,7 @@ reveal_type(a >= a) # revealed: @Todo ```py def int_instance() -> int: ... + a = (1, 2) b = ((3, 4), (1, 2)) c = ((1, 2, 3), (4, 5, 6)) diff --git a/crates/red_knot_python_semantic/resources/mdtest/declaration/error.md b/crates/red_knot_python_semantic/resources/mdtest/declaration/error.md index 2062f0fa76..b1eded0113 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/declaration/error.md +++ b/crates/red_knot_python_semantic/resources/mdtest/declaration/error.md @@ -35,5 +35,5 @@ else: # error: [conflicting-declarations] # error: [invalid-assignment] -x = b'foo' +x = b"foo" ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/exception/basic.md b/crates/red_knot_python_semantic/resources/mdtest/exception/basic.md index 5e4c7b3468..85bc87b7fd 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/exception/basic.md +++ b/crates/red_knot_python_semantic/resources/mdtest/exception/basic.md @@ -4,6 +4,7 @@ ```py import re + try: x except NameError as e: diff --git a/crates/red_knot_python_semantic/resources/mdtest/exception/control_flow.md b/crates/red_knot_python_semantic/resources/mdtest/exception/control_flow.md index ead639e490..f7cf500d0b 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/exception/control_flow.md +++ b/crates/red_knot_python_semantic/resources/mdtest/exception/control_flow.md @@ -38,7 +38,8 @@ to the `except` suite *after* that redefinition. ```py path=union_type_inferred.py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + x = 1 @@ -60,7 +61,8 @@ unify and `x` is not inferred as having a union type following the ```py path=branches_unify_to_non_union_type.py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + x = 1 @@ -84,7 +86,8 @@ possibility when it comes to control-flow analysis. ```py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + x = 1 @@ -114,7 +117,8 @@ the three suites: ```py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + x = 1 @@ -147,7 +151,8 @@ the end of the `except` suite: ```py path=single_except.py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + x = 1 @@ -175,7 +180,8 @@ in their entireties: ```py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + x = 1 @@ -208,7 +214,8 @@ therefore `Literal[2]`: ```py path=redef_in_finally.py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + x = 1 @@ -235,7 +242,8 @@ suites, however; this is still a TODO item for us.) ```py path=no_redef_in_finally.py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + x = 1 @@ -267,14 +275,17 @@ following possibilities inside `finally` suites: ```py path=redef_in_finally.py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + def could_raise_returns_bytes() -> bytes: - return b'foo' + return b"foo" + def could_raise_returns_bool() -> bool: return True + x = 1 try: @@ -305,14 +316,17 @@ conclusion of the `finally` suite.) ```py path=no_redef_in_finally.py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + def could_raise_returns_bytes() -> bytes: - return b'foo' + return b"foo" + def could_raise_returns_bool() -> bool: return True + x = 1 try: @@ -336,20 +350,25 @@ An example with multiple `except` branches and a `finally` branch: ```py path=multiple_except_branches.py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + def could_raise_returns_bytes() -> bytes: - return b'foo' + return b"foo" + def could_raise_returns_bool() -> bool: return True + def could_raise_returns_memoryview() -> memoryview: return memoryview(b"") + def could_raise_returns_float() -> float: return 3.14 + x = 1 try: @@ -383,20 +402,25 @@ partway through the `else` suite due to an exception raised *there*. ```py path=single_except_branch.py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + def could_raise_returns_bytes() -> bytes: - return b'foo' + return b"foo" + def could_raise_returns_bool() -> bool: return True + def could_raise_returns_memoryview() -> memoryview: return memoryview(b"") + def could_raise_returns_float() -> float: return 3.14 + x = 1 try: @@ -426,26 +450,33 @@ The same again, this time with multiple `except` branches: ```py path=multiple_except_branches.py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + def could_raise_returns_bytes() -> bytes: - return b'foo' + return b"foo" + def could_raise_returns_bool() -> bool: return True + def could_raise_returns_memoryview() -> memoryview: return memoryview(b"") + def could_raise_returns_float() -> float: return 3.14 + def could_raise_returns_range() -> range: return range(42) + def could_raise_returns_slice() -> slice: return slice(None) + x = 1 try: @@ -491,41 +522,55 @@ prior to the suite running to completion. ```py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + def could_raise_returns_bytes() -> bytes: - return b'foo' + return b"foo" + def could_raise_returns_bool() -> bool: return True + def could_raise_returns_memoryview() -> memoryview: return memoryview(b"") + def could_raise_returns_float() -> float: return 3.14 + def could_raise_returns_range() -> range: return range(42) + def could_raise_returns_slice() -> slice: return slice(None) + def could_raise_returns_complex() -> complex: return 3j + def could_raise_returns_bytearray() -> bytearray: return bytearray() + class Foo: ... + + class Bar: ... + def could_raise_returns_Foo() -> Foo: return Foo() + def could_raise_returns_Bar() -> Bar: return Bar() + x = 1 try: @@ -585,23 +630,29 @@ variable by that name in the outer scope: ```py def could_raise_returns_str() -> str: - return 'foo' + return "foo" + def could_raise_returns_bytes() -> bytes: - return b'foo' + return b"foo" + def could_raise_returns_range() -> range: return range(42) + def could_raise_returns_bytearray() -> bytearray: return bytearray() + def could_raise_returns_float() -> float: return 3.14 + x = 1 try: + def foo(param=could_raise_returns_str()): x = could_raise_returns_str() diff --git a/crates/red_knot_python_semantic/resources/mdtest/exception/except_star.md b/crates/red_knot_python_semantic/resources/mdtest/exception/except_star.md index a733c79e8a..44d701d1f8 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/exception/except_star.md +++ b/crates/red_knot_python_semantic/resources/mdtest/exception/except_star.md @@ -25,6 +25,6 @@ except* OSError as e: try: x except* (TypeError, AttributeError) as e: - #TODO(Alex): more precise would be `ExceptionGroup[TypeError | AttributeError]`. + # TODO(Alex): more precise would be `ExceptionGroup[TypeError | AttributeError]`. reveal_type(e) # revealed: BaseExceptionGroup ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/expression/boolean.md b/crates/red_knot_python_semantic/resources/mdtest/expression/boolean.md index 3398cff77d..fad3069bb6 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/expression/boolean.md +++ b/crates/red_knot_python_semantic/resources/mdtest/expression/boolean.md @@ -6,10 +6,11 @@ def foo() -> str: pass + reveal_type(True or False) # revealed: Literal[True] -reveal_type('x' or 'y' or 'z') # revealed: Literal["x"] -reveal_type('' or 'y' or 'z') # revealed: Literal["y"] -reveal_type(False or 'z') # revealed: Literal["z"] +reveal_type("x" or "y" or "z") # revealed: Literal["x"] +reveal_type("" or "y" or "z") # revealed: Literal["y"] +reveal_type(False or "z") # revealed: Literal["z"] reveal_type(False or True) # revealed: Literal[True] reveal_type(False or False) # revealed: Literal[False] reveal_type(foo() or False) # revealed: str | Literal[False] @@ -22,13 +23,14 @@ reveal_type(foo() or True) # revealed: str | Literal[True] def foo() -> str: pass + reveal_type(True and False) # revealed: Literal[False] reveal_type(False and True) # revealed: Literal[False] reveal_type(foo() and False) # revealed: str | Literal[False] reveal_type(foo() and True) # revealed: str | Literal[True] -reveal_type('x' and 'y' and 'z') # revealed: Literal["z"] -reveal_type('x' and 'y' and '') # revealed: Literal[""] -reveal_type('' and 'y') # revealed: Literal[""] +reveal_type("x" and "y" and "z") # revealed: Literal["z"] +reveal_type("x" and "y" and "") # revealed: Literal[""] +reveal_type("" and "y") # revealed: Literal[""] ``` ## Simple function calls to bool @@ -37,6 +39,7 @@ reveal_type('' and 'y') # revealed: Literal[""] def returns_bool() -> bool: return True + if returns_bool(): x = True else: @@ -51,6 +54,7 @@ reveal_type(x) # revealed: bool def foo() -> str: pass + reveal_type("x" and "y" or "z") # revealed: Literal["y"] reveal_type("x" or "y" and "z") # revealed: Literal["x"] reveal_type("" and "y" or "z") # revealed: Literal["z"] @@ -66,7 +70,9 @@ reveal_type("x" or "y" and "") # revealed: Literal["x"] ```py path=a.py redefined_builtin_bool = bool -def my_bool(x)-> bool: pass + +def my_bool(x) -> bool: + return True ``` ```py @@ -84,7 +90,10 @@ reveal_type(bool((0,))) # revealed: Literal[True] reveal_type(bool("NON EMPTY")) # revealed: Literal[True] reveal_type(bool(True)) # revealed: Literal[True] -def foo(): pass + +def foo(): ... + + reveal_type(bool(foo)) # revealed: Literal[True] ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/generics.md b/crates/red_knot_python_semantic/resources/mdtest/generics.md index a7b1c59d2c..a88b2d4d9b 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/generics.md +++ b/crates/red_knot_python_semantic/resources/mdtest/generics.md @@ -6,10 +6,12 @@ Basic PEP 695 generics ```py class MyBox[T]: - data: T - box_model_number = 695 - def __init__(self, data: T): - self.data = data + data: T + box_model_number = 695 + + def __init__(self, data: T): + self.data = data + # TODO not error (should be subscriptable) box: MyBox[int] = MyBox(5) # error: [non-subscriptable] @@ -25,14 +27,15 @@ reveal_type(MyBox.box_model_number) # revealed: Literal[695] ```py class MyBox[T]: - data: T - - def __init__(self, data: T): - self.data = data + data: T + + def __init__(self, data: T): + self.data = data + # TODO not error on the subscripting -class MySecureBox[T](MyBox[T]): # error: [non-subscriptable] - pass +class MySecureBox[T](MyBox[T]): ... # error: [non-subscriptable] + secure_box: MySecureBox[int] = MySecureBox(5) reveal_type(secure_box) # revealed: MySecureBox @@ -47,11 +50,12 @@ In type stubs, classes can reference themselves in their base class definitions. This should hold true even with generics at play. ```py path=a.pyi -class Seq[T]: - pass +class Seq[T]: ... + # TODO not error on the subscripting -class S[T](Seq[S]): # error: [non-subscriptable] - pass +class S[T](Seq[S]): ... # error: [non-subscriptable] + + reveal_type(S) # revealed: Literal[S] ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/import/basic.md b/crates/red_knot_python_semantic/resources/mdtest/import/basic.md index 6876ce3142..fb802bb215 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/import/basic.md +++ b/crates/red_knot_python_semantic/resources/mdtest/import/basic.md @@ -3,21 +3,25 @@ ## Class import following ```py -from b import C as D; E = D +from b import C as D + +E = D reveal_type(E) # revealed: Literal[C] ``` ```py path=b.py -class C: pass +class C: ... ``` ## Module member resolution ```py -import b; D = b.C +import b + +D = b.C reveal_type(D) # revealed: Literal[C] ``` ```py path=b.py -class C: pass +class C: ... ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/import/builtins.md b/crates/red_knot_python_semantic/resources/mdtest/import/builtins.md index 9f5044c484..b029221bce 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/import/builtins.md +++ b/crates/red_knot_python_semantic/resources/mdtest/import/builtins.md @@ -1,6 +1,8 @@ # Importing builtin module ```py -import builtins; x = builtins.copyright +import builtins + +x = builtins.copyright reveal_type(x) # revealed: Literal[copyright] ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/import/conditional.md b/crates/red_knot_python_semantic/resources/mdtest/import/conditional.md index 199d4c1302..9fd0e09bef 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/import/conditional.md +++ b/crates/red_knot_python_semantic/resources/mdtest/import/conditional.md @@ -12,6 +12,7 @@ reveal_type(y) # revealed: Unbound | Literal[3] ```py from maybe_unbound import x, y + reveal_type(x) # revealed: Literal[3] reveal_type(y) # revealed: Literal[3] ``` @@ -30,6 +31,7 @@ Importing an annotated name prefers the declared type over the inferred type: ```py from maybe_unbound_annotated import x, y + reveal_type(x) # revealed: Literal[3] reveal_type(y) # revealed: int ``` @@ -44,11 +46,13 @@ def f(): ... if flag: from c import f else: + def f(): ... ``` ```py from b import f + # TODO: We should disambiguate in such cases, showing `Literal[b.f, c.f]`. reveal_type(f) # revealed: Literal[f, f] ``` @@ -71,5 +75,6 @@ else: ```py from b import x + reveal_type(x) # revealed: int ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/import/errors.md b/crates/red_knot_python_semantic/resources/mdtest/import/errors.md index c611f40c7e..1ed943cd13 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/import/errors.md +++ b/crates/red_knot_python_semantic/resources/mdtest/import/errors.md @@ -4,6 +4,7 @@ ```py import bar # error: "Cannot resolve import `bar`" + reveal_type(bar) # revealed: Unknown ``` @@ -11,6 +12,7 @@ reveal_type(bar) # revealed: Unknown ```py from bar import baz # error: "Cannot resolve import `bar`" + reveal_type(baz) # revealed: Unknown ``` @@ -21,6 +23,7 @@ reveal_type(baz) # revealed: Unknown ```py from a import thing # error: "Module `a` has no member `thing`" + reveal_type(thing) # revealed: Unknown ``` @@ -28,6 +31,7 @@ reveal_type(thing) # revealed: Unknown ```py path=a.py import foo as foo # error: "Cannot resolve import `foo`" + reveal_type(foo) # revealed: Unknown ``` @@ -36,6 +40,7 @@ import" violation: ```py from a import foo + reveal_type(foo) # revealed: Unknown ``` @@ -48,5 +53,5 @@ x: int ```py from b import x -x = 'foo' # error: [invalid-assignment] "Object of type `Literal["foo"]" +x = "foo" # error: [invalid-assignment] "Object of type `Literal["foo"]" ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/import/relative.md b/crates/red_knot_python_semantic/resources/mdtest/import/relative.md index ebbccc8bb7..be9a3168b1 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/import/relative.md +++ b/crates/red_knot_python_semantic/resources/mdtest/import/relative.md @@ -7,6 +7,7 @@ ```py path=package/bar.py from .foo import X # error: [unresolved-import] + reveal_type(X) # revealed: Unknown ``` @@ -21,6 +22,7 @@ X = 42 ```py path=package/bar.py from .foo import X + reveal_type(X) # revealed: Literal[42] ``` @@ -35,6 +37,7 @@ X = 42 ```py path=package/bar.py from .foo.bar.baz import X + reveal_type(X) # revealed: Literal[42] ``` @@ -46,6 +49,7 @@ X = 42 ```py path=package/bar.py from . import X + reveal_type(X) # revealed: Literal[42] ``` @@ -53,6 +57,7 @@ reveal_type(X) # revealed: Literal[42] ```py path=package/bar.py from . import X # error: [unresolved-import] + reveal_type(X) # revealed: Unknown ``` @@ -60,6 +65,7 @@ reveal_type(X) # revealed: Unknown ```py path=package/__init__.py from .foo import X + reveal_type(X) # revealed: Literal[42] ``` @@ -71,6 +77,7 @@ X = 42 ```py path=package/__init__.py from .foo import X # error: [unresolved-import] + reveal_type(X) # revealed: Unknown ``` @@ -85,6 +92,7 @@ X = 42 ```py path=package/subpackage/subsubpackage/bar.py from ...foo import X + reveal_type(X) # revealed: Literal[42] ``` @@ -99,6 +107,7 @@ x ```py path=package/bar.py from .foo import x # error: [unresolved-import] + reveal_type(x) # revealed: Unknown ``` @@ -114,6 +123,7 @@ X = 42 ```py path=package/bar.py # TODO: support submodule imports from . import foo # error: [unresolved-import] + y = foo.X # TODO: should be `Literal[42]` diff --git a/crates/red_knot_python_semantic/resources/mdtest/import/stubs.md b/crates/red_knot_python_semantic/resources/mdtest/import/stubs.md index 9b6fb7f0ad..151b9cc110 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/import/stubs.md +++ b/crates/red_knot_python_semantic/resources/mdtest/import/stubs.md @@ -4,6 +4,7 @@ ```py from b import x + y = x reveal_type(y) # revealed: int ``` @@ -16,6 +17,7 @@ x: int ```py from b import x + y = x reveal_type(y) # revealed: int ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/literal/collections/tuple.md b/crates/red_knot_python_semantic/resources/mdtest/literal/collections/tuple.md index deaf60cb27..ef77802f6c 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/literal/collections/tuple.md +++ b/crates/red_knot_python_semantic/resources/mdtest/literal/collections/tuple.md @@ -9,9 +9,9 @@ reveal_type(()) # revealed: tuple[()] ## Heterogeneous tuple ```py -reveal_type((1, 'a')) # revealed: tuple[Literal[1], Literal["a"]] +reveal_type((1, "a")) # revealed: tuple[Literal[1], Literal["a"]] reveal_type((1, (2, 3))) # revealed: tuple[Literal[1], tuple[Literal[2], Literal[3]]] -reveal_type(((1, 'a'), 2)) # revealed: tuple[tuple[Literal[1], Literal["a"]], Literal[2]] +reveal_type(((1, "a"), 2)) # revealed: tuple[tuple[Literal[1], Literal["a"]], Literal[2]] ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/literal/f_string.md b/crates/red_knot_python_semantic/resources/mdtest/literal/f_string.md index 30c72531ce..5be1b2a271 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/literal/f_string.md +++ b/crates/red_knot_python_semantic/resources/mdtest/literal/f_string.md @@ -7,27 +7,27 @@ x = 0 y = str() z = False -reveal_type(f'hello') # revealed: Literal["hello"] -reveal_type(f'h {x}') # revealed: Literal["h 0"] -reveal_type('one ' f'single ' f'literal') # revealed: Literal["one single literal"] -reveal_type('first ' f'second({x})' f' third') # revealed: Literal["first second(0) third"] -reveal_type(f'-{y}-') # revealed: str -reveal_type(f'-{y}-' f'--' '--') # revealed: str -reveal_type(f'{z} == {False} is {True}') # revealed: Literal["False == False is True"] +reveal_type(f"hello") # revealed: Literal["hello"] +reveal_type(f"h {x}") # revealed: Literal["h 0"] +reveal_type("one " f"single " f"literal") # revealed: Literal["one single literal"] +reveal_type("first " f"second({x})" f" third") # revealed: Literal["first second(0) third"] +reveal_type(f"-{y}-") # revealed: str +reveal_type(f"-{y}-" f"--" "--") # revealed: str +reveal_type(f"{z} == {False} is {True}") # revealed: Literal["False == False is True"] ``` ## Conversion Flags ```py -string = 'hello' +string = "hello" # TODO: should be `Literal["'hello'"]` -reveal_type(f'{string!r}') # revealed: str +reveal_type(f"{string!r}") # revealed: str ``` ## Format Specifiers ```py # TODO: should be `Literal["01"]` -reveal_type(f'{1:02}') # revealed: str +reveal_type(f"{1:02}") # revealed: str ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/literal/string.md b/crates/red_knot_python_semantic/resources/mdtest/literal/string.md index da5f469735..44a1ed056e 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/literal/string.md +++ b/crates/red_knot_python_semantic/resources/mdtest/literal/string.md @@ -4,15 +4,18 @@ ```py reveal_type("Hello") # revealed: Literal["Hello"] -reveal_type('world') # revealed: Literal["world"] -reveal_type("Guten " + 'Tag') # revealed: Literal["Guten Tag"] -reveal_type('bon ' + "jour") # revealed: Literal["bon jour"] +reveal_type("world") # revealed: Literal["world"] +reveal_type("Guten " + "Tag") # revealed: Literal["Guten Tag"] +reveal_type("bon " + "jour") # revealed: Literal["bon jour"] ``` ## Nested Quotes ```py reveal_type('I say "hello" to you') # revealed: Literal["I say \"hello\" to you"] -reveal_type("You say \"hey\" back") # revealed: Literal["You say \"hey\" back"] + +# revealed: Literal["You say \"hey\" back"] +reveal_type("You say \"hey\" back") # fmt: skip + reveal_type('No "closure here') # revealed: Literal["No \"closure here"] ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/loops/async_for_loops.md b/crates/red_knot_python_semantic/resources/mdtest/loops/async_for_loops.md index c09a60dd1b..ba6c471312 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/loops/async_for_loops.md +++ b/crates/red_knot_python_semantic/resources/mdtest/loops/async_for_loops.md @@ -33,7 +33,7 @@ async def foo(): def __aiter__(self) -> IntAsyncIterator: return IntAsyncIterator() - #TODO(Alex): async iterables/iterators! + # TODO(Alex): async iterables/iterators! async for x in IntAsyncIterable(): pass diff --git a/crates/red_knot_python_semantic/resources/mdtest/loops/for_loop.md b/crates/red_knot_python_semantic/resources/mdtest/loops/for_loop.md index 95cf6e34cb..66d7564d0e 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/loops/for_loop.md +++ b/crates/red_knot_python_semantic/resources/mdtest/loops/for_loop.md @@ -7,10 +7,12 @@ class IntIterator: def __next__(self) -> int: return 42 + class IntIterable: def __iter__(self) -> IntIterator: return IntIterator() + for x in IntIterable(): pass @@ -24,11 +26,13 @@ class IntIterator: def __next__(self) -> int: return 42 + class IntIterable: def __iter__(self) -> IntIterator: return IntIterator() -x = 'foo' + +x = "foo" for x in IntIterable(): pass @@ -43,14 +47,16 @@ class IntIterator: def __next__(self) -> int: return 42 + class IntIterable: def __iter__(self) -> IntIterator: return IntIterator() + for x in IntIterable(): pass else: - x = 'foo' + x = "foo" reveal_type(x) # revealed: Literal["foo"] ``` @@ -62,15 +68,17 @@ class IntIterator: def __next__(self) -> int: return 42 + class IntIterable: def __iter__(self) -> IntIterator: return IntIterator() + for x in IntIterable(): if x > 5: break else: - x = 'foo' + x = "foo" reveal_type(x) # revealed: int | Literal["foo"] ``` @@ -82,6 +90,7 @@ class OldStyleIterable: def __getitem__(self, key: int) -> int: return 42 + for x in OldStyleIterable(): pass @@ -91,7 +100,7 @@ reveal_type(x) # revealed: Unbound | int ## With heterogeneous tuple ```py -for x in (1, 'a', b'foo'): +for x in (1, "a", b"foo"): pass reveal_type(x) # revealed: Unbound | Literal[1] | Literal["a"] | Literal[b"foo"] @@ -106,6 +115,7 @@ class NotIterable: else: __iter__ = None + for x in NotIterable(): # error: "Object of type `NotIterable` is not iterable" pass @@ -129,6 +139,7 @@ class NotIterable: __iter__ = None + for x in NotIterable(): # error: "Object of type `NotIterable` is not iterable" pass ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/loops/iterators.md b/crates/red_knot_python_semantic/resources/mdtest/loops/iterators.md index b9b8ae40b9..2dfbd026b8 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/loops/iterators.md +++ b/crates/red_knot_python_semantic/resources/mdtest/loops/iterators.md @@ -3,15 +3,18 @@ ## Yield must be iterable ```py -class NotIterable: pass +class NotIterable: ... + class Iterator: def __next__(self) -> int: return 42 + class Iterable: def __iter__(self) -> Iterator: ... + def generator_function(): yield from Iterable() yield from NotIterable() # error: "Object of type `NotIterable` is not iterable" diff --git a/crates/red_knot_python_semantic/resources/mdtest/narrow/conditionals_is.md b/crates/red_knot_python_semantic/resources/mdtest/narrow/conditionals_is.md index d215be4bc2..3d9af15a64 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/narrow/conditionals_is.md +++ b/crates/red_knot_python_semantic/resources/mdtest/narrow/conditionals_is.md @@ -14,8 +14,8 @@ reveal_type(x) # revealed: None | Literal[1] ## `is` for other types ```py -class A: - ... +class A: ... + x = A() y = x if flag else None diff --git a/crates/red_knot_python_semantic/resources/mdtest/scopes/builtin.md b/crates/red_knot_python_semantic/resources/mdtest/scopes/builtin.md index 7be6c7531b..88698d3cb9 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/scopes/builtin.md +++ b/crates/red_knot_python_semantic/resources/mdtest/scopes/builtin.md @@ -9,9 +9,11 @@ with the conditionally-defined type: def returns_bool() -> bool: return True + if returns_bool(): copyright = 1 + def f(): reveal_type(copyright) # revealed: Literal[copyright] | Literal[1] ``` @@ -24,9 +26,11 @@ Same is true if the name is annotated: def returns_bool() -> bool: return True + if returns_bool(): copyright: int = 1 + def f(): reveal_type(copyright) # revealed: Literal[copyright] | int ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/shadowing/class.md b/crates/red_knot_python_semantic/resources/mdtest/shadowing/class.md index 8267bfd635..ef50b25a66 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/shadowing/class.md +++ b/crates/red_knot_python_semantic/resources/mdtest/shadowing/class.md @@ -3,7 +3,9 @@ ## Implicit error ```py -class C: pass +class C: ... + + C = 1 # error: "Implicit shadowing of class `C`; annotate to make it explicit if this is intentional" ``` @@ -12,6 +14,8 @@ C = 1 # error: "Implicit shadowing of class `C`; annotate to make it explicit i No diagnostic is raised in the case of explicit shadowing: ```py -class C: pass +class C: ... + + C: int = 1 ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/shadowing/function.md b/crates/red_knot_python_semantic/resources/mdtest/shadowing/function.md index c6113a62dd..bd283babd3 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/shadowing/function.md +++ b/crates/red_knot_python_semantic/resources/mdtest/shadowing/function.md @@ -12,13 +12,17 @@ def f(x: str): ## Implicit error ```py path=a.py -def f(): pass +def f(): ... + + f = 1 # error: "Implicit shadowing of function `f`; annotate to make it explicit if this is intentional" ``` ## Explicit shadowing ```py path=a.py -def f(): pass +def f(): ... + + f: int = 1 ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/shadowing/variable_declaration.md b/crates/red_knot_python_semantic/resources/mdtest/shadowing/variable_declaration.md index a896987baa..ebce13cced 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/shadowing/variable_declaration.md +++ b/crates/red_knot_python_semantic/resources/mdtest/shadowing/variable_declaration.md @@ -7,5 +7,5 @@ if flag: x: str else: x: int -x: bytes = b'foo' +x: bytes = b"foo" ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/stubs/class.md b/crates/red_knot_python_semantic/resources/mdtest/stubs/class.md index 94cb3b158c..f962c2d037 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/stubs/class.md +++ b/crates/red_knot_python_semantic/resources/mdtest/stubs/class.md @@ -6,5 +6,7 @@ In type stubs, classes can reference themselves in their base class definitions. ```py path=a.pyi class C(C): ... + + reveal_type(C) # revealed: Literal[C] ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/subscript/bytes.md b/crates/red_knot_python_semantic/resources/mdtest/subscript/bytes.md index 58eda3ac46..0e71cb814b 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/subscript/bytes.md +++ b/crates/red_knot_python_semantic/resources/mdtest/subscript/bytes.md @@ -3,8 +3,8 @@ ## Simple ```py -reveal_type(b'red' b'knot') # revealed: Literal[b"redknot"] -reveal_type(b'hello') # revealed: Literal[b"hello"] -reveal_type(b'world' + b'!') # revealed: Literal[b"world!"] -reveal_type(b'\xff\x00') # revealed: Literal[b"\xff\x00"] +reveal_type(b"red" b"knot") # revealed: Literal[b"redknot"] +reveal_type(b"hello") # revealed: Literal[b"hello"] +reveal_type(b"world" + b"!") # revealed: Literal[b"world!"] +reveal_type(b"\xff\x00") # revealed: Literal[b"\xff\x00"] ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/subscript/class.md b/crates/red_knot_python_semantic/resources/mdtest/subscript/class.md index d00fe34cd7..2423749e69 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/subscript/class.md +++ b/crates/red_knot_python_semantic/resources/mdtest/subscript/class.md @@ -3,7 +3,9 @@ ## Class getitem unbound ```py -class NotSubscriptable: pass +class NotSubscriptable: ... + + a = NotSubscriptable[0] # error: "Cannot subscript object of type `Literal[NotSubscriptable]` with no `__class_getitem__` method" ``` @@ -14,6 +16,7 @@ class Identity: def __class_getitem__(cls, item: int) -> str: return item + reveal_type(Identity[0]) # revealed: str ``` @@ -22,15 +25,20 @@ reveal_type(Identity[0]) # revealed: str ```py flag = True -class Identity: + +class UnionClassGetItem: if flag: + def __class_getitem__(cls, item: int) -> str: return item + else: + def __class_getitem__(cls, item: int) -> int: return item -reveal_type(Identity[0]) # revealed: str | int + +reveal_type(UnionClassGetItem[0]) # revealed: str | int ``` ## Class getitem with class union @@ -38,21 +46,21 @@ reveal_type(Identity[0]) # revealed: str | int ```py flag = True -class Identity1: + +class A: def __class_getitem__(cls, item: int) -> str: return item -class Identity2: + +class B: def __class_getitem__(cls, item: int) -> int: return item -if flag: - a = Identity1 -else: - a = Identity2 -reveal_type(a) # revealed: Literal[Identity1, Identity2] -reveal_type(a[0]) # revealed: str | int +x = A if flag else B + +reveal_type(x) # revealed: Literal[A, B] +reveal_type(x[0]) # revealed: str | int ``` ## Class getitem with unbound method union @@ -61,14 +69,19 @@ reveal_type(a[0]) # revealed: str | int flag = True if flag: - class Identity: - def __class_getitem__(self, x: int) -> str: - pass -else: - class Identity: pass -a = Identity[42] # error: [call-non-callable] "Method `__class_getitem__` of type `Literal[__class_getitem__] | Unbound` is not callable on object of type `Literal[Identity, Identity]`" -reveal_type(a) # revealed: str | Unknown + class Spam: + def __class_getitem__(self, x: int) -> str: + return "foo" + +else: + + class Spam: ... + + +# error: [call-non-callable] "Method `__class_getitem__` of type `Literal[__class_getitem__] | Unbound` is not callable on object of type `Literal[Spam, Spam]`" +# revealed: str | Unknown +reveal_type(Spam[42]) ``` ## TODO: Class getitem non-class union @@ -77,13 +90,16 @@ reveal_type(a) # revealed: str | Unknown flag = True if flag: - class Identity: - def __class_getitem__(self, x: int) -> str: - pass -else: - Identity = 1 -a = Identity[42] # error: "Cannot subscript object of type `Literal[Identity] | Literal[1]` with no `__getitem__` method" -# TODO: should _probably_ emit `str | Unknown` -reveal_type(a) # revealed: Unknown + class Eggs: + def __class_getitem__(self, x: int) -> str: + return "foo" + +else: + Eggs = 1 + +a = Eggs[42] # error: "Cannot subscript object of type `Literal[Eggs] | Literal[1]` with no `__getitem__` method" + +# TODO: should _probably_ emit `str | Unknown` +reveal_type(a) # revealed: Unknown ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/subscript/instance.md b/crates/red_knot_python_semantic/resources/mdtest/subscript/instance.md index e0edc55ba9..73ce30ec5c 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/subscript/instance.md +++ b/crates/red_knot_python_semantic/resources/mdtest/subscript/instance.md @@ -3,7 +3,9 @@ ## Getitem unbound ```py -class NotSubscriptable: pass +class NotSubscriptable: ... + + a = NotSubscriptable()[0] # error: "Cannot subscript object of type `NotSubscriptable` with no `__getitem__` method" ``` @@ -13,6 +15,7 @@ a = NotSubscriptable()[0] # error: "Cannot subscript object of type `NotSubscri class NotSubscriptable: __getitem__ = None + a = NotSubscriptable()[0] # error: "Method `__getitem__` of type `None` is not callable on object of type `NotSubscriptable`" ``` @@ -23,6 +26,7 @@ class Identity: def __getitem__(self, index: int) -> int: return index + reveal_type(Identity()[0]) # revealed: int ``` @@ -31,13 +35,18 @@ reveal_type(Identity()[0]) # revealed: int ```py flag = True + class Identity: if flag: + def __getitem__(self, index: int) -> int: return index + else: + def __getitem__(self, index: int) -> str: return str(index) + reveal_type(Identity()[0]) # revealed: int | str ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/subscript/string.md b/crates/red_knot_python_semantic/resources/mdtest/subscript/string.md index 6d73ac3355..0e1c21389a 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/subscript/string.md +++ b/crates/red_knot_python_semantic/resources/mdtest/subscript/string.md @@ -3,7 +3,7 @@ ## Simple ```py -s = 'abcde' +s = "abcde" reveal_type(s[0]) # revealed: Literal["a"] reveal_type(s[1]) # revealed: Literal["b"] @@ -14,7 +14,7 @@ a = s[8] # error: [index-out-of-bounds] "Index 8 is out of bounds for string `L reveal_type(a) # revealed: Unknown b = s[-8] # error: [index-out-of-bounds] "Index -8 is out of bounds for string `Literal["abcde"]` with length 5" -reveal_type(b) # revealed: Unknown +reveal_type(b) # revealed: Unknown ``` ## Function return @@ -23,7 +23,8 @@ reveal_type(b) # revealed: Unknown def add(x: int, y: int) -> int: return x + y -a = 'abcde'[add(0, 1)] + +a = "abcde"[add(0, 1)] # TODO: Support overloads... Should be `str` reveal_type(a) # revealed: @Todo ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/subscript/tuple.md b/crates/red_knot_python_semantic/resources/mdtest/subscript/tuple.md index 23b3537f0b..7545e8d1c5 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/subscript/tuple.md +++ b/crates/red_knot_python_semantic/resources/mdtest/subscript/tuple.md @@ -3,7 +3,7 @@ ## Basic ```py -t = (1, 'a', 'b') +t = (1, "a", "b") reveal_type(t[0]) # revealed: Literal[1] reveal_type(t[1]) # revealed: Literal["a"] diff --git a/crates/red_knot_python_semantic/resources/mdtest/unary/integers.md b/crates/red_knot_python_semantic/resources/mdtest/unary/integers.md index c91755981f..ec439977ed 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/unary/integers.md +++ b/crates/red_knot_python_semantic/resources/mdtest/unary/integers.md @@ -19,7 +19,7 @@ reveal_type(-True) # revealed: Literal[-1] ## Unary Bitwise Inversion ```py -reveal_type(~0) # revealed: Literal[-1] +reveal_type(~0) # revealed: Literal[-1] reveal_type(~1) # revealed: Literal[-2] reveal_type(~True) # revealed: Literal[-2] ``` diff --git a/crates/red_knot_python_semantic/resources/mdtest/unary/not.md b/crates/red_knot_python_semantic/resources/mdtest/unary/not.md index f657ce0e40..b85cb2f31a 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/unary/not.md +++ b/crates/red_knot_python_semantic/resources/mdtest/unary/not.md @@ -12,9 +12,11 @@ reveal_type(not not None) # revealed: Literal[False] ```py from typing import reveal_type + def f(): return 1 + reveal_type(not f) # revealed: Literal[False] # TODO Unknown should not be part of the type of typing.reveal_type # reveal_type(not reveal_type) revealed: Literal[False] @@ -23,7 +25,8 @@ reveal_type(not f) # revealed: Literal[False] ## Module ```py -import b; import warnings +import b +import warnings reveal_type(not b) # revealed: Literal[False] diff --git a/crates/red_knot_python_semantic/resources/mdtest/unpacking.md b/crates/red_knot_python_semantic/resources/mdtest/unpacking.md index 974d672b48..be4ef400b3 100644 --- a/crates/red_knot_python_semantic/resources/mdtest/unpacking.md +++ b/crates/red_knot_python_semantic/resources/mdtest/unpacking.md @@ -191,7 +191,7 @@ reveal_type(d) # revealed: Literal[2] ### Simple unpacking ```py -a, b = 'ab' +a, b = "ab" reveal_type(a) # revealed: LiteralString reveal_type(b) # revealed: LiteralString ``` @@ -200,7 +200,7 @@ reveal_type(b) # revealed: LiteralString ```py # TODO: Add diagnostic (there aren't enough values to unpack) -a, b, c = 'ab' +a, b, c = "ab" reveal_type(a) # revealed: LiteralString reveal_type(b) # revealed: LiteralString reveal_type(c) # revealed: Unknown @@ -210,7 +210,7 @@ reveal_type(c) # revealed: Unknown ```py # TODO: Add diagnostic (too many values to unpack) -a, b = 'abc' +a, b = "abc" reveal_type(a) # revealed: LiteralString reveal_type(b) # revealed: LiteralString ```