Skip to content

Commit b0abcac

Browse files
authored
Add hidden --overwrite-union-syntax option (#20332)
Start updating the test output (errors and reveal type) to use the PEP 604 union syntax. The process is similar to what we did last year when we adopted PEP 585 generics in the test output. As we still default to Python 3.9 for type checking, this PR adds a temporary internal flag `--overwrite-union-syntax` to be able to overwrite the output. This PR only changes a handful of test files so the modifications to mypy itself are clearly visible. The goal is to change the test output for all other tests in followup PRs. Once that's done, I plan to deprecate the `--force-union-syntax` flag similar to the already deprecated `--force-uppercase-builtins`.
1 parent e69af83 commit b0abcac

File tree

7 files changed

+48
-44
lines changed

7 files changed

+48
-44
lines changed

mypy/main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -815,6 +815,10 @@ def add_invertible_flag(
815815
add_invertible_flag(
816816
"--force-union-syntax", default=False, help=argparse.SUPPRESS, group=none_group
817817
)
818+
# For internal use only! Will be removed once Mypy drops support for Python 3.9.
819+
add_invertible_flag(
820+
"--overwrite-union-syntax", default=False, help=argparse.SUPPRESS, group=none_group
821+
)
818822

819823
lint_group = parser.add_argument_group(
820824
title="Configuring warnings",

mypy/options.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,8 @@ def __init__(self) -> None:
413413
# Deprecated, Mypy only supports Python 3.9+
414414
self.force_uppercase_builtins = False
415415
self.force_union_syntax = False
416+
# Mypy internal use only! Set during test run.
417+
self.overwrite_union_syntax = False
416418

417419
# Sets custom output format
418420
self.output: str | None = None
@@ -434,7 +436,7 @@ def use_lowercase_names(self) -> bool:
434436
def use_or_syntax(self) -> bool:
435437
if self.python_version >= (3, 10):
436438
return not self.force_union_syntax
437-
return False
439+
return self.overwrite_union_syntax
438440

439441
def use_star_unpack(self) -> bool:
440442
return self.python_version >= (3, 11)

mypy/test/testcmdline.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,13 @@ def test_python_cmdline(testcase: DataDrivenTestCase, step: int) -> None:
6060
args = parse_args(testcase.input[0])
6161
custom_cwd = parse_cwd(testcase.input[1]) if len(testcase.input) > 1 else None
6262
args.append("--show-traceback")
63+
args.append("--overwrite-union-syntax")
6364
if "--error-summary" not in args:
6465
args.append("--no-error-summary")
6566
if "--show-error-codes" not in args:
6667
args.append("--hide-error-codes")
6768
if "--disallow-empty-bodies" not in args:
6869
args.append("--allow-empty-bodies")
69-
if "--no-force-union-syntax" not in args:
70-
args.append("--force-union-syntax")
7170
# Type check the program.
7271
fixed = [python3_path, "-m", "mypy"]
7372
env = os.environ.copy()

mypy/test/testpythoneval.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ def test_python_evaluation(testcase: DataDrivenTestCase, cache_dir: str) -> None
5252
"--no-error-summary",
5353
"--hide-error-codes",
5454
"--allow-empty-bodies",
55+
"--overwrite-union-syntax",
5556
"--test-env", # Speeds up some checks
5657
]
5758
interpreter = python3_path
@@ -71,9 +72,6 @@ def test_python_evaluation(testcase: DataDrivenTestCase, cache_dir: str) -> None
7172
return
7273
mypy_cmdline.extend(additional_flags)
7374

74-
if "--no-force-union-syntax" not in mypy_cmdline:
75-
mypy_cmdline.append("--force-union-syntax")
76-
7775
# Write the program to a file.
7876
program = "_" + testcase.name + ".py"
7977
program_path = os.path.join(test_temp_dir, program)

mypy/types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3736,6 +3736,7 @@ class TypeStrVisitor(SyntheticTypeVisitor[str]):
37363736
Notes:
37373737
- Represent unbound types as Foo? or Foo?[...].
37383738
- Represent the NoneType type as None.
3739+
- Represent Union[x, y] as x | y
37393740
"""
37403741

37413742
def __init__(self, id_mapper: IdMapper | None = None, *, options: Options) -> None:

test-data/unit/cmdline.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -900,7 +900,7 @@ some_file.py:11: error: Incompatible types in assignment (expression has type
900900
...t_attribute_with_long_name: OneCustomClassName = OneCustomClassName()....
901901
^~~~~~~~~~~~~~~~~~~~~...
902902
some_file.py:11: error: Argument 1 to "some_interesting_method" of
903-
"OneCustomClassName" has incompatible type "Union[int, str, float]"; expected
903+
"OneCustomClassName" has incompatible type "int | str | float"; expected
904904
"AnotherCustomClassDefinedBelow"
905905
...OneCustomClassName = OneCustomClassName().some_interesting_method(arg)
906906
^~~

test-data/unit/pythoneval.test

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ txt(sys.stdout)
234234
bin(sys.stdout)
235235
[out]
236236
_program.py:5: error: Argument 1 to "write" of "IO" has incompatible type "bytes"; expected "str"
237-
_program.py:10: error: Argument 1 to "bin" has incompatible type "Union[TextIO, Any]"; expected "IO[bytes]"
237+
_program.py:10: error: Argument 1 to "bin" has incompatible type "TextIO | Any"; expected "IO[bytes]"
238238

239239
[case testBuiltinOpen]
240240
f = open('x')
@@ -627,7 +627,7 @@ a + 1
627627
_testMapStr.py:4: error: No overload variant of "__add__" of "list" matches argument type "int"
628628
_testMapStr.py:4: note: Possible overload variants:
629629
_testMapStr.py:4: note: def __add__(self, list[str], /) -> list[str]
630-
_testMapStr.py:4: note: def [_S] __add__(self, list[_S], /) -> list[Union[_S, str]]
630+
_testMapStr.py:4: note: def [_S] __add__(self, list[_S], /) -> list[_S | str]
631631

632632
[case testRelativeImport]
633633
import typing
@@ -762,7 +762,7 @@ def p(t: Tuple[str, ...]) -> None:
762762
''.startswith(('x', b'y'))
763763
[out]
764764
_program.py:6: error: "str" not callable
765-
_program.py:8: error: Argument 1 to "startswith" of "str" has incompatible type "tuple[str, bytes]"; expected "Union[str, tuple[str, ...]]"
765+
_program.py:8: error: Argument 1 to "startswith" of "str" has incompatible type "tuple[str, bytes]"; expected "str | tuple[str, ...]"
766766

767767
[case testMultiplyTupleByInteger]
768768
n = 4
@@ -772,7 +772,7 @@ t + 1
772772
_program.py:3: error: No overload variant of "__add__" of "tuple" matches argument type "int"
773773
_program.py:3: note: Possible overload variants:
774774
_program.py:3: note: def __add__(self, tuple[str, ...], /) -> tuple[str, ...]
775-
_program.py:3: note: def [_T] __add__(self, tuple[_T, ...], /) -> tuple[Union[str, _T], ...]
775+
_program.py:3: note: def [_T] __add__(self, tuple[_T, ...], /) -> tuple[str | _T, ...]
776776

777777
[case testMultiplyTupleByIntegerReverse]
778778
n = 4
@@ -782,7 +782,7 @@ t + 1
782782
_program.py:3: error: No overload variant of "__add__" of "tuple" matches argument type "int"
783783
_program.py:3: note: Possible overload variants:
784784
_program.py:3: note: def __add__(self, tuple[str, ...], /) -> tuple[str, ...]
785-
_program.py:3: note: def [_T] __add__(self, tuple[_T, ...], /) -> tuple[Union[str, _T], ...]
785+
_program.py:3: note: def [_T] __add__(self, tuple[_T, ...], /) -> tuple[str | _T, ...]
786786

787787
[case testDictWithKeywordArgs]
788788
from typing import Dict, Any, List
@@ -822,7 +822,7 @@ class MyDDict(t.DefaultDict[int,T], t.Generic[T]):
822822
MyDDict(dict)['0']
823823
MyDDict(dict)[0]
824824
[out]
825-
_program.py:6: error: Argument 1 to "defaultdict" has incompatible type "type[list[_T]]"; expected "Optional[Callable[[], str]]"
825+
_program.py:6: error: Argument 1 to "defaultdict" has incompatible type "type[list[_T]]"; expected "Callable[[], str] | None"
826826
_program.py:9: error: Invalid index type "str" for "defaultdict[int, str]"; expected type "int"
827827
_program.py:9: error: Incompatible types in assignment (expression has type "int", target has type "str")
828828
_program.py:19: error: Argument 1 to "tst" has incompatible type "defaultdict[str, list[Never]]"; expected "defaultdict[int, list[Never]]"
@@ -962,9 +962,9 @@ re.subn(bpat, lambda m: b'', b'')[0] + b''
962962
[out]
963963
_testReModuleBytes.py:9: error: No overload variant of "search" matches argument types "bytes", "str"
964964
_testReModuleBytes.py:9: note: Possible overload variants:
965-
_testReModuleBytes.py:9: note: def search(pattern: Union[str, Pattern[str]], string: str, flags: Union[int, RegexFlag] = ...) -> Optional[Match[str]]
966-
_testReModuleBytes.py:9: note: def search(pattern: Union[bytes, Pattern[bytes]], string: Buffer, flags: Union[int, RegexFlag] = ...) -> Optional[Match[bytes]]
967-
_testReModuleBytes.py:13: error: Argument 1 to "search" has incompatible type "Pattern[bytes]"; expected "Union[str, Pattern[str]]"
965+
_testReModuleBytes.py:9: note: def search(pattern: str | Pattern[str], string: str, flags: int | RegexFlag = ...) -> Match[str] | None
966+
_testReModuleBytes.py:9: note: def search(pattern: bytes | Pattern[bytes], string: Buffer, flags: int | RegexFlag = ...) -> Match[bytes] | None
967+
_testReModuleBytes.py:13: error: Argument 1 to "search" has incompatible type "Pattern[bytes]"; expected "str | Pattern[str]"
968968

969969
[case testReModuleString]
970970
# Regression tests for various overloads in the re module -- string version
@@ -993,9 +993,9 @@ re.subn(spat, lambda m: '', '')[0] + ''
993993
[out]
994994
_testReModuleString.py:9: error: No overload variant of "search" matches argument types "str", "bytes"
995995
_testReModuleString.py:9: note: Possible overload variants:
996-
_testReModuleString.py:9: note: def search(pattern: Union[str, Pattern[str]], string: str, flags: Union[int, RegexFlag] = ...) -> Optional[Match[str]]
997-
_testReModuleString.py:9: note: def search(pattern: Union[bytes, Pattern[bytes]], string: Buffer, flags: Union[int, RegexFlag] = ...) -> Optional[Match[bytes]]
998-
_testReModuleString.py:13: error: Argument 1 to "search" has incompatible type "Pattern[str]"; expected "Union[bytes, Pattern[bytes]]"
996+
_testReModuleString.py:9: note: def search(pattern: str | Pattern[str], string: str, flags: int | RegexFlag = ...) -> Match[str] | None
997+
_testReModuleString.py:9: note: def search(pattern: bytes | Pattern[bytes], string: Buffer, flags: int | RegexFlag = ...) -> Match[bytes] | None
998+
_testReModuleString.py:13: error: Argument 1 to "search" has incompatible type "Pattern[str]"; expected "bytes | Pattern[bytes]"
999999

10001000
[case testListSetitemTuple]
10011001
from typing import List, Tuple
@@ -1062,8 +1062,8 @@ _testTypedDictGet.py:11: note: def get(self, str, /) -> object
10621062
_testTypedDictGet.py:11: note: def get(self, str, /, default: object) -> object
10631063
_testTypedDictGet.py:11: note: def [_T] get(self, str, /, default: _T) -> object
10641064
_testTypedDictGet.py:13: note: Revealed type is "builtins.object"
1065-
_testTypedDictGet.py:16: note: Revealed type is "Union[builtins.int, None]"
1066-
_testTypedDictGet.py:17: note: Revealed type is "Union[builtins.str, None]"
1065+
_testTypedDictGet.py:16: note: Revealed type is "builtins.int | None"
1066+
_testTypedDictGet.py:17: note: Revealed type is "builtins.str | None"
10671067
_testTypedDictGet.py:18: note: Revealed type is "builtins.object"
10681068
_testTypedDictGet.py:19: error: All overload variants of "get" of "Mapping" require at least one argument
10691069
_testTypedDictGet.py:19: note: Possible overload variants:
@@ -1184,10 +1184,10 @@ for a, b in x.items():
11841184
[out]
11851185
_testNoCrashOnGenericUnionUnpacking.py:6: note: Revealed type is "builtins.str"
11861186
_testNoCrashOnGenericUnionUnpacking.py:7: note: Revealed type is "builtins.str"
1187-
_testNoCrashOnGenericUnionUnpacking.py:10: note: Revealed type is "Union[builtins.str, builtins.int]"
1188-
_testNoCrashOnGenericUnionUnpacking.py:11: note: Revealed type is "Union[builtins.str, builtins.int]"
1189-
_testNoCrashOnGenericUnionUnpacking.py:15: note: Revealed type is "Union[builtins.int, builtins.str]"
1190-
_testNoCrashOnGenericUnionUnpacking.py:16: note: Revealed type is "Union[builtins.int, builtins.str]"
1187+
_testNoCrashOnGenericUnionUnpacking.py:10: note: Revealed type is "builtins.str | builtins.int"
1188+
_testNoCrashOnGenericUnionUnpacking.py:11: note: Revealed type is "builtins.str | builtins.int"
1189+
_testNoCrashOnGenericUnionUnpacking.py:15: note: Revealed type is "builtins.int | builtins.str"
1190+
_testNoCrashOnGenericUnionUnpacking.py:16: note: Revealed type is "builtins.int | builtins.str"
11911191

11921192
[case testMetaclassOpAccess]
11931193
from typing import Type
@@ -1234,7 +1234,7 @@ bar: Type[Union[A, B]]
12341234
res = bar * 4
12351235
reveal_type(res)
12361236
[out]
1237-
_testMetaclassOpAccessUnion.py:16: note: Revealed type is "Union[builtins.str, builtins.int]"
1237+
_testMetaclassOpAccessUnion.py:16: note: Revealed type is "builtins.str | builtins.int"
12381238

12391239
[case testMetaclassOpAccessAny]
12401240
from typing import Type
@@ -1303,9 +1303,9 @@ class B:
13031303
class C:
13041304
__slots__: List[int] = []
13051305
[out]
1306-
_testInvalidSlots.py:3: error: Invalid type for "__slots__" (actual type "int", expected type "Union[str, Iterable[str]]")
1307-
_testInvalidSlots.py:5: error: Invalid type for "__slots__" (actual type "tuple[int, int]", expected type "Union[str, Iterable[str]]")
1308-
_testInvalidSlots.py:7: error: Invalid type for "__slots__" (actual type "list[int]", expected type "Union[str, Iterable[str]]")
1306+
_testInvalidSlots.py:3: error: Invalid type for "__slots__" (actual type "int", expected type "str | Iterable[str]")
1307+
_testInvalidSlots.py:5: error: Invalid type for "__slots__" (actual type "tuple[int, int]", expected type "str | Iterable[str]")
1308+
_testInvalidSlots.py:7: error: Invalid type for "__slots__" (actual type "list[int]", expected type "str | Iterable[str]")
13091309

13101310
[case testDictWithStarStarSpecialCase]
13111311
from typing import Dict
@@ -1609,9 +1609,9 @@ else:
16091609

16101610
[out]
16111611
_testNarrowTypeForDictKeys.py:6: note: Revealed type is "builtins.str"
1612-
_testNarrowTypeForDictKeys.py:8: note: Revealed type is "Union[builtins.str, None]"
1612+
_testNarrowTypeForDictKeys.py:8: note: Revealed type is "builtins.str | None"
16131613
_testNarrowTypeForDictKeys.py:13: note: Revealed type is "builtins.str"
1614-
_testNarrowTypeForDictKeys.py:15: note: Revealed type is "Union[builtins.str, None]"
1614+
_testNarrowTypeForDictKeys.py:15: note: Revealed type is "builtins.str | None"
16151615

16161616
[case testTypeAliasWithNewStyleUnion]
16171617
# flags: --python-version 3.10
@@ -1651,8 +1651,8 @@ def foo(x: T) -> T:
16511651
return x
16521652
[out]
16531653
_testTypeAliasWithNewStyleUnion.py:5: note: Revealed type is "typing._SpecialForm"
1654-
_testTypeAliasWithNewStyleUnion.py:25: note: Revealed type is "Union[type[builtins.int], builtins.str]"
1655-
_testTypeAliasWithNewStyleUnion.py:28: note: Revealed type is "Union[type[builtins.int], builtins.str]"
1654+
_testTypeAliasWithNewStyleUnion.py:25: note: Revealed type is "type[builtins.int] | builtins.str"
1655+
_testTypeAliasWithNewStyleUnion.py:28: note: Revealed type is "type[builtins.int] | builtins.str"
16561656

16571657
[case testTypeAliasWithNewStyleUnionInStub]
16581658
import m
@@ -1705,12 +1705,12 @@ CU4: TypeAlias = int | Callable[[str | bool], str]
17051705
[out]
17061706
m.pyi:5: note: Revealed type is "typing._SpecialForm"
17071707
m.pyi:22: note: Revealed type is "types.UnionType[type[builtins.int], builtins.str]"
1708-
_testTypeAliasWithNewStyleUnionInStub.py:3: note: Revealed type is "Union[type[builtins.int], builtins.str]"
1709-
_testTypeAliasWithNewStyleUnionInStub.py:5: note: Revealed type is "Union[type[builtins.int], builtins.str]"
1710-
_testTypeAliasWithNewStyleUnionInStub.py:7: note: Revealed type is "Union[type[builtins.int], builtins.str]"
1711-
_testTypeAliasWithNewStyleUnionInStub.py:9: note: Revealed type is "Union[type[builtins.int], builtins.str]"
1712-
_testTypeAliasWithNewStyleUnionInStub.py:11: note: Revealed type is "Union[builtins.str, type[builtins.int]]"
1713-
_testTypeAliasWithNewStyleUnionInStub.py:13: note: Revealed type is "Union[builtins.str, type[builtins.int]]"
1708+
_testTypeAliasWithNewStyleUnionInStub.py:3: note: Revealed type is "type[builtins.int] | builtins.str"
1709+
_testTypeAliasWithNewStyleUnionInStub.py:5: note: Revealed type is "type[builtins.int] | builtins.str"
1710+
_testTypeAliasWithNewStyleUnionInStub.py:7: note: Revealed type is "type[builtins.int] | builtins.str"
1711+
_testTypeAliasWithNewStyleUnionInStub.py:9: note: Revealed type is "type[builtins.int] | builtins.str"
1712+
_testTypeAliasWithNewStyleUnionInStub.py:11: note: Revealed type is "builtins.str | type[builtins.int]"
1713+
_testTypeAliasWithNewStyleUnionInStub.py:13: note: Revealed type is "builtins.str | type[builtins.int]"
17141714

17151715
[case testEnumNameWorkCorrectlyOn311]
17161716
# flags: --python-version 3.11
@@ -1730,7 +1730,7 @@ reveal_type(e.foo)
17301730
reveal_type(E.Y.foo)
17311731
[out]
17321732
_testEnumNameWorkCorrectlyOn311.py:11: note: Revealed type is "builtins.str"
1733-
_testEnumNameWorkCorrectlyOn311.py:12: note: Revealed type is "Union[Literal[1]?, Literal[2]?]"
1733+
_testEnumNameWorkCorrectlyOn311.py:12: note: Revealed type is "Literal[1]? | Literal[2]?"
17341734
_testEnumNameWorkCorrectlyOn311.py:13: note: Revealed type is "Literal['X']?"
17351735
_testEnumNameWorkCorrectlyOn311.py:14: note: Revealed type is "builtins.int"
17361736
_testEnumNameWorkCorrectlyOn311.py:15: note: Revealed type is "builtins.int"
@@ -1799,9 +1799,9 @@ WrongEllipsis = tuple[float, float, ...] | str # Error
17991799

18001800
reveal_type(tuple[int, str]((1, "x")))
18011801
[out]
1802-
_testTupleWithDifferentArgsPy310.py:15: note: Revealed type is "Union[builtins.str, tuple[builtins.float, builtins.float, builtins.str]]"
1803-
_testTupleWithDifferentArgsPy310.py:16: note: Revealed type is "Union[tuple[builtins.float], builtins.str]"
1804-
_testTupleWithDifferentArgsPy310.py:17: note: Revealed type is "Union[builtins.tuple[builtins.float, ...], builtins.str]"
1802+
_testTupleWithDifferentArgsPy310.py:15: note: Revealed type is "builtins.str | tuple[builtins.float, builtins.float, builtins.str]"
1803+
_testTupleWithDifferentArgsPy310.py:16: note: Revealed type is "tuple[builtins.float] | builtins.str"
1804+
_testTupleWithDifferentArgsPy310.py:17: note: Revealed type is "builtins.tuple[builtins.float, ...] | builtins.str"
18051805
_testTupleWithDifferentArgsPy310.py:18: note: Revealed type is "tuple[builtins.float, builtins.str]"
18061806
_testTupleWithDifferentArgsPy310.py:19: note: Revealed type is "builtins.tuple[builtins.float, ...]"
18071807
_testTupleWithDifferentArgsPy310.py:20: note: Revealed type is "builtins.list[tuple[builtins.int, builtins.str]]"
@@ -2059,7 +2059,7 @@ class Description:
20592059
def f(d: Description) -> None:
20602060
reveal_type(d.name_fn)
20612061
[out]
2062-
_testDataclassStrictOptionalAlwaysSet.py:9: note: Revealed type is "def (Union[builtins.int, None]) -> Union[builtins.str, None]"
2062+
_testDataclassStrictOptionalAlwaysSet.py:9: note: Revealed type is "def (builtins.int | None) -> builtins.str | None"
20632063

20642064
[case testPEP695VarianceInference]
20652065
# flags: --python-version=3.12

0 commit comments

Comments
 (0)