Skip to content

Commit e2a5783

Browse files
committed
Deprecated --force-union-syntax flag
1 parent 69112dd commit e2a5783

File tree

10 files changed

+29
-92
lines changed

10 files changed

+29
-92
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ Support for this will be dropped in the first half of 2026!
1111

1212
Contributed by Marc Mueller (PR [20156](https://github.com/python/mypy/pull/20156)).
1313

14+
### Deprecated Flag: `--force-union-syntax`
15+
16+
Mypy only supports Python 3.10+. The `--force-union-syntax` flag is now
17+
deprecated, and a no-op. It will be removed in a future version.
18+
19+
Contributed by Marc Mueller (PR [20405](https://github.com/python/mypy/pull/20405))
20+
1421
## Mypy 1.19
1522

1623
We’ve just uploaded mypy 1.19.0 to the Python Package Index ([PyPI](https://pypi.org/project/mypy/)).

docs/source/command_line.rst

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -958,12 +958,6 @@ in error messages.
958958
useful or they may be overly noisy. If ``N`` is negative, there is
959959
no limit. The default limit is -1.
960960

961-
.. option:: --force-union-syntax
962-
963-
Always use ``Union[]`` and ``Optional[]`` for union types
964-
in error messages (instead of the ``|`` operator),
965-
even on Python 3.10+.
966-
967961

968962
.. _incremental:
969963

docs/source/config_file.rst

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -930,15 +930,6 @@ These options may only be set in the global section (``[mypy]``).
930930

931931
Show absolute paths to files.
932932

933-
.. confval:: force_union_syntax
934-
935-
:type: boolean
936-
:default: False
937-
938-
Always use ``Union[]`` and ``Optional[]`` for union types
939-
in error messages (instead of the ``|`` operator),
940-
even on Python 3.10+.
941-
942933
Incremental mode
943934
****************
944935

mypy/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,7 @@ def add_invertible_flag(
819819
add_invertible_flag(
820820
"--force-uppercase-builtins", default=False, help=argparse.SUPPRESS, group=none_group
821821
)
822-
822+
# This flag is deprecated, Mypy only supports Python 3.10+
823823
add_invertible_flag(
824824
"--force-union-syntax", default=False, help=argparse.SUPPRESS, group=none_group
825825
)

mypy/messages.py

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,10 +1813,7 @@ def need_annotation_for_var(
18131813
type_dec = "<type>"
18141814
if not node.type.type:
18151815
# partial None
1816-
if options.use_or_syntax():
1817-
recommended_type = f"{type_dec} | None"
1818-
else:
1819-
recommended_type = f"Optional[{type_dec}]"
1816+
recommended_type = f"{type_dec} | None"
18201817
elif node.type.type.fullname in reverse_builtin_aliases:
18211818
# partial types other than partial None
18221819
name = node.type.type.fullname.partition(".")[2]
@@ -2713,17 +2710,9 @@ def format_literal_value(typ: LiteralType) -> str:
27132710
)
27142711

27152712
if len(union_items) == 1 and isinstance(get_proper_type(union_items[0]), NoneType):
2716-
return (
2717-
f"{literal_str} | None"
2718-
if options.use_or_syntax()
2719-
else f"Optional[{literal_str}]"
2720-
)
2713+
return f"{literal_str} | None"
27212714
elif union_items:
2722-
return (
2723-
f"{literal_str} | {format_union(union_items)}"
2724-
if options.use_or_syntax()
2725-
else f"Union[{', '.join(format_union_items(union_items))}, {literal_str}]"
2726-
)
2715+
return f"{literal_str} | {format_union(union_items)}"
27272716
else:
27282717
return literal_str
27292718
else:
@@ -2734,17 +2723,9 @@ def format_literal_value(typ: LiteralType) -> str:
27342723
)
27352724
if print_as_optional:
27362725
rest = [t for t in typ.items if not isinstance(get_proper_type(t), NoneType)]
2737-
return (
2738-
f"{format(rest[0])} | None"
2739-
if options.use_or_syntax()
2740-
else f"Optional[{format(rest[0])}]"
2741-
)
2726+
return f"{format(rest[0])} | None"
27422727
else:
2743-
s = (
2744-
format_union(typ.items)
2745-
if options.use_or_syntax()
2746-
else f"Union[{', '.join(format_union_items(typ.items))}]"
2747-
)
2728+
s = format_union(typ.items)
27482729
return s
27492730
elif isinstance(typ, NoneType):
27502731
return "None"

mypy/options.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -434,9 +434,12 @@ def use_lowercase_names(self) -> bool:
434434
return True
435435

436436
def use_or_syntax(self) -> bool:
437-
if self.python_version >= (3, 10):
438-
return not self.force_union_syntax
439-
return self.overwrite_union_syntax
437+
warnings.warn(
438+
"options.use_or_syntax() is deprecated and will be removed in a future version",
439+
DeprecationWarning,
440+
stacklevel=2,
441+
)
442+
return True
440443

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

mypy/suggestions.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ def visit_typeddict_type(self, t: TypedDictType) -> str:
891891
def visit_union_type(self, t: UnionType) -> str:
892892
if len(t.items) == 2 and is_overlapping_none(t):
893893
s = remove_optional(t).accept(self)
894-
return f"{s} | None" if self.options.use_or_syntax() else f"Optional[{s}]"
894+
return f"{s} | None"
895895
else:
896896
return super().visit_union_type(t)
897897

mypy/types.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3967,9 +3967,7 @@ def visit_literal_type(self, t: LiteralType, /) -> str:
39673967
return f"Literal[{t.value_repr()}]"
39683968

39693969
def visit_union_type(self, t: UnionType, /) -> str:
3970-
use_or_syntax = self.options.use_or_syntax()
3971-
s = self.list_str(t.items, use_or_syntax=use_or_syntax)
3972-
return s if use_or_syntax else f"Union[{s}]"
3970+
return self.list_str(t.items, use_or_syntax=True)
39733971

39743972
def visit_partial_type(self, t: PartialType, /) -> str:
39753973
if t.type is None:

test-data/unit/check-union-error-syntax.test

Lines changed: 7 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,37 @@
1-
[case testUnionErrorSyntax]
2-
# flags: --python-version 3.10 --no-force-union-syntax
3-
from typing import Union
4-
x : Union[bool, str]
5-
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "bool | str")
6-
71
[case testOrErrorSyntax]
8-
# flags: --python-version 3.10 --force-union-syntax
2+
# flags: --python-version 3.10
93
from typing import Union
104
x : Union[bool, str]
11-
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "Union[bool, str]")
5+
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "bool | str")
126

137
[case testOrNoneErrorSyntax]
14-
# flags: --python-version 3.10 --no-force-union-syntax
8+
# flags: --python-version 3.10
159
from typing import Union
1610
x : Union[bool, None]
1711
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "bool | None")
1812

19-
[case testOptionalErrorSyntax]
20-
# flags: --python-version 3.10 --force-union-syntax
21-
from typing import Union
22-
x : Union[bool, None]
23-
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "Optional[bool]")
24-
2513
[case testNoneAsFinalItem]
26-
# flags: --python-version 3.10 --no-force-union-syntax
14+
# flags: --python-version 3.10
2715
from typing import Union
2816
x : Union[bool, None, str]
2917
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "bool | str | None")
3018

