Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Deprecated --force-union-syntax flag
  • Loading branch information
cdce8p committed Dec 13, 2025
commit e2a5783921e92d49bff39328b720174d0d4a7a2f
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ Support for this will be dropped in the first half of 2026!

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

### Deprecated Flag: `--force-union-syntax`

Mypy only supports Python 3.10+. The `--force-union-syntax` flag is now
deprecated, and a no-op. It will be removed in a future version.

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

## Mypy 1.19

We’ve just uploaded mypy 1.19.0 to the Python Package Index ([PyPI](https://pypi.org/project/mypy/)).
Expand Down
6 changes: 0 additions & 6 deletions docs/source/command_line.rst
Original file line number Diff line number Diff line change
Expand Up @@ -958,12 +958,6 @@ in error messages.
useful or they may be overly noisy. If ``N`` is negative, there is
no limit. The default limit is -1.

.. option:: --force-union-syntax

Always use ``Union[]`` and ``Optional[]`` for union types
in error messages (instead of the ``|`` operator),
even on Python 3.10+.


.. _incremental:

Expand Down
9 changes: 0 additions & 9 deletions docs/source/config_file.rst
Original file line number Diff line number Diff line change
Expand Up @@ -930,15 +930,6 @@ These options may only be set in the global section (``[mypy]``).

Show absolute paths to files.

.. confval:: force_union_syntax

:type: boolean
:default: False

Always use ``Union[]`` and ``Optional[]`` for union types
in error messages (instead of the ``|`` operator),
even on Python 3.10+.

Incremental mode
****************

Expand Down
2 changes: 1 addition & 1 deletion mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,7 @@ def add_invertible_flag(
add_invertible_flag(
"--force-uppercase-builtins", default=False, help=argparse.SUPPRESS, group=none_group
)

# This flag is deprecated, Mypy only supports Python 3.10+
add_invertible_flag(
"--force-union-syntax", default=False, help=argparse.SUPPRESS, group=none_group
)
Expand Down
29 changes: 5 additions & 24 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -1813,10 +1813,7 @@ def need_annotation_for_var(
type_dec = "<type>"
if not node.type.type:
# partial None
if options.use_or_syntax():
recommended_type = f"{type_dec} | None"
else:
recommended_type = f"Optional[{type_dec}]"
recommended_type = f"{type_dec} | None"
elif node.type.type.fullname in reverse_builtin_aliases:
# partial types other than partial None
name = node.type.type.fullname.partition(".")[2]
Expand Down Expand Up @@ -2713,17 +2710,9 @@ def format_literal_value(typ: LiteralType) -> str:
)

if len(union_items) == 1 and isinstance(get_proper_type(union_items[0]), NoneType):
return (
f"{literal_str} | None"
if options.use_or_syntax()
else f"Optional[{literal_str}]"
)
return f"{literal_str} | None"
elif union_items:
return (
f"{literal_str} | {format_union(union_items)}"
if options.use_or_syntax()
else f"Union[{', '.join(format_union_items(union_items))}, {literal_str}]"
)
return f"{literal_str} | {format_union(union_items)}"
else:
return literal_str
else:
Expand All @@ -2734,17 +2723,9 @@ def format_literal_value(typ: LiteralType) -> str:
)
if print_as_optional:
rest = [t for t in typ.items if not isinstance(get_proper_type(t), NoneType)]
return (
f"{format(rest[0])} | None"
if options.use_or_syntax()
else f"Optional[{format(rest[0])}]"
)
return f"{format(rest[0])} | None"
else:
s = (
format_union(typ.items)
if options.use_or_syntax()
else f"Union[{', '.join(format_union_items(typ.items))}]"
)
s = format_union(typ.items)
return s
elif isinstance(typ, NoneType):
return "None"
Expand Down
9 changes: 6 additions & 3 deletions mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -434,9 +434,12 @@ def use_lowercase_names(self) -> bool:
return True

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

def use_star_unpack(self) -> bool:
return self.python_version >= (3, 11)
Expand Down
2 changes: 1 addition & 1 deletion mypy/suggestions.py
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ def visit_typeddict_type(self, t: TypedDictType) -> str:
def visit_union_type(self, t: UnionType) -> str:
if len(t.items) == 2 and is_overlapping_none(t):
s = remove_optional(t).accept(self)
return f"{s} | None" if self.options.use_or_syntax() else f"Optional[{s}]"
return f"{s} | None"
else:
return super().visit_union_type(t)

Expand Down
4 changes: 1 addition & 3 deletions mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3967,9 +3967,7 @@ def visit_literal_type(self, t: LiteralType, /) -> str:
return f"Literal[{t.value_repr()}]"

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

def visit_partial_type(self, t: PartialType, /) -> str:
if t.type is None:
Expand Down
51 changes: 7 additions & 44 deletions test-data/unit/check-union-error-syntax.test
Original file line number Diff line number Diff line change
@@ -1,74 +1,37 @@
[case testUnionErrorSyntax]
# flags: --python-version 3.10 --no-force-union-syntax
from typing import Union
x : Union[bool, str]
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "bool | str")

[case testOrErrorSyntax]
# flags: --python-version 3.10 --force-union-syntax
# flags: --python-version 3.10
from typing import Union
x : Union[bool, str]
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "Union[bool, str]")
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "bool | str")

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

