From f01ba5e017baf5a0ee581819d2c8cced7ea0237c Mon Sep 17 00:00:00 2001 From: Oleh Prypin Date: Tue, 1 Oct 2024 23:44:48 -0700 Subject: [PATCH] Print union types with the pipe syntax E.g. `Foo | Bar` rather than `Union[Foo, Bar]` and `Foo | None` rather than `Optional[None]` This affect error messages, `reveal_type`, production of pyi files. PiperOrigin-RevId: 681316241 --- pytype/abstract/abstract_test.py | 4 +- pytype/abstract/mixin.py | 2 +- pytype/annotation_utils.py | 3 +- pytype/constant_folding_test.py | 52 ++++---- pytype/convert_test.py | 4 +- pytype/errors/CMakeLists.txt | 1 + pytype/errors/errors.py | 3 + pytype/load_pytd_test.py | 11 +- pytype/pretty_printer_base.py | 9 +- pytype/pyi/definitions.py | 7 +- pytype/pyi/parser.py | 2 +- pytype/pyi/parser_test.py | 122 ++++++++---------- pytype/pytd/optimize.py | 32 ++--- pytype/pytd/optimize_test.py | 4 +- pytype/pytd/pep484.py | 5 + pytype/pytd/pep484_test.py | 4 +- pytype/pytd/printer.py | 73 +++-------- pytype/pytd/pytd_utils_test.py | 25 ++-- pytype/pytd/visitors.py | 11 +- pytype/pytd/visitors_test.py | 34 ++--- pytype/rewrite/output_test.py | 6 +- pytype/rewrite/tests/test_basic.py | 2 +- pytype/tests/test_annotations.py | 20 +-- pytype/tests/test_anystr2.py | 4 +- pytype/tests/test_async_generators.py | 12 +- pytype/tests/test_attributes1.py | 6 +- pytype/tests/test_attributes2.py | 2 +- pytype/tests/test_builtins2.py | 6 +- pytype/tests/test_builtins3.py | 2 +- pytype/tests/test_builtins4.py | 4 +- pytype/tests/test_checker.py | 10 +- pytype/tests/test_classes1.py | 4 +- pytype/tests/test_coroutine.py | 2 +- pytype/tests/test_dataclasses.py | 2 +- pytype/tests/test_enums.py | 9 +- pytype/tests/test_errors1.py | 52 ++++---- pytype/tests/test_errors2.py | 28 ++-- pytype/tests/test_exceptions2.py | 2 +- pytype/tests/test_final.py | 2 +- pytype/tests/test_generic2.py | 2 +- pytype/tests/test_import1.py | 4 +- pytype/tests/test_list1.py | 2 +- pytype/tests/test_match2.py | 2 +- pytype/tests/test_methods1.py | 2 +- pytype/tests/test_protocols2.py | 14 +- pytype/tests/test_pyi2.py | 8 +- pytype/tests/test_recursive_types.py | 25 ++-- pytype/tests/test_stdlib2.py | 4 +- pytype/tests/test_super1.py | 2 +- pytype/tests/test_tuple2.py | 16 +-- pytype/tests/test_type_comments1.py | 2 +- pytype/tests/test_type_comments2.py | 2 +- pytype/tests/test_typed_dict.py | 4 +- pytype/tests/test_typevar2.py | 18 ++- pytype/tests/test_typing1.py | 6 +- pytype/tests/test_typing2.py | 16 +-- pytype/tests/test_typing_namedtuple2.py | 2 +- pytype/tests/test_typing_self.py | 12 +- pytype/tests/test_unions.py | 10 +- pytype/tests/test_unpack.py | 2 +- pytype/tests/test_variable_annotations.py | 2 +- .../tools/annotate_ast/annotate_ast_test.py | 6 +- pytype/tools/traces/traces_test.py | 31 +++-- 63 files changed, 362 insertions(+), 415 deletions(-) diff --git a/pytype/abstract/abstract_test.py b/pytype/abstract/abstract_test.py index 4b7a69533..069f0d613 100644 --- a/pytype/abstract/abstract_test.py +++ b/pytype/abstract/abstract_test.py @@ -463,7 +463,7 @@ def test_signature_annotations(self): ), ) self.assertEqual( - repr(sig), "def f(self: Any, *args: Tuple[Any, ...]) -> Any" + repr(sig), "def f(self: Any, *args: tuple[Any, ...]) -> Any" ) self.assertIs(sig.annotations["self"], self._ctx.convert.unsolvable) args_type = sig.annotations["args"] @@ -1221,7 +1221,7 @@ def test_signature_func_output(self): ) fp = self._ctx.pytd_convert.value_to_pytd_def(node, f, f.name) f_str = ( - "def test(a: str, b: int = ..., *c: str, d: Dict[str, int] = ...," + "def test(a: str, b: int = ..., *c: str, d: dict[str, int] = ...," " e: int, **f: str) -> str: ..." ) self.assertEqual(pytd_utils.Print(fp), f_str) diff --git a/pytype/abstract/mixin.py b/pytype/abstract/mixin.py index 52611eaa8..b8bffb9f7 100644 --- a/pytype/abstract/mixin.py +++ b/pytype/abstract/mixin.py @@ -163,7 +163,7 @@ def get_special_attribute(self, node, name, valself): class NestedAnnotation(metaclass=MixinMeta): """An annotation containing inner types, such as a Union. - For example, in `Union[int, str]`, `int` and `str` are the annotation's inner + For example, in `int | str`, `int` and `str` are the annotation's inner types. Classes that inherit from this mixin should implement: get_inner_types(): Returns a sequence of (key, typ) of the inner types. A diff --git a/pytype/annotation_utils.py b/pytype/annotation_utils.py index cb9ed98c7..2cb8174a8 100644 --- a/pytype/annotation_utils.py +++ b/pytype/annotation_utils.py @@ -521,8 +521,7 @@ def _log_illegal_params(self, illegal_params, stack, typ, name): frame_name = method.name details += f" for {desc} {frame_name!r}" if "AnyStr" in out_of_scope_params: - str_type = "Union[str, bytes]" - details += f"\nNote: For all string types, use {str_type}." + details += "\nNote: For all string types, use `str | bytes`." self.ctx.errorlog.invalid_annotation(stack, typ, details, name) def eval_multi_arg_annotation(self, node, func, annot, stack): diff --git a/pytype/constant_folding_test.py b/pytype/constant_folding_test.py index 9ac8d0e78..dd9e6d4ae 100644 --- a/pytype/constant_folding_test.py +++ b/pytype/constant_folding_test.py @@ -257,23 +257,23 @@ def test_prim(self): def test_homogeneous_list(self): val = self._convert(("list", int)) - self.assertPytd(val, "List[int]") + self.assertPytd(val, "list[int]") def test_heterogeneous_list(self): val = self._convert(("list", (int, str))) - self.assertPytd(val, "List[Union[int, str]]") + self.assertPytd(val, "list[int | str]") def test_homogeneous_map(self): val = self._convert(("map", str, int)) - self.assertPytd(val, "Dict[str, int]") + self.assertPytd(val, "dict[str, int]") def test_heterogeneous_map(self): val = self._convert(("map", (str, int), (("list", str), str))) - self.assertPytd(val, "Dict[Union[int, str], Union[List[str], str]]") + self.assertPytd(val, "dict[int | str, list[str] | str]") def test_tuple(self): val = self._convert(("tuple", str, int, bool)) - self.assertPytd(val, "Tuple[str, int, bool]") + self.assertPytd(val, "tuple[str, int, bool]") class PyvalTest(TypeBuilderTestBase): @@ -291,7 +291,7 @@ def test_simple_list(self): """) a = defs["a"].data[0] b = defs["b"].data[0] - self.assertPytd(a, "List[Union[int, str]]") + self.assertPytd(a, "list[int | str]") self.assertPytd(b, "str") self.assertEqual(a.pyval[0].data[0].pyval, 1) @@ -303,9 +303,9 @@ def test_nested_list(self): a = defs["a"].data[0] b = defs["b"].data[0] c = defs["c"].data[0] - t1 = "List[Union[int, str]]" - t2 = "List[int]" - self.assertPytd(a, f"List[Union[{t2}, {t1}]]") + t1 = "list[int | str]" + t2 = "list[int]" + self.assertPytd(a, f"list[{t2} | {t1}]") self.assertPytd(b, t1) self.assertPytd(c, t2) @@ -318,12 +318,12 @@ def test_long_list(self): b = defs["b"].data[0] c = defs["c"].data[0] d = defs["d"].data[0] - t1 = "List[int]" - t2 = "List[str]" - self.assertPytd(a, "List[Union[List[int], List[str]]]") + t1 = "list[int]" + t2 = "list[str]" + self.assertPytd(a, "list[list[int] | list[str]]") self.assertPytd(b, t1) self.assertPytd(c, t2) - self.assertPytd(d, "List[Union[List[int], List[str]]]") + self.assertPytd(d, "list[list[int] | list[str]]") def test_long_list_of_tuples(self): elts = [" (1, 2),", " ('a', False),"] * 82 @@ -334,12 +334,12 @@ def test_long_list_of_tuples(self): b = defs["b"].data[0] c = defs["c"].data[0] d = defs["d"].data[0] - t1 = "Tuple[int, int]" - t2 = "Tuple[str, bool]" - self.assertPytd(a, f"List[Union[{t1}, {t2}]]") + t1 = "tuple[int, int]" + t2 = "tuple[str, bool]" + self.assertPytd(a, f"list[{t1} | {t2}]") self.assertPytd(b, t1) self.assertPytd(c, t2) - self.assertPytd(d, f"List[Union[{t1}, {t2}]]") + self.assertPytd(d, f"list[{t1} | {t2}]") def test_simple_map(self): defs = self._process(""" @@ -350,7 +350,7 @@ def test_simple_map(self): a = defs["a"].data[0] b = defs["b"].data[0] c = defs["c"].data[0] - self.assertPytd(a, "Dict[str, Union[int, str]]") + self.assertPytd(a, "dict[str, int | str]") self.assertPytd(b, "int") self.assertPytd(c, "str") self.assertEqual(a.pyval["b"].data[0].pyval, 1) @@ -377,9 +377,9 @@ def test_nested_map(self): b = defs["b"].data[0] c = defs["c"].data[0] d = defs["d"].data[0] - t1 = "List[Union[int, str]]" - t2 = "Dict[str, Union[bool, int]]" - self.assertPytd(a, f"Dict[str, Union[{t2}, {t1}]]") + t1 = "list[int | str]" + t2 = "dict[str, bool | int]" + self.assertPytd(a, f"dict[str, {t2} | {t1}]") self.assertPytd(b, t1) self.assertPytd(c, t2) self.assertPytd(d, "int") @@ -401,14 +401,14 @@ def test_long_map(self): src = ["a = {"] + elts + ["}"] defs = self._process("\n".join(src)) a = defs["a"].data[0] - self.assertPytd(a, "Dict[str, List[int]]") + self.assertPytd(a, "dict[str, list[int]]") def test_long_map_with_tuple_keys(self): elts = [f" ({i}, True): 'a'," for i in range(64)] src = ["a = {"] + elts + ["}"] defs = self._process("\n".join(src)) a = defs["a"].data[0] - self.assertPytd(a, "Dict[Tuple[int, bool], str]") + self.assertPytd(a, "dict[tuple[int, bool], str]") self.assertFalse(a.pyval) def test_nested_long_map(self): @@ -426,10 +426,10 @@ def test_nested_long_map(self): d = defs["d"].data[0] e = defs["e"].data[0] self.assertPytd(a, "int") - self.assertPytd(b, "Dict[str, List[Union[bool, int]]]") - self.assertPytd(c, "Dict[str, int]") + self.assertPytd(b, "dict[str, list[bool | int]]") + self.assertPytd(c, "dict[str, int]") self.assertPytd(d, "int") - self.assertPytd(e, "List[Union[bool, int]]") + self.assertPytd(e, "list[bool | int]") if __name__ == "__main__": diff --git a/pytype/convert_test.py b/pytype/convert_test.py index 2eed447d4..a38abb73a 100644 --- a/pytype/convert_test.py +++ b/pytype/convert_test.py @@ -288,7 +288,7 @@ def f(*args: int): ... (sig,) = f.signatures annot = sig.signature.annotations["args"] self.assertEqual( - pytd_utils.Print(annot.to_pytd_type_of_instance()), "Tuple[int, ...]" + pytd_utils.Print(annot.to_pytd_type_of_instance()), "tuple[int, ...]" ) def test_function_with_starstarargs(self): @@ -304,7 +304,7 @@ def f(**kwargs: int): ... (sig,) = f.signatures annot = sig.signature.annotations["kwargs"] self.assertEqual( - pytd_utils.Print(annot.to_pytd_type_of_instance()), "Dict[str, int]" + pytd_utils.Print(annot.to_pytd_type_of_instance()), "dict[str, int]" ) def test_mro(self): diff --git a/pytype/errors/CMakeLists.txt b/pytype/errors/CMakeLists.txt index 97a78fdfd..3dd0adc66 100644 --- a/pytype/errors/CMakeLists.txt +++ b/pytype/errors/CMakeLists.txt @@ -19,6 +19,7 @@ py_library( pytype._utils pytype.debug pytype.pretty_printer_base + pytype.abstract.abstract pytype.pytd.pytd pytype.types.types ) diff --git a/pytype/errors/errors.py b/pytype/errors/errors.py index d6277eb68..1c59add47 100644 --- a/pytype/errors/errors.py +++ b/pytype/errors/errors.py @@ -11,6 +11,7 @@ from pytype import debug from pytype import pretty_printer_base from pytype import utils +from pytype.abstract import abstract from pytype.errors import error_printer from pytype.errors import error_types from pytype.pytd import slots @@ -1054,6 +1055,8 @@ def wrong_annotation_parameter_count( ): """Log an error for an annotation with the wrong number of parameters.""" base_type = self._pp.print_type_of_instance(annot) + if isinstance(annot, abstract.Union): + base_type = f"({base_type})" full_type = base_type + self._print_params_helper(params) if template: templated_type = f"{base_type}[{', '.join(template)}]" diff --git a/pytype/load_pytd_test.py b/pytype/load_pytd_test.py index eb466406a..180b9140d 100644 --- a/pytype/load_pytd_test.py +++ b/pytype/load_pytd_test.py @@ -405,7 +405,7 @@ def f() -> module1.x: ... ) module2 = loader.import_name("module2") (f,) = module2.Lookup("module2.f").signatures - self.assertEqual("List[int]", pytd_utils.Print(f.return_type)) + self.assertEqual("list[int]", pytd_utils.Print(f.return_type)) def test_import_map_congruence(self): with test_utils.Tempdir() as d: @@ -782,10 +782,9 @@ def f() -> List[int]: ... self.assertEqual( pytd_utils.Print(bar), textwrap.dedent(""" - import typing from builtins import list as List - def bar.f() -> typing.List[int]: ... + def bar.f() -> list[int]: ... """).strip(), ) @@ -976,7 +975,7 @@ def test_container(self): """, ) self.assertEqual( - pytd_utils.Print(ast.Lookup("b.Strings").type), "List[str]" + pytd_utils.Print(ast.Lookup("b.Strings").type), "list[str]" ) def test_union(self): @@ -992,13 +991,13 @@ def test_union(self): """, ) self.assertEqual( - pytd_utils.Print(ast.Lookup("b.Strings").type), "Union[str, List[str]]" + pytd_utils.Print(ast.Lookup("b.Strings").type), "str | list[str]" ) def test_bad_parameterization(self): with self.assertRaisesRegex( load_pytd.BadDependencyError, - r"Union\[T, List\[T\]\] expected 1 parameters, got 2", + r"T \| list\[T\] expected 1 parameters, got 2", ): self._import( a=""" diff --git a/pytype/pretty_printer_base.py b/pytype/pretty_printer_base.py index 9954a1911..3cd51aacd 100644 --- a/pytype/pretty_printer_base.py +++ b/pytype/pretty_printer_base.py @@ -88,13 +88,10 @@ def join_printed_types(self, typs: Iterable[str]) -> str: if literal_contents: literal = f"Literal[{', '.join(sorted(literal_contents))}]" new_types.append(literal) - if len(new_types) > 1: - out = f"Union[{', '.join(sorted(new_types))}]" - else: - out = new_types[0] + new_types.sort() if optional: - out = f"Optional[{out}]" - return out + new_types.append("None") + return " | ".join(new_types) else: # TODO(mdemello): change this to Never return "nothing" diff --git a/pytype/pyi/definitions.py b/pytype/pyi/definitions.py index a8ef78f96..0312ae740 100644 --- a/pytype/pyi/definitions.py +++ b/pytype/pyi/definitions.py @@ -589,11 +589,8 @@ def _is_builtin_or_typing_member(self, t): if t.name is None: return False module, _, name = t.name.rpartition(".") - return ( - not module - and name in pep484.BUILTIN_TO_TYPING - or module == "typing" - and name in pep484.ALL_TYPING_NAMES + return (not module and name in pep484.BUILTIN_TO_TYPING) or ( + module == "typing" and name in pep484.ALL_TYPING_NAMES ) def _check_for_illegal_parameters(self, base_type, parameters, is_callable): diff --git a/pytype/pyi/parser.py b/pytype/pyi/parser.py index 1e7e99d19..c0266a96b 100644 --- a/pytype/pyi/parser.py +++ b/pytype/pyi/parser.py @@ -271,7 +271,7 @@ def visit_BinOp(self, node): def visit_BoolOp(self, node): if isinstance(node.op, astlib.Or): - raise ParseError("Deprecated syntax `x or y`; use `Union[x, y]` instead") + raise ParseError("Deprecated syntax `x or y`; use `x | y` instead") else: raise ParseError(f"Unexpected operator {node.op}") diff --git a/pytype/pyi/parser_test.py b/pytype/pyi/parser_test.py index 45e8446ab..ca8d29e39 100644 --- a/pytype/pyi/parser_test.py +++ b/pytype/pyi/parser_test.py @@ -286,11 +286,9 @@ class B: ... C = A.B """, """ - from typing import Type - class A: class B: ... - C: Type[A.B] + C: type[A.B] """, ) @@ -302,9 +300,7 @@ class B: ... C = A.B """, """ - from typing import Type - - C: Type[A.B] + C: type[A.B] class A: class B: ... @@ -543,13 +539,13 @@ def func(x: T) -> T: ...""") def test_type_param_arguments(self): self.check(""" - from typing import List, TypeVar + from typing import TypeVar - T = TypeVar('T', List[int], List[str])""") + T = TypeVar('T', list[int], list[str])""") self.check(""" - from typing import List, TypeVar + from typing import TypeVar - T = TypeVar('T', bound=List[str])""") + T = TypeVar('T', bound=list[str])""") # 'covariant' and 'contravariant' are ignored for now. self.check( """ @@ -662,9 +658,7 @@ def test_all(self): __all__ = ['a'] """, """ - from typing import List - - __all__: List[str] = ... + __all__: list[str] = ... """, ) @@ -931,11 +925,11 @@ def test_ellipsis(self): # Tuple[T] and Tuple[T, ...] are distinct. self.check( "from typing import Tuple\n\nx = ... # type: Tuple[int]", - "from typing import Tuple\n\nx: Tuple[int]", + "x: tuple[int]", ) self.check( "from typing import Tuple\n\nx = ... # type: Tuple[int, ...]", - "from typing import Tuple\n\nx: Tuple[int, ...]", + "x: tuple[int, ...]", ) def test_tuple(self): @@ -945,9 +939,7 @@ def test_tuple(self): x = ... # type: Tuple[int, str]""", """ - from typing import Tuple - - x: Tuple[int, str]""", + x: tuple[int, str]""", ) self.check_error( """ @@ -966,9 +958,7 @@ def test_empty_tuple(self): def f() -> Tuple[()]: ... """, """ - from typing import Tuple - - def f() -> Tuple[()]: ... + def f() -> tuple[()]: ... """, ) @@ -2860,15 +2850,15 @@ def test_simple(self): def f(x: Alias[S]) -> S: ... def g(x: Alias[str]) -> str: ...""", """ - from typing import List, TypeVar + from typing import TypeVar - Alias = List[List[T]] + Alias = list[list[T]] S = TypeVar('S') T = TypeVar('T') - def f(x: List[List[S]]) -> S: ... - def g(x: List[List[str]]) -> str: ...""", + def f(x: list[list[S]]) -> S: ... + def g(x: list[list[str]]) -> str: ...""", ) def test_partial_replacement(self): @@ -2879,13 +2869,13 @@ def test_partial_replacement(self): V = TypeVar('V') def f(x: DictAlias[str]) -> None: ...""", """ - from typing import Dict, TypeVar + from typing import TypeVar - DictAlias = Dict[int, V] + DictAlias = dict[int, V] V = TypeVar('V') - def f(x: Dict[int, str]) -> None: ...""", + def f(x: dict[int, str]) -> None: ...""", ) def test_multiple_parameters(self): @@ -2897,14 +2887,14 @@ def test_multiple_parameters(self): V = TypeVar('V') def f(x: Alias[K, V]) -> Dict[K, V]: ...""", """ - from typing import Dict, List, TypeVar + from typing import TypeVar - Alias = List[Dict[K, V]] + Alias = list[dict[K, V]] K = TypeVar('K') V = TypeVar('V') - def f(x: List[Dict[K, V]]) -> Dict[K, V]: ...""", + def f(x: list[dict[K, V]]) -> dict[K, V]: ...""", ) def test_union(self): @@ -2916,14 +2906,14 @@ def test_union(self): S = TypeVar('S') def f(x: Alias[S, T]) -> Union[S, T]: ...""", """ - from typing import List, TypeVar, Union + from typing import TypeVar - Alias = Union[List[T], List[S]] + Alias = list[T] | list[S] S = TypeVar('S') T = TypeVar('T') - def f(x: Union[List[S], List[T]]) -> Union[S, T]: ...""", + def f(x: list[S] | list[T]) -> S | T: ...""", ) def test_repeated_type_parameter(self): @@ -2934,13 +2924,13 @@ def test_repeated_type_parameter(self): T = TypeVar('T') def f(x: Alias[str]) -> None: ...""", """ - from typing import Dict, TypeVar + from typing import TypeVar - Alias = Dict[T, T] + Alias = dict[T, T] T = TypeVar('T') - def f(x: Dict[str, str]) -> None: ...""", + def f(x: dict[str, str]) -> None: ...""", ) def test_wrong_parameter_count(self): @@ -2963,11 +2953,11 @@ def test_anystr(self): def f(x: Alias[str]) -> None: ... """, """ - from typing import AnyStr, List + from typing import AnyStr - Alias = List[AnyStr] + Alias = list[AnyStr] - def f(x: List[str]) -> None: ... + def f(x: list[str]) -> None: ... """, ) @@ -3077,9 +3067,9 @@ def test_multiple_parameters(self): x: Literal[True, 0, b"", "", None] """, """ - from typing import Literal, Optional + from typing import Literal - x: Optional[Literal[True, 0, b'', '']] + x: Literal[True, 0, b'', ''] | None """, ) @@ -3132,11 +3122,11 @@ def test_unnest(self): y: Literal[1, Literal[2, Literal[3]]] """, """ - from typing import Literal, Optional + from typing import Literal MyLiteralAlias = Literal[42] - x: Optional[Literal[42, True]] + x: Literal[42, True] | None y: Literal[1, 2, 3] """, ) @@ -3270,7 +3260,7 @@ def test_bad_literal(self): x: Literal[list[int]] """, 2, - "Literal[List[int]] not supported", + "Literal[list[int]] not supported", ) @@ -3620,11 +3610,11 @@ def test_attribute_access_and_call(self): def f() -> Annotated[list[int], a.b.C(3)]: ... """, """ - from typing import Annotated, Any, List + from typing import Annotated, Any a: Any - def f() -> Annotated[List[int], {'tag': 'call', 'fn': 'a.b.C', 'posargs': (3,), 'kwargs': {}}]: ... + def f() -> Annotated[list[int], {'tag': 'call', 'fn': 'a.b.C', 'posargs': (3,), 'kwargs': {}}]: ... """, ) @@ -3934,11 +3924,9 @@ def g(x: bool | str | float) -> None: ... def h(x: str | None) -> None: ... """, """ - from typing import Optional, Union - - def f(x: Union[int, str]) -> None: ... - def g(x: Union[bool, str, float]) -> None: ... - def h(x: Optional[str]) -> None: ... + def f(x: int | str) -> None: ... + def g(x: bool | str | float) -> None: ... + def h(x: str | None) -> None: ... """, ) @@ -3950,12 +3938,11 @@ def test_alias(self): def f(x: X | str) -> None: ... """, """ - from typing import Optional from typing_extensions import TypeAlias X = None - def f(x: Optional[str]) -> None: ... + def f(x: str | None) -> None: ... """, ) @@ -3971,10 +3958,9 @@ def test_typing_extensions(self): def f(x: List[object]) -> TypeGuard[List[str]]: ... """, """ - from typing import List from typing_extensions import TypeGuard - def f(x: List[object]) -> TypeGuard[List[str]]: ... + def f(x: list[object]) -> TypeGuard[list[str]]: ... """, ) @@ -3986,9 +3972,9 @@ def test_typing(self): def f(x: List[object]) -> TypeGuard[List[str]]: ... """, """ - from typing import List, TypeGuard + from typing import TypeGuard - def f(x: List[object]) -> TypeGuard[List[str]]: ... + def f(x: list[object]) -> TypeGuard[list[str]]: ... """, ) @@ -4169,14 +4155,14 @@ class A: def f(cls) -> Self: ... """, """ - from typing import Type, TypeVar + from typing import TypeVar from typing_extensions import Self _SelfA = TypeVar('_SelfA', bound=A) class A: @classmethod - def f(cls: Type[_SelfA]) -> _SelfA: ... + def f(cls: type[_SelfA]) -> _SelfA: ... """, ) @@ -4189,13 +4175,13 @@ class A: def __new__(cls) -> Self: ... """, """ - from typing import Type, TypeVar + from typing import TypeVar from typing_extensions import Self _SelfA = TypeVar('_SelfA', bound=A) class A: - def __new__(cls: Type[_SelfA]) -> _SelfA: ... + def __new__(cls: type[_SelfA]) -> _SelfA: ... """, ) @@ -4209,13 +4195,13 @@ class A: def f(self) -> List[Self]: ... """, """ - from typing import List, TypeVar + from typing import TypeVar from typing_extensions import Self _SelfA = TypeVar('_SelfA', bound=A) class A: - def f(self: _SelfA) -> List[_SelfA]: ... + def f(self: _SelfA) -> list[_SelfA]: ... """, ) @@ -4319,12 +4305,10 @@ class None: ... def f(x: Union[str, getattr(X, 'None')]) -> None: ... """, """ - from typing import Union - class X: class None: ... - def f(x: Union[str, X.None]) -> None: ... + def f(x: str | X.None) -> None: ... """, ) @@ -4370,10 +4354,10 @@ def test_tuple(self): def f(x: tuple[Unpack[_Ts]]): ... """, """ - from typing import Any, Tuple + from typing import Any from typing_extensions import TypeVarTuple, TypeVarTuple as _Ts, Unpack - def f(x: Tuple[Any, ...]) -> Any: ... + def f(x: tuple[Any, ...]) -> Any: ... """, ) diff --git a/pytype/pytd/optimize.py b/pytype/pytd/optimize.py index e8f01cf02..ba7565fa7 100644 --- a/pytype/pytd/optimize.py +++ b/pytype/pytd/optimize.py @@ -101,13 +101,13 @@ class SimplifyUnions(visitors.Visitor): """Remove duplicate or redundant entries in union types. For example, this transforms - a: Union[int, int] - b: Union[int, Any] - c: Union[int, int, float] + a: int | int + b: int | Any + c: int | int | float to a: int b: Any - c: Union[int, float] + c: int | float """ def VisitUnionType(self, union): @@ -151,7 +151,7 @@ def f(x: int) -> float: def f(x: int) -> int: raise IndexError() to - def f(x: int) -> Union[float, int]: + def f(x: int) -> float | int: raise IndexError() raise OverflowError() """ @@ -208,9 +208,9 @@ class CombineContainers(visitors.Visitor): """Change unions of containers to containers of unions. For example, this transforms - Union[list[int], list[float]] + list[int] | list[float] to - list[Union[int, float]] + list[int | float] . """ @@ -388,7 +388,7 @@ class SimplifyUnionsWithSuperclasses(visitors.Visitor): """Simplify Unions with superclasses. E.g., this changes - Union[int, bool] + int | bool to int since bool is a subclass of int. @@ -417,7 +417,7 @@ class FindCommonSuperClasses(visitors.Visitor): """Find common super classes. Optionally also uses abstract base classes. E.g., this changes - def f(x: Union[list, tuple], y: Union[frozenset, set]) -> Union[int, float] + def f(x: list | tuple, y: frozenset | set) -> int | float to def f(x: Sequence, y: Set) -> Real """ @@ -431,7 +431,7 @@ def VisitUnionType(self, union): This is a lossy optimization that tries to map a list of types to a common base type. For example, int and bool are both base classes of int, so it - would convert "Union[int, bool]" to "int". + would convert "int | bool" to "int". Arguments: union: A union type. @@ -689,9 +689,9 @@ class AbsorbMutableParameters(visitors.Visitor): For example, this will change def f(x: list[int]): - x = list[Union[int, float]] + x = list[int | float] to - def f(x: Union[list[int], list[Union[int, float]]) + def f(x: list[int] | list[int | float]) . (Use optimize.CombineContainers to then change x to list[Union[int, float]].) @@ -767,7 +767,7 @@ class MergeTypeParameters(TypeParameterScope): For example, this will change class A(typing.Generic(T)): - def append(self, Union[T, T2]) -> T2 + def append(self, T | T2) -> T2 to class A(typing.Generic(T)): def append(self, T) -> T @@ -778,7 +778,7 @@ def append(self, T) -> T MergeTypeParameters transforms class list(typing.Generic(T)): def append(self, v: T2) -> NoneType: - self = Union[T, T2] + self = T | T2 to class list(typing.Generic(T')): def append(self, V:T') -> NoneType @@ -887,8 +887,8 @@ def Optimize( return a new node. deps: Definitions of all of the external types in node. lossy: Allow optimizations that change the meaning of the pytd. - use_abcs: Use abstract base classes to represent unions like e.g. - "Union[float, int]" as "Real". + use_abcs: Use abstract base classes to represent unions like e.g. "float | + int" as "Real". max_union: How many types we allow in a union before we simplify it to just "object". remove_mutable: Whether to simplify mutable parameters to normal parameters. diff --git a/pytype/pytd/optimize_test.py b/pytype/pytd/optimize_test.py index 61413640f..6acd6517e 100644 --- a/pytype/pytd/optimize_test.py +++ b/pytype/pytd/optimize_test.py @@ -547,7 +547,7 @@ def test_absorb_mutable_parameters_from_methods(self): NEW = TypeVar('NEW') class MyClass(typing.Generic[T], object): def append(self, x: NEW) -> Any: - self = MyClass[Union[T, NEW]] + self = MyClass[T | NEW] """) tree = self.Parse(src) new_tree = tree.Visit(optimize.AbsorbMutableParameters()) @@ -555,7 +555,7 @@ def append(self, x: NEW) -> Any: self_type = ( new_tree.Lookup("MyClass").Lookup("append").signatures[0].params[0].type ) - self.assertEqual(pytd_utils.Print(self_type), "MyClass[Union[T, NEW]]") + self.assertEqual(pytd_utils.Print(self_type), "MyClass[T | NEW]") def test_merge_type_parameters(self): # This test uses pytd of the kind that's typically the output of diff --git a/pytype/pytd/pep484.py b/pytype/pytd/pep484.py index 2e327a105..645aacb79 100644 --- a/pytype/pytd/pep484.py +++ b/pytype/pytd/pep484.py @@ -58,6 +58,11 @@ ] +# These builtins can be stored inside pytype despite not being real, this is an +# implementation detail to be preserved and eventually fixed. +FAKE_BUILTINS = frozenset(("generator", "coroutine", "asyncgenerator")) + + # The PEP 484 definition of built-in types. # E.g. "typing.List" is used to represent the "list" type. TYPING_TO_BUILTIN = { diff --git a/pytype/pytd/pep484_test.py b/pytype/pytd/pep484_test.py index e148733c7..3a20aac56 100644 --- a/pytype/pytd/pep484_test.py +++ b/pytype/pytd/pep484_test.py @@ -16,14 +16,14 @@ def test_convert_optional(self): t = pytd.GenericType( pytd.NamedType("typing.Optional"), (pytd.NamedType("str"),) ) - self.assertEqual(self.convert(t), "Optional[str]") + self.assertEqual(self.convert(t), "str | None") def test_convert_union(self): t = pytd.GenericType( pytd.NamedType("typing.Union"), (pytd.NamedType("str"), pytd.NamedType("float")), ) - self.assertEqual(self.convert(t), "Union[str, float]") + self.assertEqual(self.convert(t), "str | float") def test_convert_list(self): t = pytd.NamedType("typing.List") diff --git a/pytype/pytd/printer.py b/pytype/pytd/printer.py index 8704cc585..7f9f37ffa 100644 --- a/pytype/pytd/printer.py +++ b/pytype/pytd/printer.py @@ -358,9 +358,8 @@ def _DropTypingConstant(self, node): "typing.OrderedDict", ): return False - if node.type == f"Type[{full_typing_name}]": + if node.type == f"type[{full_typing_name}]": self._imports.add(full_typing_name, node.name) - self._imports.decrement_typing_count("Type") self._local_names.remove(node.name) return True @@ -625,9 +624,10 @@ def VisitParameter(self, node): self._DecrementParameterImports(node.type) return node.name + suffix elif node.name == "cls" and re.fullmatch( - rf"Type\[{class_name}(\[.+\])?\]", node.type + rf"(?:Type|type)\[{class_name}(?:\[.+\])?\]", node.type ): - self._imports.decrement_typing_count("Type") + if node.type.startswith("Type"): + self._imports.decrement_typing_count("Type") self._DecrementParameterImports(node.type[5:-1]) return node.name + suffix elif node.type is None: @@ -738,7 +738,7 @@ def VisitModule(self, node): def MaybeCapitalize(self, name): """Capitalize a generic type, if necessary.""" - if name in pep484.BUILTIN_TO_TYPING: + if name in pep484.FAKE_BUILTINS: return self._FromTyping(pep484.BUILTIN_TO_TYPING[name]) else: return name @@ -758,12 +758,12 @@ def VisitGenericType(self, node): else: assert isinstance(param, (pytd.NothingType, pytd.TypeParameter)), param parameters = ("...",) + parameters[1:] - return ( - self.MaybeCapitalize(node.base_type) - + "[" - + ", ".join(str(p) for p in parameters) - + "]" - ) + if isinstance(node.base_type, pytd.UnionType): + base_type = "(" + node.base_type + ")" + else: + base_type = self.MaybeCapitalize(node.base_type) + + return base_type + "[" + ", ".join(str(p) for p in parameters) + "]" def VisitCallableType(self, node): typ = self.MaybeCapitalize(node.base_type) @@ -786,23 +786,13 @@ def VisitTupleType(self, node): def VisitUnionType(self, node): """Convert a union type ("x or y") to a string.""" - type_list = self._FormSetTypeList(node) - return self._BuildUnion(type_list) - - def VisitIntersectionType(self, node): - """Convert a intersection type ("x and y") to a string.""" - type_list = self._FormSetTypeList(node) - return self._BuildIntersection(type_list) - - def _FormSetTypeList(self, node): - """Form list of types within a set type.""" type_list = dict.fromkeys(node.type_list) if self.in_parameter: for compat, name in pep484.get_compat_items(): # name can replace compat. if compat in type_list and name in type_list: del type_list[compat] - return type_list + return self._BuildUnion(type_list) def _BuildUnion(self, type_list): """Builds a union of the types in type_list. @@ -811,48 +801,25 @@ def _BuildUnion(self, type_list): type_list: A list of strings representing types. Returns: - A string representing the union of the types in type_list. Simplifies - Union[X] to X and Union[X, None] to Optional[X]. + A string representing the union of the types in type_list. """ # Collect all literals, so we can print them using the Literal[x1, ..., xn] # syntactic sugar. literals = [] new_type_list = [] + optional = False for t in type_list: - match = re.fullmatch(r"Literal\[(?P.*)\]", t) - if match: + if t == "None": + optional = True + elif match := re.fullmatch(r"Literal\[(?P.*)\]", t): literals.append(match.group("content")) else: new_type_list.append(t) if literals: new_type_list.append(f"Literal[{', '.join(literals)}]") - if len(new_type_list) == 1: - return new_type_list[0] - elif "None" in new_type_list: - return ( - self._FromTyping("Optional") - + "[" - + self._BuildUnion(t for t in new_type_list if t != "None") - + "]" - ) - else: - return self._FromTyping("Union") + "[" + ", ".join(new_type_list) + "]" - - def _BuildIntersection(self, type_list): - """Builds a intersection of the types in type_list. - - Args: - type_list: A list of strings representing types. - - Returns: - A string representing the intersection of the types in type_list. - Simplifies Intersection[X] to X and Intersection[X, None] to Optional[X]. - """ - type_list = tuple(type_list) - if len(type_list) == 1: - return type_list[0] - else: - return " and ".join(type_list) + if optional: + new_type_list.append("None") + return " | ".join(new_type_list) def EnterLiteral(self, _): assert not self.in_literal diff --git a/pytype/pytd/pytd_utils_test.py b/pytype/pytd/pytd_utils_test.py index 6c6e8f948..7efa3d87a 100644 --- a/pytype/pytd/pytd_utils_test.py +++ b/pytype/pytd/pytd_utils_test.py @@ -230,8 +230,15 @@ def test_typing_name_conflict1(self): def List() -> None: ... """) ast = parser.parse_string(src, options=self.options) + expected = textwrap.dedent(""" + import typing + + x: list[str] + + def List() -> None: ... + """) self.assertMultiLineEqual( - pytd_utils.Print(ast).strip("\n"), src.strip("\n") + pytd_utils.Print(ast).strip("\n"), expected.strip("\n") ) def test_typing_name_conflict2(self): @@ -250,13 +257,13 @@ class MyClass: ) expected = textwrap.dedent(""" import typing - from typing import Any, List + from typing import Any - x: List[str] + x: list[str] class MyClass: List: Any - x: typing.List[str] + x: list[str] """) self.assertMultiLineEqual( pytd_utils.Print(ast).strip("\n"), expected.strip("\n") @@ -391,16 +398,16 @@ def test_literal_union(self): """).strip(), ) - def test_reuse_union_name(self): + def test_reuse_name_from_typing(self): src = """ import typing - from typing import Callable, Iterable, Tuple + from typing import Callable class Node: ... - class Union: - _predicates: Tuple[Callable[[typing.Union[Iterable[Node], Node]], bool], ...] - def __init__(self, *predicates: Callable[[typing.Union[Iterable[Node], Node]], bool]) -> None: ... + class Sequence: + _predicates: tuple[Callable[[typing.Sequence[Node] | Node], bool], ...] + def __init__(self, *predicates: Callable[[typing.Sequence[Node] | Node], bool]) -> None: ... """ ast = self.Parse(src) self.assertMultiLineEqual( diff --git a/pytype/pytd/visitors.py b/pytype/pytd/visitors.py index 72534d04d..5365d2d31 100644 --- a/pytype/pytd/visitors.py +++ b/pytype/pytd/visitors.py @@ -1206,6 +1206,7 @@ def copy(self): return pytd_utils.Print( sig.return_type ) == safe_class_name and pytd_utils.Print(sig.params[0].type) in ( + f"type[{safe_class_name}]", f"Type[{safe_class_name}]", safe_class_name, ) @@ -1633,12 +1634,12 @@ class ExpandSignatures(Visitor): """Expand to Cartesian product of parameter types. For example, this transforms - def f(x: Union[int, float], y: Union[int, float]) -> Union[str, unicode] + def f(x: int | float, y: int | float) -> str | unicode to - def f(x: int, y: int) -> Union[str, unicode] - def f(x: int, y: float) -> Union[str, unicode] - def f(x: float, y: int) -> Union[str, unicode] - def f(x: float, y: float) -> Union[str, unicode] + def f(x: int, y: int) -> str | unicode + def f(x: int, y: float) -> str | unicode + def f(x: float, y: int) -> str | unicode + def f(x: float, y: float) -> str | unicode The expansion by this class is typically *not* an optimization. But it can be the precursor for optimizations that need the expanded signatures, and it can diff --git a/pytype/pytd/visitors_test.py b/pytype/pytd/visitors_test.py index 8b850379e..02bc60b6a 100644 --- a/pytype/pytd/visitors_test.py +++ b/pytype/pytd/visitors_test.py @@ -493,9 +493,9 @@ def g(x: foo.C.C2) -> None: ... """) expected = textwrap.dedent(""" import foo - from typing import Any, List, Union + from typing import Any - def f(x: Union[int, slice]) -> List[Any]: ... + def f(x: int | slice) -> list[Any]: ... def g(x: foo.C.C2) -> None: ... """).strip() tree = self.Parse(src) @@ -708,12 +708,10 @@ class C: ... D = A.B.C """) expected = textwrap.dedent(""" - from typing import Type - class foo.A: class foo.A.B: class foo.A.B.C: ... - D: Type[foo.A.B.C] + D: type[foo.A.B.C] """).strip() self.assertMultiLineEqual( expected, @@ -736,10 +734,8 @@ class D: def f(self, x: A.B) -> A.B: ... """) expected = textwrap.dedent(""" - from typing import Type - foo.b: foo.A.B - foo.C: Type[foo.A.B] + foo.C: type[foo.A.B] class foo.A: class foo.A.B: ... @@ -789,13 +785,11 @@ def d(a: float) -> int: ... def e(a: Union[bool, None]) -> Union[bool, None]: ... """) expected = textwrap.dedent(""" - from typing import Optional, Union - def a(a: float) -> int: ... def b(a: float) -> int: ... - def c(a: object) -> Union[float, int]: ... + def c(a: object) -> float | int: ... def d(a: float) -> int: ... - def e(a: Optional[bool]) -> Optional[bool]: ... + def e(a: bool | None) -> bool | None: ... """) self.assertMultiLineEqual( expected.strip(), pytd_utils.Print(self.ToAST(src)).strip() @@ -806,7 +800,7 @@ def test_print_heterogeneous_tuple(self): pytd.NamedType("tuple"), (pytd.NamedType("str"), pytd.NamedType("float")), ) - self.assertEqual("Tuple[str, float]", pytd_utils.Print(t)) + self.assertEqual("tuple[str, float]", pytd_utils.Print(t)) def test_verify_heterogeneous_tuple(self): # Error: does not inherit from Generic @@ -948,10 +942,8 @@ def g(x: Union[str, int, None]) -> None: ... def h(x: Union[None]) -> None: ... """) expected = textwrap.dedent(""" - from typing import Optional, Union - - def f(x: Optional[str]) -> None: ... - def g(x: Optional[Union[str, int]]) -> None: ... + def f(x: str | None) -> None: ... + def g(x: str | int | None) -> None: ... def h(x: None) -> None: ... """) self.assertMultiLineEqual( @@ -1095,13 +1087,11 @@ def f(x: int, y: str, z: bool) -> list[str]: self.assertMultiLineEqual( pytd_utils.Print(self.Parse(src), multiline_args=True), textwrap.dedent(""" - from typing import List - def f( x: int, y: str, z: bool - ) -> List[str]: ... + ) -> list[str]: ... """).strip(), ) @@ -1234,12 +1224,10 @@ class C: ... D = A.B.C """) expected = textwrap.dedent(""" - from typing import Type - class A: class B: class C: ... - D: Type[A.B.C] + D: type[A.B.C] """).strip() tree = self.Parse(src) diff --git a/pytype/rewrite/output_test.py b/pytype/rewrite/output_test.py index 78ce404d3..c86e7d3e6 100644 --- a/pytype/rewrite/output_test.py +++ b/pytype/rewrite/output_test.py @@ -169,7 +169,7 @@ def test_class(self): t = self.ctx.pytd_converter.to_pytd_type( abstract.SimpleClass(self.ctx, 'C', {}) ) - self.assertPytdEqual(t, 'Type[C]') + self.assertPytdEqual(t, 'type[C]') def test_mutable_instance(self): instance = abstract.MutableInstance( @@ -206,7 +206,7 @@ def test_union(self): self.ctx, (self.ctx.consts[0], self.ctx.consts[None]) ) self.assertPytdEqual( - self.ctx.pytd_converter.to_pytd_type(union), 'Optional[int]' + self.ctx.pytd_converter.to_pytd_type(union), 'int | None' ) @@ -231,7 +231,7 @@ def test_union(self): ), ) self.assertPytdEqual( - self.ctx.pytd_converter.to_pytd_type_of_instance(union), 'Union[C, D]' + self.ctx.pytd_converter.to_pytd_type_of_instance(union), 'C | D' ) diff --git a/pytype/rewrite/tests/test_basic.py b/pytype/rewrite/tests/test_basic.py index e897084b4..0ce05756a 100644 --- a/pytype/rewrite/tests/test_basic.py +++ b/pytype/rewrite/tests/test_basic.py @@ -156,7 +156,7 @@ def test_import(self): def test_builtins(self): self.Check(""" - assert_type(__builtins__.int, "Type[int]") + assert_type(__builtins__.int, "type[int]") """) def test_dotted_import(self): diff --git a/pytype/tests/test_annotations.py b/pytype/tests/test_annotations.py index 991de59d6..7b838c4ce 100644 --- a/pytype/tests/test_annotations.py +++ b/pytype/tests/test_annotations.py @@ -253,7 +253,7 @@ def foo(x: str) -> int: return y # bad-return-type[e] """) self.assertErrorRegexes( - errors, {"e": r"Expected.*int.*Actual.*Union(?=.*complex).*str"} + errors, {"e": r"Expected.*int.*Actual.*complex \| str"} ) @test_utils.skipUnlessPy( @@ -714,7 +714,7 @@ def h(x: List[Union[int, str]]): # okay self.assertErrorRegexes( errors, { - "e1": r"List\[int\] or List\[str\].*constant", + "e1": r"list\[int\] or list\[str\].*constant", "e2": r"int or str.*constant", }, ) @@ -745,11 +745,11 @@ def h() -> Dict[float, int]: ... ) error1 = ( r"Expected.*Mapping\[str, int\].*" - r"Actually passed.*Dict\[str, float\]" + r"Actually passed.*dict\[str, float\]" ) error2 = ( r"Expected.*Mapping\[str, int\].*" - r"Actually passed.*Dict\[float, int\]" + r"Actually passed.*dict\[float, int\]" ) self.assertErrorRegexes(errors, {"e1": error1, "e2": error2}) @@ -1263,7 +1263,7 @@ def _AddMachines(self, cluster_info_config: ClusterInfoConfig): cluster_info_config[''] = {} # container-type-mismatch[e] """) self.assertErrorRegexes( - errors, {"e": r"Container: Dict\[_K, _V\].*_V: int.*_V: Dict"} + errors, {"e": r"Container: dict\[_K, _V\].*_V: int.*_V: dict"} ) def test_check_defaults(self): @@ -1375,7 +1375,7 @@ def test_container_mutation(self): x: List[int] = [] x.append("hello") # container-type-mismatch[e] """) - pattern = r"Container.*List\[_T\].*Allowed.*int.*New.*str" + pattern = r"Container.*list\[_T\].*Allowed.*int.*New.*str" self.assertErrorRegexes(errors, {"e": pattern}) def test_varargs(self): @@ -1394,7 +1394,7 @@ def quack(x, *args: int): def quack(x, *args: int) -> Tuple[int, ...]: ... """, ) - error = r"Expected.*Iterable\[int\].*Actually passed.*Tuple\[float\]" + error = r"Expected.*Iterable\[int\].*Actually passed.*tuple\[float\]" self.assertErrorRegexes(errors, {"e": error}) def test_container_multiple_mutations(self): @@ -1404,7 +1404,7 @@ def test_container_multiple_mutations(self): x["hello"] = 1.0 # container-type-mismatch[e] """) pattern = ( - r"New container.*for x.*Dict\[_K, _V\].*" + r"New container.*for x.*dict\[_K, _V\].*" + r"Allowed.*_K.*int.*_V.*str.*" r"New.*_K.*str.*_V.*float" ) @@ -1475,8 +1475,8 @@ def f() -> Union[List[MyDict], MyDict]: ... errors, { "e": ( - r"Allowed contained types.*Dict\[str, int\].*" - r"New contained types.*List\[Dict\[str, int\]\]" + r"Allowed contained types.*dict\[str, int\].*" + r"New contained types.*list\[dict\[str, int\]\]" ) }, ) diff --git a/pytype/tests/test_anystr2.py b/pytype/tests/test_anystr2.py index d28d6d260..f997d2d7c 100644 --- a/pytype/tests/test_anystr2.py +++ b/pytype/tests/test_anystr2.py @@ -64,7 +64,7 @@ def dofoo() -> Foo[str]: ... )]): self.Check(""" import foo - assert_type(foo.dofoo().name, 'Optional[str]') + assert_type(foo.dofoo().name, 'str | None') """) @@ -129,7 +129,7 @@ def f(x: AnyStr, y: AnyStr) -> AnyStr: ... v2 = ... # type: Any """, ) - self.assertErrorRegexes(errors, {"e": r"Union\[bytes, str\].*int"}) + self.assertErrorRegexes(errors, {"e": r"bytes \| str\b.*int"}) def test_constraint_mismatch(self): _, errors = self.InferWithErrors(""" diff --git a/pytype/tests/test_async_generators.py b/pytype/tests/test_async_generators.py index 8c035917b..37e63dcf1 100644 --- a/pytype/tests/test_async_generators.py +++ b/pytype/tests/test_async_generators.py @@ -150,9 +150,9 @@ def f6(x: AsyncGenerator[bool, Any]): self.assertErrorRegexes( errors, { - "e1": r"bool.*Union\[int, str\]", - "e2": r"bool.*Union\[int, str\]", - "e3": r"bool.*Union\[int, str\]", + "e1": r"bool.*int \| str", + "e2": r"bool.*int \| str", + "e3": r"bool.*int \| str", }, ) @@ -384,10 +384,10 @@ def __aiter__(self) -> Self: "e1": r"Awaitable\[str\].*Awaitable\[int\]", "e3": r"Awaitable\[str\].*Awaitable\[int\]", "e4": r"Awaitable\[str\].*Awaitable\[int\]", - "e5": r"Awaitable\[str\].*Awaitable\[Union\[bytes, int\]\]", + "e5": r"Awaitable\[str\].*Awaitable\[bytes | int\]", "e6": r"Awaitable\[str\].*Awaitable", - "e7": r"Awaitable\[str\].*Awaitable\[Union\[bytes, int\]\]", - "e8": r"Awaitable\[str\].*Awaitable\[Union\[bytes, int\]\]", + "e7": r"Awaitable\[str\].*Awaitable\[bytes | int\]", + "e8": r"Awaitable\[str\].*Awaitable\[bytes | int\]", "e9": r"AsyncIterator.*listiterator\[int\]", }, ) diff --git a/pytype/tests/test_attributes1.py b/pytype/tests/test_attributes1.py index 585362127..63c15cfa6 100644 --- a/pytype/tests/test_attributes1.py +++ b/pytype/tests/test_attributes1.py @@ -832,7 +832,7 @@ def __getitem__(self, x): for _ in v: # attribute-error[e] pass """) - self.assertErrorRegexes(errors, {"e": r"__iter__.*int.*Union\[Foo, int\]"}) + self.assertErrorRegexes(errors, {"e": r"__iter__.*int.*\bFoo \| int"}) def test_bad_contains(self): errors = self.CheckWithErrors(""" @@ -843,9 +843,7 @@ def __iter__(self): if 42 in v: # unsupported-operands[e] pass """) - self.assertErrorRegexes( - errors, {"e": r"'in'.*'.*Union\[Foo, int\]' and 'int'"} - ) + self.assertErrorRegexes(errors, {"e": r"'in'.*'.*\bFoo \| int' and 'int'"}) def test_subclass_shadowing(self): with test_utils.Tempdir() as d: diff --git a/pytype/tests/test_attributes2.py b/pytype/tests/test_attributes2.py index df8343711..58363de68 100644 --- a/pytype/tests/test_attributes2.py +++ b/pytype/tests/test_attributes2.py @@ -92,7 +92,7 @@ def f3(self) -> List[Union[int, str]]: ... """, ) self.assertErrorRegexes( - errors, {"e": r"Annotation: List\[int\].*Assignment: List\[str\]"} + errors, {"e": r"Annotation: list\[int\].*Assignment: list\[str\]"} ) def test_set_attribute_in_other_class(self): diff --git a/pytype/tests/test_builtins2.py b/pytype/tests/test_builtins2.py index 90e921a10..a69194ffa 100644 --- a/pytype/tests/test_builtins2.py +++ b/pytype/tests/test_builtins2.py @@ -448,9 +448,9 @@ def test_reversed(self): self.assertErrorRegexes( errors, { - "e1": r"Set\[int\]", - "e2": r"FrozenSet\[int\]", - "e3": r"Dict\[bool, int\]", + "e1": r"set\[int\]", + "e2": r"frozenset\[int\]", + "e3": r"dict\[bool, int\]", }, ) diff --git a/pytype/tests/test_builtins3.py b/pytype/tests/test_builtins3.py index 981c73d2b..c519421af 100644 --- a/pytype/tests/test_builtins3.py +++ b/pytype/tests/test_builtins3.py @@ -431,7 +431,7 @@ def g() -> int: ... def test_str_join_error(self): errors = self.CheckWithErrors("', '.join([1, 2, 3]) # wrong-arg-types[e]") self.assertErrorRegexes( - errors, {"e": r"Expected.*Iterable\[str\].*Actual.*List\[int\]"} + errors, {"e": r"Expected.*Iterable\[str\].*Actual.*list\[int\]"} ) def test_int_protocols(self): diff --git a/pytype/tests/test_builtins4.py b/pytype/tests/test_builtins4.py index 42affbd93..d656e583a 100644 --- a/pytype/tests/test_builtins4.py +++ b/pytype/tests/test_builtins4.py @@ -88,7 +88,7 @@ def func(a: int) -> float: map(func, ['str']) # wrong-arg-types[e] """) self.assertErrorSequences( - errors, {"e": ["Expected", "Iterable[int]", "Actual", "List[str]"]} + errors, {"e": ["Expected", "Iterable[int]", "Actual", "list[str]"]} ) def test_abspath(self): @@ -567,7 +567,7 @@ def test_int_init(self): _, errors = self.InferWithErrors(""" int(0, 1) # wrong-arg-types[e] """) - self.assertErrorRegexes(errors, {"e": r"Union\[bytes, str\].*int"}) + self.assertErrorRegexes(errors, {"e": r"bytes \| str\b.*int"}) def test_removed_builtins(self): self.CheckWithErrors(""" diff --git a/pytype/tests/test_checker.py b/pytype/tests/test_checker.py index 1d6f1ab2e..fd4f26fce 100644 --- a/pytype/tests/test_checker.py +++ b/pytype/tests/test_checker.py @@ -33,7 +33,7 @@ def f() -> List[int]: return [object()] # bad-return-type[e] f()[0] += 1 """) - self.assertErrorRegexes(errorlog, {"e": r"List\[int\].*List\[object\]"}) + self.assertErrorRegexes(errorlog, {"e": r"list\[int\].*list\[object\]"}) def test_use_varargs_and_kwargs(self): self.Check(""" @@ -120,7 +120,7 @@ def test_multiple_parameter_bindings(self): def f(x) -> List[int]: return ["", x] # bad-return-type[e] """) - self.assertErrorRegexes(errorlog, {"e": r"List\[int\].*List\[str\]"}) + self.assertErrorRegexes(errorlog, {"e": r"list\[int\].*list\[str\]"}) def test_no_param_binding(self): errorlog = self.CheckWithErrors(""" @@ -128,7 +128,7 @@ def f() -> None: x = [] return x # bad-return-type[e] """) - self.assertErrorRegexes(errorlog, {"e": r"None.*List\[nothing\]"}) + self.assertErrorRegexes(errorlog, {"e": r"None.*list\[nothing\]"}) def test_attribute_in_incomplete_instance(self): errorlog = self.CheckWithErrors(""" @@ -142,7 +142,7 @@ def __init__(self, other: "List[Foo]"): self.z = Foo.z # attribute-error[e2] """) self.assertErrorRegexes( - errorlog, {"e1": r"y.*List\[Foo\]", "e2": r"z.*Type\[Foo\]"} + errorlog, {"e1": r"y.*list\[Foo\]", "e2": r"z.*type\[Foo\]"} ) def test_bad_getitem(self): @@ -184,7 +184,7 @@ def f(x: Union[int, str]) -> int: { "e": ( r"bad option 'str' in return type.*" - r"Expected: int.*Actually returned: Union\[int, str\]" + r"Expected: int.*Actually returned: int \| str" ) }, ) diff --git a/pytype/tests/test_classes1.py b/pytype/tests/test_classes1.py index 4499dcd16..a97170833 100644 --- a/pytype/tests/test_classes1.py +++ b/pytype/tests/test_classes1.py @@ -205,11 +205,11 @@ def factory(cls, *args, **kwargs): self.assertTypesMatchPytd( ty, """ - from typing import Type, TypeVar + from typing import TypeVar _TFoo = TypeVar('_TFoo', bound=Foo) class Foo: @classmethod - def factory(cls: Type[_TFoo], *args, **kwargs) -> _TFoo: ... + def factory(cls: type[_TFoo], *args, **kwargs) -> _TFoo: ... """, ) diff --git a/pytype/tests/test_coroutine.py b/pytype/tests/test_coroutine.py index cadf8961e..d514be02d 100644 --- a/pytype/tests/test_coroutine.py +++ b/pytype/tests/test_coroutine.py @@ -361,7 +361,7 @@ async def caller(): { "e1": r"No attribute.*__aiter__", "e2": r"No attribute.*__anext__", - "e3": r"Awaitable.*Union\[int, str\]", + "e3": r"Awaitable.*int \| str", }, ) diff --git a/pytype/tests/test_dataclasses.py b/pytype/tests/test_dataclasses.py index 2b941e90f..b3df71901 100644 --- a/pytype/tests/test_dataclasses.py +++ b/pytype/tests/test_dataclasses.py @@ -214,7 +214,7 @@ def f() -> Union[int, str]: class Foo: x: List[int] = dataclasses.field(default_factory=f) # annotation-type-mismatch[e] """) - self.assertErrorRegexes(err, {"e": r"Union\[int, str\]"}) + self.assertErrorRegexes(err, {"e": r"int \| str"}) def test_field_no_init(self): ty = self.Infer(""" diff --git a/pytype/tests/test_enums.py b/pytype/tests/test_enums.py index 1b132fd90..c7e1d18c9 100644 --- a/pytype/tests/test_enums.py +++ b/pytype/tests/test_enums.py @@ -255,7 +255,7 @@ class M(enum.Enum): B = "b" assert_type(M["A"].value, "int") assert_type(M["B"].value, "str") - assert_type(M[e.a_string].value, "Union[int, str]") + assert_type(M[e.a_string].value, "int | str") _ = M["C"] # attribute-error """, pythonpath=[d.path], @@ -343,7 +343,6 @@ class M(enum.Enum): def test_value_lookup(self): self.CheckWithErrors(""" import enum - from typing import Union class M(enum.Enum): A = 1 assert_type(M(1), "M") @@ -356,7 +355,7 @@ class N(enum.Enum): B = "str" assert_type(N(1), "N") assert_type(N("str"), "N") - assert_type(N(499).value, "Union[int, str]") + assert_type(N(499).value, "int | str") N(M.A) # wrong-arg-types """) @@ -520,7 +519,7 @@ class N(enum.Enum): 1 in M # unsupported-operands # __iter__ - assert_type([e for e in M], "List[M]") + assert_type([e for e in M], "list[M]") # __len__ assert_type(len(M), "int") @@ -552,7 +551,7 @@ class N(enum.Enum): 1 in M # unsupported-operands # __iter__ - assert_type([e for e in M], "List[m.M]") + assert_type([e for e in M], "list[m.M]") # __len__ assert_type(len(M), "int") diff --git a/pytype/tests/test_errors1.py b/pytype/tests/test_errors1.py index baea455cc..fb6168fe8 100644 --- a/pytype/tests/test_errors1.py +++ b/pytype/tests/test_errors1.py @@ -308,12 +308,12 @@ def h(): e2_msg = "No attribute 'bar' on None" e3_msg = "No attribute 'bar' on int" else: - e2_msg = "No attribute 'bar' on int\nIn Optional[int]" - e3_msg = "No attribute 'bar' on None\nIn Optional[int]" + e2_msg = "No attribute 'bar' on int\nIn int | None" + e3_msg = "No attribute 'bar' on None\nIn int | None" self.assertErrorSequences( errors, { - "e1": ["No attribute 'foo' on Type[Foo]"], + "e1": ["No attribute 'foo' on type[Foo]"], "e2": [e2_msg], "e3": [e3_msg], "e4": ["No attribute 'baz' on module 'modfoo'"], @@ -353,7 +353,7 @@ def f(x: list[int]) -> int: ... """, pythonpath=[d.path], ) - self.assertErrorSequences(errors, {"e": ["List[int]", "List[str]"]}) + self.assertErrorSequences(errors, {"e": ["list[int]", "list[str]"]}) def test_too_many_args(self): errors = self.CheckWithErrors(""" @@ -596,14 +596,14 @@ def f(x: Union[int, str]) -> None: ... """, pythonpath=[d.path], ) - pattern = ["Expected", "Union[int, str]", "Actually passed"] + pattern = ["Expected", "int | str", "Actually passed"] self.assertErrorSequences(errors, {"e": pattern}) def test_print_type_arg(self): errors = self.CheckWithErrors(""" hex(int) # wrong-arg-types[e] """) - self.assertErrorRegexes(errors, {"e": r"Actually passed.*Type\[int\]"}) + self.assertErrorRegexes(errors, {"e": r"Actually passed.*type\[int\]"}) def test_delete_from_set(self): errors = self.CheckWithErrors(""" @@ -692,7 +692,7 @@ def test_invalid_parameters_details(self): self.assertErrorSequences( errors, { - "e1": ["Actually passed:", "self, x: List[nothing]"], + "e1": ["Actually passed:", "self, x: list[nothing]"], "e2": ["_, foobar"], "e3": ["Actually passed:", "self, x, foobar"], "e4": ["Actually passed:", "self, x, x"], @@ -721,7 +721,7 @@ class B(A): def __init__(self): super(B, A).__init__() # A cannot be the second argument to super # wrong-arg-types[e] """) - self.assertErrorSequences(errors, {"e": ["Type[B]", "Type[A]"]}) + self.assertErrorSequences(errors, {"e": ["type[B]", "type[A]"]}) def test_bad_name_import(self): with test_utils.Tempdir() as d: @@ -780,7 +780,7 @@ def f(x: Type[A]) -> bool: ... """, pythonpath=[d.path], ) - error = ["Expected", "Type[a.A]", "Actual", "Type[a.C]"] + error = ["Expected", "type[a.A]", "Actual", "type[a.C]"] self.assertErrorSequences(errors, {"e": error}) self.assertTypesMatchPytd( ty, @@ -812,7 +812,7 @@ def f(x: Type[A[int]]): ... """, pythonpath=[d.path], ) - expected_error = ["Expected", "Type[a.A[int]]", "Actual", "Type[a.B]"] + expected_error = ["Expected", "type[a.A[int]]", "Actual", "type[a.B]"] self.assertErrorSequences(errors, {"e": expected_error}) def test_mro_error(self): @@ -953,21 +953,21 @@ def test_bad_type_bases(self): errors = self.CheckWithErrors(""" X = type("X", (42,), {"a": 1}) # wrong-arg-types[e] """) - self.assertErrorSequences(errors, {"e": ["Actual", "Tuple[int]"]}) + self.assertErrorSequences(errors, {"e": ["Actual", "tuple[int]"]}) def test_half_bad_type_bases(self): errors = self.CheckWithErrors(""" X = type("X", (42, object), {"a": 1}) # wrong-arg-types[e] """) self.assertErrorSequences( - errors, {"e": ["Actual", "Tuple[int, Type[object]]"]} + errors, {"e": ["Actual", "tuple[int, type[object]]"]} ) def test_bad_type_members(self): errors = self.CheckWithErrors(""" X = type("X", (int, object), {0: 1}) # wrong-arg-types[e] """) - self.assertErrorSequences(errors, {"e": ["Actual", "Dict[int, int]"]}) + self.assertErrorSequences(errors, {"e": ["Actual", "dict[int, int]"]}) def test_recursion(self): with test_utils.Tempdir() as d: @@ -1027,7 +1027,7 @@ def test_bad_dict_attribute(self): x = {"a": 1} y = x.a # attribute-error[e] """) - self.assertErrorSequences(errors, {"e": ["a", "Dict[str, int]"]}) + self.assertErrorSequences(errors, {"e": ["a", "dict[str, int]"]}) def test_bad_pyi_dict(self): with test_utils.Tempdir() as d: @@ -1090,7 +1090,7 @@ def f(x): f("hello") f([]) """) - self.assertErrorRegexes(errors, {"e1": r"str.*int", "e2": r"List.*int"}) + self.assertErrorRegexes(errors, {"e1": r"str.*int", "e2": r"list.*int"}) def test_kwarg_order(self): with test_utils.Tempdir() as d: @@ -1128,7 +1128,7 @@ def test_bad_ambiguous_base_class(self): errors = self.CheckWithErrors(""" class Bar(None if __random__ else 42): pass # base-class-error[e] """) - self.assertErrorSequences(errors, {"e": ["Optional[]"]}) + self.assertErrorSequences(errors, {"e": [" | None"]}) @test_utils.skipUnlessPy( (3, 10), (3, 12), reason="3.10/3.12: log one error per bad option" @@ -1196,7 +1196,7 @@ def test_not_protocol(self): a = "".join(a) # wrong-arg-types[e] """) self.assertErrorRegexes( - errors, {"e": r"\(.*List\[int\]\)$"} + errors, {"e": r"\(.*list\[int\]\)$"} ) # no protocol details def test_protocol_signatures(self): @@ -1237,7 +1237,7 @@ def f(x): y = x if __random__ else None return y.groups() # attribute-error[e] """) - self.assertErrorRegexes(errors, {"e": r"Optional\[Any\]"}) + self.assertErrorRegexes(errors, {"e": r"Any \| None"}) class OperationsTest(test_base.BaseTest): @@ -1297,7 +1297,7 @@ class Foo: reveal_type([1,2,3]) # reveal-type[e3] """) self.assertErrorSequences( - errors, {"e1": ["Type[Foo]"], "e2": ["Foo"], "e3": ["List[int]"]} + errors, {"e1": ["type[Foo]"], "e2": ["Foo"], "e3": ["list[int]"]} ) def test_reveal_type_expression(self): @@ -1306,7 +1306,7 @@ def test_reveal_type_expression(self): y = "foo" reveal_type(x or y) # reveal-type[e] """) - self.assertErrorSequences(errors, {"e": ["Union[int, str]"]}) + self.assertErrorSequences(errors, {"e": ["int | str"]}) def test_combine_containers(self): errors = self.CheckWithErrors(""" @@ -1315,7 +1315,7 @@ def test_combine_containers(self): y: Set[Union[str, bytes]] reveal_type(x | y) # reveal-type[e] """) - self.assertErrorSequences(errors, {"e": ["Set[Union[bytes, int, str]]"]}) + self.assertErrorSequences(errors, {"e": ["set[bytes | int | str]"]}) class InPlaceOperationsTest(test_base.BaseTest): @@ -1326,7 +1326,7 @@ def test_iadd(self): def f(): v = []; v += 3 # unsupported-operands[e] """) self.assertErrorSequences( - errors, {"e": ["+=", "List", "int", "__iadd__ on List", "Iterable"]} + errors, {"e": ["+=", "list", "int", "__iadd__ on list", "Iterable"]} ) @@ -1339,14 +1339,14 @@ def f(): v = []; return v['foo'] # unsupported-operands[e] """) self.assertErrorRegexes( errors, - {"e": r"item retrieval.*List.*str.*__getitem__ on List.*SupportsIndex"}, + {"e": r"item retrieval.*list.*str.*__getitem__ on list.*SupportsIndex"}, ) def test_delitem(self): errors = self.CheckWithErrors(""" def f(): v = {'foo': 3}; del v[3] # unsupported-operands[e] """) - d = "Dict[str, int]" + d = "dict[str, int]" self.assertErrorSequences( errors, {"e": ["item deletion", d, "int", f"__delitem__ on {d}", "str"]} ) @@ -1359,8 +1359,8 @@ def f(): v = []; v['foo'] = 3 # unsupported-operands[e] errors, { "e": ( - r"item assignment.*List.*str.*__setitem__ on" - r" List.*SupportsIndex" + r"item assignment.*list.*str.*__setitem__ on" + r" list.*SupportsIndex" ) }, ) diff --git a/pytype/tests/test_errors2.py b/pytype/tests/test_errors2.py index 8af644421..a8e9d322d 100644 --- a/pytype/tests/test_errors2.py +++ b/pytype/tests/test_errors2.py @@ -18,9 +18,7 @@ def f(x: int): x = (3.14, "") f(x[i]) # wrong-arg-types[e] """) - self.assertErrorRegexes( - errors, {"e": r"Actually passed:.*Union\[float, str\]"} - ) + self.assertErrorRegexes(errors, {"e": r"Actually passed:.*float \| str"}) def test_invalid_annotations(self): _, errors = self.InferWithErrors(""" @@ -64,7 +62,7 @@ def f(x: str): x = [float] f(x) # wrong-arg-types[e] """) - error = ["Actual", "Union[List[Type[float]], Type[dict]]"] + error = ["Actual", "list[type[float]] | type[dict]"] self.assertErrorSequences(errors, {"e": error}) def test_wrong_brackets(self): @@ -101,9 +99,9 @@ def g2(x: dct): # invalid-annotation[e4] errors, { "e1": ["(int, str)", "Not a type"], - "e2": ["instance of Tuple[int, ...]", "Not a type"], + "e2": ["instance of tuple[int, ...]", "Not a type"], "e3": ["{'a': 1}", "Not a type"], - "e4": ["instance of Dict[str, int]", "Not a type"], + "e4": ["instance of dict[str, int]", "Not a type"], }, ) @@ -162,7 +160,7 @@ def bar(x: str): "e2": ["x: Y"], "e3": ["x: W"], "e4": ["Iterator"], - "e5": ["Union[X, int]"], + "e5": ["X | int"], }, ) @@ -281,7 +279,7 @@ def test_union_with_any(self): Y = X[str] # invalid-annotation[e] """) self.assertErrorSequences( - errors, {"e": ["Union[Any, int][str]", "Union[Any, int]", "0", "1"]} + errors, {"e": ["(Any | int)[str]", "Any | int", "0", "1"]} ) def test_optional_union(self): @@ -290,7 +288,7 @@ def test_optional_union(self): X = Union[int, str, None] Y = X[float] # invalid-annotation[e] """) - self.assertErrorSequences(errors, {"e": "Optional[Union[int, str]"}) + self.assertErrorSequences(errors, {"e": "int | str | None"}) def test_nested_class(self): errors = self.CheckWithErrors(""" @@ -326,12 +324,12 @@ class A: errors, { "e1": [ - "{'a': 1, 'b': 'hello'}: Dict[str, Union[int, str]]", - "[1, 2]: List[int]", + "{'a': 1, 'b': 'hello'}: dict[str, int | str]", + "[1, 2]: list[int]", ], "e2": [ - "{...: ...}: Dict[Union[int, str], Union[A, int]", - "[..., 2]: List[Union[A, int]]", + "{...: ...}: dict[int | str, A | int", + "[..., 2]: list[A | int]", ], }, ) @@ -414,7 +412,7 @@ def f(x: int, y: str, z): assert_type(y, 'int') # assert-type[e] if __random__: x = A() - assert_type(x, 'Union[A, int]') + assert_type(x, 'A | int') """) self.assertErrorSequences( errors, @@ -457,7 +455,7 @@ def test_combine_containers(self): from typing import Set, Union x: Set[Union[int, str]] y: Set[Union[str, bytes]] - assert_type(x | y, "Set[Union[bytes, int, str]]") + assert_type(x | y, "set[bytes | int | str]") """) diff --git a/pytype/tests/test_exceptions2.py b/pytype/tests/test_exceptions2.py index 2d2179507..8dc53140a 100644 --- a/pytype/tests/test_exceptions2.py +++ b/pytype/tests/test_exceptions2.py @@ -104,7 +104,7 @@ def __exit__(self, exc_type, exc_value, tb): with Foo(): print(0) """) - self.assertErrorSequences(errors, {"e": ["Optional[Type[BaseException]]"]}) + self.assertErrorSequences(errors, {"e": ["type[BaseException] | None"]}) def test_yield_from(self): self.Check(""" diff --git a/pytype/tests/test_final.py b/pytype/tests/test_final.py index 93c171c79..750f31b1b 100644 --- a/pytype/tests/test_final.py +++ b/pytype/tests/test_final.py @@ -551,7 +551,7 @@ def test_attribute_access(self): b = k.random() # attribute-error[e] """) self.assertErrorSequences( - err, {"e": ["No attribute", "random", "Final[List[str]]"]} + err, {"e": ["No attribute", "random", "Final[list[str]]"]} ) diff --git a/pytype/tests/test_generic2.py b/pytype/tests/test_generic2.py index 5b0b843fc..5d1f3ec99 100644 --- a/pytype/tests/test_generic2.py +++ b/pytype/tests/test_generic2.py @@ -90,7 +90,7 @@ def fun(self, x: T, y: S): self.assertErrorRegexes( errors, { - "e1": r"Union\[float, int\].*str", + "e1": r"float \| int\b.*str", "e2": r"x: int.*x: str", "e3": r"y: int.*y: str", }, diff --git a/pytype/tests/test_import1.py b/pytype/tests/test_import1.py index 236b907f8..b1fc1faeb 100644 --- a/pytype/tests/test_import1.py +++ b/pytype/tests/test_import1.py @@ -1659,10 +1659,10 @@ def __new__(cls): ty, """ from foo import bar - from typing import Type, TypeVar + from typing import TypeVar _Tfoo = TypeVar("_Tfoo", bound=foo) class foo: - def __new__(cls: Type[_Tfoo]) -> _Tfoo: ... + def __new__(cls: type[_Tfoo]) -> _Tfoo: ... """, ) diff --git a/pytype/tests/test_list1.py b/pytype/tests/test_list1.py index 813e264b8..faba16dbe 100644 --- a/pytype/tests/test_list1.py +++ b/pytype/tests/test_list1.py @@ -94,7 +94,7 @@ def test_getitem_slot(self): g = ... # type: List[Union[int, str]] """, ) - self.assertErrorRegexes(errors, {"e": r"__getitem__ on List"}) + self.assertErrorRegexes(errors, {"e": r"__getitem__ on list"}) def test_index_out_of_range(self): ty = self.Infer(""" diff --git a/pytype/tests/test_match2.py b/pytype/tests/test_match2.py index adb239d11..ce7a82db0 100644 --- a/pytype/tests/test_match2.py +++ b/pytype/tests/test_match2.py @@ -62,7 +62,7 @@ def f2(x: Callable[[T_constrained], T_constrained]): ... """, pythonpath=[d.path], ) - expected = r"Callable\[\[Union\[bool, int\]\], Union\[bool, int\]\]" + expected = r"Callable\[\[bool \| int\], bool \| int\]" self.assertErrorRegexes( errors, { diff --git a/pytype/tests/test_methods1.py b/pytype/tests/test_methods1.py index c5d82e17c..3b05fed32 100644 --- a/pytype/tests/test_methods1.py +++ b/pytype/tests/test_methods1.py @@ -576,7 +576,7 @@ def test_empty_starstar_kwargs_type(self): self.Check(""" def f(nr, **kwargs): return kwargs - assert_type(f(3), "Dict[nothing, nothing]") + assert_type(f(3), "dict[nothing, nothing]") """) def test_starstar_deep(self): diff --git a/pytype/tests/test_protocols2.py b/pytype/tests/test_protocols2.py index d88021d62..4e3d9367c 100644 --- a/pytype/tests/test_protocols2.py +++ b/pytype/tests/test_protocols2.py @@ -38,7 +38,7 @@ def f(x: protocols.SupportsAbs): f(["foo"]) # wrong-arg-types[e] """) self.assertErrorRegexes( - errors, {"e": r"\(x: SupportsAbs\).*\(x: List\[str\]\)"} + errors, {"e": r"\(x: SupportsAbs\).*\(x: list\[str\]\)"} ) def test_check_iterator_error(self): @@ -342,7 +342,7 @@ def f(x: Hashable): pass f([]) # wrong-arg-types[e] """) - self.assertErrorRegexes(errors, {"e": r"Hashable.*List.*__hash__"}) + self.assertErrorRegexes(errors, {"e": r"Hashable.*list.*__hash__"}) def test_hash_constant(self): errors = self.CheckWithErrors(""" @@ -1214,7 +1214,7 @@ def f(x: Foo): f(Bar()) f(Baz()) # wrong-arg-types[e] """) - self.assertErrorRegexes(errors, {"e": r"expected Optional\[int\], got str"}) + self.assertErrorRegexes(errors, {"e": r"expected int \| None, got str"}) def test_match_optional_to_optional(self): self.Check(""" @@ -1320,8 +1320,8 @@ class Baz: errors, { "e": ( - r"expected Dict\[str, List\[int\]\], " - r"got Dict\[str, List\[str\]\]" + r"expected dict\[str, list\[int\]\], " + r"got dict\[str, list\[str\]\]" ) }, ) @@ -1350,8 +1350,8 @@ class ShouldNotMatch: errors, { "e": ( - r"expected Dict\[str, dataclasses\.Field\[int\]\], " - r"got Dict\[str, dataclasses\.Field\[Union\[int, str\]\]\]" + r"expected dict\[str, dataclasses\.Field\[int\]\], " + r"got dict\[str, dataclasses\.Field\[int \| str\]\]" ) }, ) diff --git a/pytype/tests/test_pyi2.py b/pytype/tests/test_pyi2.py index bec26822c..f0dc99d55 100644 --- a/pytype/tests/test_pyi2.py +++ b/pytype/tests/test_pyi2.py @@ -123,9 +123,9 @@ class Z(Generic[T]): ... self.Check( """ import foo - assert_type(foo.X1, "Type[List[int]]") - assert_type(foo.X2, "Type[List[foo.Z[str]]]") - assert_type(foo.X3, "Type[Union[foo.Z[int], int]]") + assert_type(foo.X1, "type[list[int]]") + assert_type(foo.X2, "type[list[foo.Z[str]]]") + assert_type(foo.X3, "type[foo.Z[int] | int]") """, pythonpath=[d.path], ) @@ -212,7 +212,7 @@ def test_imported_literal_alias(self): ]): self.Check(""" import bar - assert_type(bar.Y, "Type[Literal['a', 'b', 'c', 'd']]") + assert_type(bar.Y, "type[Literal['a', 'b', 'c', 'd']]") """) def test_literal_in_dataclass(self): diff --git a/pytype/tests/test_recursive_types.py b/pytype/tests/test_recursive_types.py index ac06704ed..7597a7022 100644 --- a/pytype/tests/test_recursive_types.py +++ b/pytype/tests/test_recursive_types.py @@ -83,7 +83,7 @@ def test_type(self): bad2: X = [[0]] # annotation-type-mismatch """) self.assertErrorSequences( - errors, {"e": ["Annotation", "List[X]", "Assignment", "List[int]"]} + errors, {"e": ["Annotation", "list[X]", "Assignment", "list[int]"]} ) def test_value(self): @@ -96,7 +96,7 @@ def test_value(self): bad: List[int] = x # annotation-type-mismatch[e] """) self.assertErrorSequences( - errors, {"e": ["Annotation", "List[int]", "Assignment", "List[X]"]} + errors, {"e": ["Annotation", "list[int]", "Assignment", "list[X]"]} ) def test_value_and_type(self): @@ -111,7 +111,7 @@ def test_value_and_type(self): bad: Bad = x # annotation-type-mismatch[e] """) self.assertErrorSequences( - errors, {"e": ["Annotation", "Set[Bad]", "Assignment", "List[X1]"]} + errors, {"e": ["Annotation", "set[Bad]", "Assignment", "list[X1]"]} ) def test_union_as_type(self): @@ -128,7 +128,7 @@ def test_union_as_type(self): self.assertErrorSequences( errors, { - "e": ["Annotation", "Union[List[X], str]", "Assignment", "int"], + "e": ["Annotation", "list[X] | str", "Assignment", "int"], }, ) @@ -146,9 +146,9 @@ def test_union_as_value(self): { "e": [ "Annotation", - "Union[int, list]", + "int | list", "Assignment", - "Union[List[X], str]", + "list[X] | str", ] }, ) @@ -175,11 +175,11 @@ def test_union_as_value_and_type(self): { "e": [ "Annotation", - "Union[Set[Bad1], str]", + "set[Bad1] | str", "Assignment", - "List[X1]", + "list[X1]", "In assignment", - "Union[List[X1], str]", + "list[X1] | str", ], }, ) @@ -490,9 +490,8 @@ def test_parameterization(self): errors, { "e": ( - r"Annotation: Union\[List\[foo.X(\[T\])?\[int\]\]," - r" int\].*" - r"Assignment: List\[str\]" + r"Annotation: int \|" + r" list\[foo.X(\[T\])?\[int\]\].*Assignment: list\[str\]" ) }, ) @@ -517,7 +516,7 @@ def test_parameterize_and_forward(self): ]): self.Check(""" import bar - assert_type(bar.Y, "Type[Union[List[bar.foo.X[T][str]], str]]") + assert_type(bar.Y, "type[list[bar.foo.X[T][str]] | str]") """) def test_dataclass(self): diff --git a/pytype/tests/test_stdlib2.py b/pytype/tests/test_stdlib2.py index 3b5aa2a37..00e8a377b 100644 --- a/pytype/tests/test_stdlib2.py +++ b/pytype/tests/test_stdlib2.py @@ -46,7 +46,7 @@ def test_collections_container(self): self._testCollectionsObject("Container", "[]", "42", r"Container.*int") def test_collections_hashable(self): - self._testCollectionsObject("Hashable", "42", "[]", r"Hashable.*List") + self._testCollectionsObject("Hashable", "42", "[]", r"Hashable.*list") def test_collections_iterable(self): self._testCollectionsObject("Iterable", "[]", "42", r"Iterable.*int") @@ -152,7 +152,7 @@ def test_collections_bytestring(self): "ByteString", "b'hello'", "42", - r"Union\[bytearray, bytes, memoryview\].*int", + r"bytearray \| bytes \| memoryview\b.*int", ) def test_collections_collection(self): diff --git a/pytype/tests/test_super1.py b/pytype/tests/test_super1.py index 8a5dad186..485c2ec64 100644 --- a/pytype/tests/test_super1.py +++ b/pytype/tests/test_super1.py @@ -229,7 +229,7 @@ def test_method_on_single_argument_super(self): ) self.assertErrorRegexes( errors, - {"e1": r"'foo' on super", "e2": r"Type\[super\].*Type\[object\]"}, + {"e1": r"'foo' on super", "e2": r"type\[super\].*type\[object\]"}, ) def test_super_under_decorator(self): diff --git a/pytype/tests/test_tuple2.py b/pytype/tests/test_tuple2.py index eb50fd4ce..d9d92860c 100644 --- a/pytype/tests/test_tuple2.py +++ b/pytype/tests/test_tuple2.py @@ -71,11 +71,11 @@ def g(y: Tuple[str]): g(("",)) # okay g(tuple([""])) # okay """) - x = r"Tuple\[str, \.\.\.\]" - y = r"Tuple\[str\]" - tuple_int = r"Tuple\[int\]" - tuple_ints = r"Tuple\[int, \.\.\.\]" - tuple_str_str = r"Tuple\[str, str\]" + x = r"tuple\[str, \.\.\.\]" + y = r"tuple\[str\]" + tuple_int = r"tuple\[int\]" + tuple_ints = r"tuple\[int, \.\.\.\]" + tuple_str_str = r"tuple\[str, str\]" self.assertErrorRegexes( errors, { @@ -133,12 +133,12 @@ def g(x: Tuple[int, str]): """, pythonpath=[d.path], ) - expected = r"Tuple\[int, str\]" - actual = r"Tuple\[str, int\]" + expected = r"tuple\[int, str\]" + actual = r"tuple\[str, int\]" self.assertErrorRegexes( errors, { - "e1": rf"Type\[{expected}\].*Type\[{actual}\]", + "e1": rf"type\[{expected}\].*type\[{actual}\]", "e2": rf"{expected}.*{actual}", "e3": r"%s.*foo\.A" % expected, }, diff --git a/pytype/tests/test_type_comments1.py b/pytype/tests/test_type_comments1.py index 27c2a3648..a64ff5753 100644 --- a/pytype/tests/test_type_comments1.py +++ b/pytype/tests/test_type_comments1.py @@ -732,7 +732,7 @@ def g(xs: List[str]) -> List[str]: ... """, ) self.assertErrorRegexes( - errors, {"e": r"Annotation: List\[str\].*Assignment: List\[None\]"} + errors, {"e": r"Annotation: list\[str\].*Assignment: list\[None\]"} ) def test_multiple_assignments(self): diff --git a/pytype/tests/test_type_comments2.py b/pytype/tests/test_type_comments2.py index d7769e09e..e5bcd3fc6 100644 --- a/pytype/tests/test_type_comments2.py +++ b/pytype/tests/test_type_comments2.py @@ -31,7 +31,7 @@ def g(xs: List[str]) -> List[str]: ... """, ) self.assertErrorRegexes( - errors, {"e": r"Annotation: List\[str\].*Assignment: List\[None\]"} + errors, {"e": r"Annotation: list\[str\].*Assignment: list\[None\]"} ) diff --git a/pytype/tests/test_typed_dict.py b/pytype/tests/test_typed_dict.py index 0ab546d3e..220acfc0b 100644 --- a/pytype/tests/test_typed_dict.py +++ b/pytype/tests/test_typed_dict.py @@ -90,8 +90,8 @@ class A(TypedDict): "Type annotation", "key y", "TypedDict A", - "Annotation: Union[int, str]", - "Assignment: List[nothing]", + "Annotation: int | str", + "Assignment: list[nothing]", ] }, ) diff --git a/pytype/tests/test_typevar2.py b/pytype/tests/test_typevar2.py index 473854e96..4126e0f24 100644 --- a/pytype/tests/test_typevar2.py +++ b/pytype/tests/test_typevar2.py @@ -174,7 +174,7 @@ def f4(x: S, y: T, z: T) -> List[S]: "e1": r"list.*set", "e2": r"str.*int", "e3": r"bool.*int", - "e4": r"List\[bool\].*List\[Union\[float, int\]\]", + "e4": r"list\[bool\].*list\[float \| int\]", }, ) @@ -199,7 +199,7 @@ def f(x: T) -> T: ... u = ... # type: Union[int, float] """, ) - self.assertErrorRegexes(errors, {"e": r"Union\[float, int\].*str"}) + self.assertErrorRegexes(errors, {"e": r"float \| int.*str"}) def test_type_parameter_type(self): ty = self.Infer(""" @@ -230,7 +230,7 @@ def g(x: Type[Sequence[T]]) -> T: return x()[0] """) self.assertErrorRegexes( - errors, {"e": r"Expected.*int.*Actual.*Type\[Sequence\]"} + errors, {"e": r"Expected.*int.*Actual.*type\[Sequence\]"} ) def test_print_nested_type_parameter(self): @@ -240,9 +240,7 @@ def test_print_nested_type_parameter(self): def f(x: List[T]): ... f([""]) # wrong-arg-types[e] """) - self.assertErrorRegexes( - errors, {"e": r"List\[Union\[float, int\]\].*List\[str\]"} - ) + self.assertErrorRegexes(errors, {"e": r"list\[float \| int\].*list\[str\]"}) def test_constraint_subtyping(self): _, errors = self.InferWithErrors(""" @@ -388,7 +386,7 @@ def test_optional_typevar(self): def f() -> Optional[T]: return 42 if __random__ else None # bad-return-type[e] """) - self.assertErrorRegexes(errors, {"e": r"Optional\[str\].*int"}) + self.assertErrorRegexes(errors, {"e": r"str \| None.*int"}) def test_unicode_literals(self): ty = self.Infer(""" @@ -506,7 +504,7 @@ def test_typevar_in_union_alias_error(self): Foo = Union[T, List[T], Dict[T, List[U]], complex] def f(x: Foo[int]): ... # invalid-annotation[e] """) - self.assertErrorRegexes(err, {"e": "Union.*2.*got.*1"}) + self.assertErrorRegexes(err, {"e": " | .*2.*got.*1"}) def test_cast_generic_tuple(self): self.Check(""" @@ -1125,8 +1123,8 @@ def g(x: AnyStr) -> AnyStr: ... self.assertErrorRegexes( errors, { - "e1": r"Union\[float, int\].*str", - "e2": r"Union\[bytes, str\].*int", + "e1": r"float \| int\b.*str", + "e2": r"bytes \| str\b.*int", }, ) diff --git a/pytype/tests/test_typing1.py b/pytype/tests/test_typing1.py index 9e42b3e5f..130f96d5a 100644 --- a/pytype/tests/test_typing1.py +++ b/pytype/tests/test_typing1.py @@ -176,16 +176,16 @@ def test_new_type_arg_error(self): self.assertErrorRegexes( errors, { - "e1": r".*Expected:.*str.*\nActually passed:.*Type\[int\].*", + "e1": r".*Expected:.*str.*\nActually passed:.*type\[int\].*", "e2": r".*Expected:.*type.*\nActually passed:.*str.*", - "e3": r".*Expected:.*str.*\nActually passed:.*Union.*", + "e3": r".*Expected:.*str.*\nActually passed:.* \| .*", "e4": ( # 3.12+ unrolls the ternary into 2 separate branches with 2 # separate CALL instructions. This means both branches are # individually type checked. r".*Expected:.*type.*\nActually passed:.*str.*" if self.python_version >= (3, 12) - else r".*Expected:.*type.*\nActually passed:.*Union.*" + else r".*Expected:.*type.*\nActually passed:.* \| .*" ), }, ) diff --git a/pytype/tests/test_typing2.py b/pytype/tests/test_typing2.py index 8c0ca917c..01f1e1664 100644 --- a/pytype/tests/test_typing2.py +++ b/pytype/tests/test_typing2.py @@ -189,7 +189,7 @@ def g9(x: Callable[[], Any]) -> None: ... "e3": r"'Any'.*must be a list of argument types or ellipsis", "e4": r"bool or str.*Must be constant", "e5": r"int or str.*Must be constant", - "e6": r"instance of List\[int\].*Must be constant", + "e6": r"instance of list\[int\].*Must be constant", "e7": r"instance of int", "e8": r"Callable.*expected 2.*got 3", "e9": r"'Any'.*must be a list of argument types or ellipsis", @@ -225,12 +225,10 @@ def g2(x: Callable[..., bool]) -> None: ... errors, { "e1": ( - r"instance of List\[Type\[Union\[int, str\]\]\].*" - r"Must be constant" + r"instance of list\[type\[int \| str\]\].*" r"Must be constant" ), "e2": ( - r"instance of List\[Type\[Union\[int, str\]\]\].*Must be" - r" constant" + r"instance of list\[type\[int \| str\]\].*Must be" r" constant" ), }, ) @@ -636,11 +634,11 @@ def func4(): self.assertErrorSequences( errors, { - "e1": ["Expected: List[nothing]", "Actually returned: List[None]"], + "e1": ["Expected: list[nothing]", "Actually returned: list[None]"], "e2": ["Expected: (x: Never)", "Actually passed: (x: int)"], "e3": [ - "Expected: (x: List[nothing])", - "Actually passed: (x: List[int])", + "Expected: (x: list[nothing])", + "Actually passed: (x: list[int])", ], "e4": ["Allowed", "_T: Never", "New", "_T: int"], }, @@ -1271,7 +1269,7 @@ def test_pyi(self): self.Check( """ import foo - assert_type(foo.X, "Type[int]") + assert_type(foo.X, "type[int]") """, pythonpath=[d.path], ) diff --git a/pytype/tests/test_typing_namedtuple2.py b/pytype/tests/test_typing_namedtuple2.py index 1193f9a5e..fb546d2b2 100644 --- a/pytype/tests/test_typing_namedtuple2.py +++ b/pytype/tests/test_typing_namedtuple2.py @@ -270,7 +270,7 @@ def foo(x: X): """) self.assertMultiLineEqual( pytd_utils.Print(ty.Lookup("foo")), - "def foo(x: X) -> Union[bytes, str]: ...", + "def foo(x: X) -> bytes | str: ...", ) def test_bad_call(self): diff --git a/pytype/tests/test_typing_self.py b/pytype/tests/test_typing_self.py index 63f121061..58e809c29 100644 --- a/pytype/tests/test_typing_self.py +++ b/pytype/tests/test_typing_self.py @@ -31,8 +31,8 @@ def f(self) -> List[Self]: return [self] class B(A): pass - assert_type(A().f(), "List[A]") - assert_type(B().f(), "List[B]") + assert_type(A().f(), "list[A]") + assert_type(B().f(), "list[B]") """) def test_parameter(self): @@ -374,8 +374,8 @@ def f(self) -> list[Self]: ... import foo class B(foo.A): pass - assert_type(foo.A().f(), "List[foo.A]") - assert_type(B().f(), "List[B]") + assert_type(foo.A().f(), "list[foo.A]") + assert_type(B().f(), "list[B]") """) def test_parameter(self): @@ -617,8 +617,8 @@ def f(self) -> List[Self]: import foo class B(foo.A): pass - assert_type(foo.A().f(), "List[foo.A]") - assert_type(B().f(), "List[B]") + assert_type(foo.A().f(), "list[foo.A]") + assert_type(B().f(), "list[B]") """) def test_parameter(self): diff --git a/pytype/tests/test_unions.py b/pytype/tests/test_unions.py index 3864ba1db..ce00d0676 100644 --- a/pytype/tests/test_unions.py +++ b/pytype/tests/test_unions.py @@ -214,10 +214,10 @@ def f3() -> Union[int, str]: self.assertErrorRegexes( errors, { - "e1b": r"str.*bytes.*Union\[bytes, int\]", - "e1i": r"str.*int.*Union\[bytes, int\]", - "e2": r"str.*int.*Union\[int, str\]", - "e3": r"str.*int.*Union\[int, str\]", + "e1b": r"str.*bytes.*\bbytes \| int", + "e1i": r"str.*int.*\bbytes \| int", + "e2": r"str.*int.*\bint \| str", + "e3": r"str.*int.*\bint \| str", }, ) @@ -239,7 +239,7 @@ def g(x: str) -> None: self.assertErrorRegexes( errors, { - "e1": r"str.*Union\[bytes, int\]", + "e1": r"str.*\bbytes \| int", }, ) diff --git a/pytype/tests/test_unpack.py b/pytype/tests/test_unpack.py index 68e96f97e..b95ed4f5f 100644 --- a/pytype/tests/test_unpack.py +++ b/pytype/tests/test_unpack.py @@ -107,7 +107,7 @@ def f(w: A, x: int, y: str, z: str): """, pythonpath=[d.path], ) - self.assertErrorRegexes(errors, {"e": r"w: A.*w: Union.int,.str."}) + self.assertErrorRegexes(errors, {"e": r"w: A.*w: int \| str"}) def test_unpack_concrete_in_function_args(self): self.CheckWithErrors(""" diff --git a/pytype/tests/test_variable_annotations.py b/pytype/tests/test_variable_annotations.py index 747b7d232..835c0c4fe 100644 --- a/pytype/tests/test_variable_annotations.py +++ b/pytype/tests/test_variable_annotations.py @@ -33,7 +33,7 @@ def f(x: int) -> None: """, pythonpath=[d.path], ) - self.assertErrorRegexes(errors, {"e1": r"int.*List", "e2": r"int.*str"}) + self.assertErrorRegexes(errors, {"e1": r"int.*list", "e2": r"int.*str"}) def test_typevar_annot_with_subclass(self): self.Check(""" diff --git a/pytype/tools/annotate_ast/annotate_ast_test.py b/pytype/tools/annotate_ast/annotate_ast_test.py index 742975ee0..12162915b 100644 --- a/pytype/tools/annotate_ast/annotate_ast_test.py +++ b/pytype/tools/annotate_ast/annotate_ast_test.py @@ -43,9 +43,9 @@ def test_annotating_name(self): expected = { (1, 'Name', 'a'): 'int', - (2, 'Name', 'b'): 'Dict[int, str]', - (3, 'Name', 'c'): 'List[int]', - (4, 'Name', 'd'): 'Tuple[int, int]', + (2, 'Name', 'b'): 'dict[int, str]', + (3, 'Name', 'c'): 'list[int]', + (4, 'Name', 'd'): 'tuple[int, int]', } self.assertEqual(expected, self.get_annotations_dict(module)) diff --git a/pytype/tools/traces/traces_test.py b/pytype/tools/traces/traces_test.py index ab06f2f22..5d30e4141 100644 --- a/pytype/tools/traces/traces_test.py +++ b/pytype/tools/traces/traces_test.py @@ -158,9 +158,13 @@ class Foo: # The second attribute is at the wrong location due to limitations of # source.Code.get_attr_location(), but we can at least test that we get the # right number of traces with the right types. - self.assertTracesEqual(matches, [ - ((4, 5), "LOAD_ATTR", "real", ("Type[Foo]", "bool")), - ((4, 5), "LOAD_ATTR", "real", ("int", "int"))]) + self.assertTracesEqual( + matches, + [ + ((4, 5), "LOAD_ATTR", "real", ("type[Foo]", "bool")), + ((4, 5), "LOAD_ATTR", "real", ("int", "int")), + ], + ) def test_property(self): matches = self._get_traces(""" @@ -194,7 +198,7 @@ def test_multiline_subscr(self): x[0] = (1, 2) """, ast.Name) - x_annot = "List[Union[int, Tuple[int, int]]]" + x_annot = "list[int | tuple[int, int]]" self.assertTracesEqual(matches, [((1, 0), "STORE_NAME", "x", (x_annot,)), ((2, 0), "LOAD_NAME", "x", (x_annot,))]) @@ -218,9 +222,13 @@ def f(self, x): return x Foo().f(42) """, ast.Call) - self.assertTracesEqual(matches, [ - ((4, 0), _CALLFUNC_OP, "Foo", ("Type[Foo]", "Foo")), - ((4, 0), _CALLMETH_OP, "f", ("Callable[[Any], Any]", "int"))]) + self.assertTracesEqual( + matches, + [ + ((4, 0), _CALLFUNC_OP, "Foo", ("type[Foo]", "Foo")), + ((4, 0), _CALLMETH_OP, "f", ("Callable[[Any], Any]", "int")), + ], + ) def test_multiple_bindings(self): matches = self._get_traces(""" @@ -235,9 +243,10 @@ def f(x): f = Foo.f if __random__ else Bar.f f(42) """, ast.Call) - self.assertTracesEqual(matches, [ - ((10, 0), _CALLFUNC_OP, "f", - ("Callable[[Any], Any]", "Union[int, float]"))]) + self.assertTracesEqual( + matches, + [((10, 0), _CALLFUNC_OP, "f", ("Callable[[Any], Any]", "int | float"))], + ) def test_bad_call(self): matches = self._get_traces(""" @@ -316,7 +325,7 @@ def test_simple_slice(self): (2, 6), "BINARY_SLICE", "__getitem__", - ("Callable[[Union[int, slice]], str]", "str"), + ("Callable[[int | slice], str]", "str"), )] else: expected = [((2, 6), "BINARY_SUBSCR", "__getitem__", ("str",))]