3119
[case testLiteralOrErrorSyntax]
32-
# flags: --python-version 3.10 --no-force-union-syntax
20+
# flags: --python-version 3.10
3321
from typing import Literal, Union
3422
x : Union[Literal[1], Literal[2], str]
3523
x = 3 # E: Incompatible types in assignment (expression has type "Literal[3]", variable has type "Literal[1, 2] | str")
3624
[builtins fixtures/tuple.pyi]
3725

38-
[case testLiteralUnionErrorSyntax]
39-
# flags: --python-version 3.10 --force-union-syntax
40-
from typing import Literal, Union
41-
x : Union[Literal[1], Literal[2], str]
42-
x = 3 # E: Incompatible types in assignment (expression has type "Literal[3]", variable has type "Union[str, Literal[1, 2]]")
43-
[builtins fixtures/tuple.pyi]
44-
4526
[case testLiteralOrNoneErrorSyntax]
46-
# flags: --python-version 3.10 --no-force-union-syntax
27+
# flags: --python-version 3.10
4728
from typing import Literal, Union
4829
x : Union[Literal[1], None]
4930
x = 3 # E: Incompatible types in assignment (expression has type "Literal[3]", variable has type "Literal[1] | None")
5031
[builtins fixtures/tuple.pyi]
5132

52-
[case testLiteralOptionalErrorSyntax]
53-
# flags: --python-version 3.10 --force-union-syntax
54-
from typing import Literal, Union
55-
x : Union[Literal[1], None]
56-
x = 3 # E: Incompatible types in assignment (expression has type "Literal[3]", variable has type "Optional[Literal[1]]")
57-
[builtins fixtures/tuple.pyi]
58-
59-
[case testUnionSyntaxRecombined]
60-
# flags: --python-version 3.10 --force-union-syntax --allow-redefinition-new --local-partial-types
61-
# The following revealed type is recombined because the finally body is visited twice.
62-
try:
63-
x = 1
64-
x = ""
65-
x = {1: ""}
66-
finally:
67-
reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str, builtins.dict[builtins.int, builtins.str]]"
68-
[builtins fixtures/isinstancelist.pyi]
69-
7033
[case testOrSyntaxRecombined]
71-
# flags: --python-version 3.10 --no-force-union-syntax --allow-redefinition-new --local-partial-types
34+
# flags: --python-version 3.10 --allow-redefinition-new --local-partial-types
7235
# The following revealed type is recombined because the finally body is visited twice.
7336
try:
7437
x = 1

test-data/unit/daemon.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ $ dmypy inspect foo.py:3:10:3:17 -vv
456456
$ dmypy inspect foo.py:9:9:9:11
457457
"int"
458458
$ dmypy inspect foo.py:11:1:11:3
459-
"Callable[[Optional[int]], None]"
459+
"Callable[[int | None], None]"
460460
$ dmypy inspect foo.py:11:1:13:1
461461
"None"
462462
$ dmypy inspect foo.py:1:2:3:4

0 commit comments

Comments
 (0)