[case testOptionalErrorSyntax]
# flags: --python-version 3.10 --force-union-syntax
from typing import Union
x : Union[bool, None]
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "Optional[bool]")

[case testNoneAsFinalItem]
# flags: --python-version 3.10 --no-force-union-syntax
# flags: --python-version 3.10
from typing import Union
x : Union[bool, None, str]
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "bool | str | None")

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

[case testLiteralUnionErrorSyntax]
# flags: --python-version 3.10 --force-union-syntax
from typing import Literal, Union
x : Union[Literal[1], Literal[2], str]
x = 3 # E: Incompatible types in assignment (expression has type "Literal[3]", variable has type "Union[str, Literal[1, 2]]")
[builtins fixtures/tuple.pyi]

[case testLiteralOrNoneErrorSyntax]
# flags: --python-version 3.10 --no-force-union-syntax
# flags: --python-version 3.10
from typing import Literal, Union
x : Union[Literal[1], None]
x = 3 # E: Incompatible types in assignment (expression has type "Literal[3]", variable has type "Literal[1] | None")
[builtins fixtures/tuple.pyi]

[case testLiteralOptionalErrorSyntax]
# flags: --python-version 3.10 --force-union-syntax
from typing import Literal, Union
x : Union[Literal[1], None]
x = 3 # E: Incompatible types in assignment (expression has type "Literal[3]", variable has type "Optional[Literal[1]]")
[builtins fixtures/tuple.pyi]

[case testUnionSyntaxRecombined]
# flags: --python-version 3.10 --force-union-syntax --allow-redefinition-new --local-partial-types
# The following revealed type is recombined because the finally body is visited twice.
try:
x = 1
x = ""
x = {1: ""}
finally:
reveal_type(x) # N: Revealed type is "Union[builtins.int, builtins.str, builtins.dict[builtins.int, builtins.str]]"
[builtins fixtures/isinstancelist.pyi]

[case testOrSyntaxRecombined]
# flags: --python-version 3.10 --no-force-union-syntax --allow-redefinition-new --local-partial-types
# flags: --python-version 3.10 --allow-redefinition-new --local-partial-types
# The following revealed type is recombined because the finally body is visited twice.
try:
x = 1
Expand Down
2 changes: 1 addition & 1 deletion test-data/unit/daemon.test
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ $ dmypy inspect foo.py:3:10:3:17 -vv
$ dmypy inspect foo.py:9:9:9:11
"int"
$ dmypy inspect foo.py:11:1:11:3
"Callable[[Optional[int]], None]"
"Callable[[int | None], None]"
$ dmypy inspect foo.py:11:1:13:1
"None"
$ dmypy inspect foo.py:1:2:3:4
Expand Down