Skip to content

Commit 9ded5b1

Browse files
authored
Deprecated --force-uppercase-builtins flag (#19176)
Use lowercase builtins for error messages, Mypy only supports 3.9+. This PR deprecates the `--force-uppercase-builtins` flag and makes it a no-op. Followup to #19173.
1 parent 9fd55aa commit 9ded5b1

File tree

8 files changed

+36
-81
lines changed

8 files changed

+36
-81
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
## Next Release
44

5+
### Deprecated Flag: \--force-uppercase-builtins
6+
7+
Mypy only supports Python 3.9+. The \--force-uppercase-builtins flag is now deprecated and a no-op. It will be removed in a future version.
8+
9+
Contributed by Marc Mueller (PR [19176](https://github.com/python/mypy/pull/19176))
10+
511
## Mypy 1.16
612

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

docs/source/command_line.rst

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -937,11 +937,6 @@ in error messages.
937937
useful or they may be overly noisy. If ``N`` is negative, there is
938938
no limit. The default limit is -1.
939939

940-
.. option:: --force-uppercase-builtins
941-
942-
Always use ``List`` instead of ``list`` in error messages,
943-
even on Python 3.9+.
944-
945940
.. option:: --force-union-syntax
946941

947942
Always use ``Union[]`` and ``Optional[]`` for union types

docs/source/config_file.rst

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

923923
Show absolute paths to files.
924924

925-
.. confval:: force_uppercase_builtins
926-
927-
:type: boolean
928-
:default: False
929-
930-
Always use ``List`` instead of ``list`` in error messages,
931-
even on Python 3.9+.
932-
933925
.. confval:: force_union_syntax
934926

935927
:type: boolean

mypy/main.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,7 @@ def add_invertible_flag(
801801
help="Disable strict Optional checks (inverse: --strict-optional)",
802802
)
803803

804+
# This flag is deprecated, Mypy only supports Python 3.9+
804805
add_invertible_flag(
805806
"--force-uppercase-builtins", default=False, help=argparse.SUPPRESS, group=none_group
806807
)
@@ -1494,6 +1495,9 @@ def set_strict_flags() -> None:
14941495
if options.strict_concatenate and not strict_option_set:
14951496
print("Warning: --strict-concatenate is deprecated; use --extra-checks instead")
14961497

1498+
if options.force_uppercase_builtins:
1499+
print("Warning: --force-uppercase-builtins is deprecated; mypy only supports Python 3.9+")
1500+
14971501
# Set target.
14981502
if special_opts.modules + special_opts.packages:
14991503
options.build_type = BuildType.MODULE

mypy/messages.py

Lines changed: 8 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1823,13 +1823,10 @@ def need_annotation_for_var(
18231823
recommended_type = f"Optional[{type_dec}]"
18241824
elif node.type.type.fullname in reverse_builtin_aliases:
18251825
# partial types other than partial None
1826-
alias = reverse_builtin_aliases[node.type.type.fullname]
1827-
alias = alias.split(".")[-1]
1828-
if alias == "Dict":
1826+
name = node.type.type.fullname.partition(".")[2]
1827+
if name == "dict":
18291828
type_dec = f"{type_dec}, {type_dec}"
1830-
if self.options.use_lowercase_names():
1831-
alias = alias.lower()
1832-
recommended_type = f"{alias}[{type_dec}]"
1829+
recommended_type = f"{name}[{type_dec}]"
18331830
if recommended_type is not None:
18341831
hint = f' (hint: "{node.name}: {recommended_type} = ...")'
18351832

@@ -2424,8 +2421,7 @@ def format_long_tuple_type(self, typ: TupleType) -> str:
24242421
"""Format very long tuple type using an ellipsis notation"""
24252422
item_cnt = len(typ.items)
24262423
if item_cnt > MAX_TUPLE_ITEMS:
2427-
return "{}[{}, {}, ... <{} more items>]".format(
2428-
"tuple" if self.options.use_lowercase_names() else "Tuple",
2424+
return "tuple[{}, {}, ... <{} more items>]".format(
24292425
format_type_bare(typ.items[0], self.options),
24302426
format_type_bare(typ.items[1], self.options),
24312427
str(item_cnt - 2),
@@ -2610,10 +2606,7 @@ def format_literal_value(typ: LiteralType) -> str:
26102606
if itype.type.fullname == "typing._SpecialForm":
26112607
# This is not a real type but used for some typing-related constructs.
26122608
return "<typing special form>"
2613-
if itype.type.fullname in reverse_builtin_aliases and not options.use_lowercase_names():
2614-
alias = reverse_builtin_aliases[itype.type.fullname]
2615-
base_str = alias.split(".")[-1]
2616-
elif verbosity >= 2 or (fullnames and itype.type.fullname in fullnames):
2609+
if verbosity >= 2 or (fullnames and itype.type.fullname in fullnames):
26172610
base_str = itype.type.fullname
26182611
else:
26192612
base_str = itype.type.name
@@ -2624,7 +2617,7 @@ def format_literal_value(typ: LiteralType) -> str:
26242617
return base_str
26252618
elif itype.type.fullname == "builtins.tuple":
26262619
item_type_str = format(itype.args[0])
2627-
return f"{'tuple' if options.use_lowercase_names() else 'Tuple'}[{item_type_str}, ...]"
2620+
return f"tuple[{item_type_str}, ...]"
26282621
else:
26292622
# There are type arguments. Convert the arguments to strings.
26302623
return f"{base_str}[{format_list(itype.args)}]"
@@ -2660,11 +2653,7 @@ def format_literal_value(typ: LiteralType) -> str:
26602653
if typ.partial_fallback.type.fullname != "builtins.tuple":
26612654
return format(typ.partial_fallback)
26622655
type_items = format_list(typ.items) or "()"
2663-
if options.use_lowercase_names():
2664-
s = f"tuple[{type_items}]"
2665-
else:
2666-
s = f"Tuple[{type_items}]"
2667-
return s
2656+
return f"tuple[{type_items}]"
26682657
elif isinstance(typ, TypedDictType):
26692658
# If the TypedDictType is named, return the name
26702659
if not typ.is_anonymous():
@@ -2736,8 +2725,7 @@ def format_literal_value(typ: LiteralType) -> str:
27362725
elif isinstance(typ, UninhabitedType):
27372726
return "Never"
27382727
elif isinstance(typ, TypeType):
2739-
type_name = "type" if options.use_lowercase_names() else "Type"
2740-
return f"{type_name}[{format(typ.item)}]"
2728+
return f"type[{format(typ.item)}]"
27412729
elif isinstance(typ, FunctionLike):
27422730
func = typ
27432731
if func.is_type_obj():

mypy/options.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import re
55
import sys
66
import sysconfig
7+
import warnings
78
from collections.abc import Mapping
89
from re import Pattern
910
from typing import Any, Callable, Final
@@ -400,6 +401,7 @@ def __init__(self) -> None:
400401

401402
self.disable_bytearray_promotion = False
402403
self.disable_memoryview_promotion = False
404+
# Deprecated, Mypy only supports Python 3.9+
403405
self.force_uppercase_builtins = False
404406
self.force_union_syntax = False
405407

@@ -413,9 +415,12 @@ def __init__(self) -> None:
413415
self.mypyc_skip_c_generation = False
414416

415417
def use_lowercase_names(self) -> bool:
416-
if self.python_version >= (3, 9):
417-
return not self.force_uppercase_builtins
418-
return False
418+
warnings.warn(
419+
"options.use_lowercase_names() is deprecated and will be removed in a future version",
420+
DeprecationWarning,
421+
stacklevel=2,
422+
)
423+
return True
419424

420425
def use_or_syntax(self) -> bool:
421426
if self.python_version >= (3, 10):

mypy/types.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3463,12 +3463,11 @@ def visit_overloaded(self, t: Overloaded, /) -> str:
34633463

34643464
def visit_tuple_type(self, t: TupleType, /) -> str:
34653465
s = self.list_str(t.items) or "()"
3466-
tuple_name = "tuple" if self.options.use_lowercase_names() else "Tuple"
34673466
if t.partial_fallback and t.partial_fallback.type:
34683467
fallback_name = t.partial_fallback.type.fullname
34693468
if fallback_name != "builtins.tuple":
3470-
return f"{tuple_name}[{s}, fallback={t.partial_fallback.accept(self)}]"
3471-
return f"{tuple_name}[{s}]"
3469+
return f"tuple[{s}, fallback={t.partial_fallback.accept(self)}]"
3470+
return f"tuple[{s}]"
34723471

34733472
def visit_typeddict_type(self, t: TypedDictType, /) -> str:
34743473
def item_str(name: str, typ: str) -> str:
@@ -3511,11 +3510,7 @@ def visit_ellipsis_type(self, t: EllipsisType, /) -> str:
35113510
return "..."
35123511

35133512
def visit_type_type(self, t: TypeType, /) -> str:
3514-
if self.options.use_lowercase_names():
3515-
type_name = "type"
3516-
else:
3517-
type_name = "Type"
3518-
return f"{type_name}[{t.item.accept(self)}]"
3513+
return f"type[{t.item.accept(self)}]"
35193514

35203515
def visit_placeholder_type(self, t: PlaceholderType, /) -> str:
35213516
return f"<placeholder {t.fullname}>"

test-data/unit/check-lowercase.test

Lines changed: 7 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,34 @@
1-
2-
[case testTupleLowercaseSettingOff]
3-
# flags: --force-uppercase-builtins
4-
x = (3,)
5-
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "Tuple[int]")
6-
[builtins fixtures/tuple.pyi]
7-
8-
[case testTupleLowercaseSettingOn]
9-
# flags: --no-force-uppercase-builtins
1+
[case testTupleLowercase]
102
x = (3,)
113
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "tuple[int]")
124
[builtins fixtures/tuple.pyi]
135

14-
[case testListLowercaseSettingOff]
15-
# flags: --force-uppercase-builtins
16-
x = [3]
17-
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "List[int]")
18-
19-
[case testListLowercaseSettingOn]
20-
# flags: --no-force-uppercase-builtins
6+
[case testListLowercase]
217
x = [3]
228
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "list[int]")
239

24-
[case testDictLowercaseSettingOff]
25-
# flags: --force-uppercase-builtins
26-
x = {"key": "value"}
27-
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "Dict[str, str]")
28-
29-
[case testDictLowercaseSettingOn]
30-
# flags: --no-force-uppercase-builtins
10+
[case testDictLowercase]
3111
x = {"key": "value"}
3212
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "dict[str, str]")
3313

34-
[case testSetLowercaseSettingOff]
35-
# flags: --force-uppercase-builtins
36-
x = {3}
37-
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "Set[int]")
38-
[builtins fixtures/set.pyi]
39-
40-
[case testSetLowercaseSettingOn]
41-
# flags: --no-force-uppercase-builtins
14+
[case testSetLowercase]
4215
x = {3}
4316
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "set[int]")
4417
[builtins fixtures/set.pyi]
4518

46-
[case testTypeLowercaseSettingOff]
47-
# flags: --no-force-uppercase-builtins
19+
[case testTypeLowercase]
4820
x: type[type]
4921
y: int
5022

5123
y = x # E: Incompatible types in assignment (expression has type "type[type]", variable has type "int")
5224

53-
[case testLowercaseSettingOnTypeAnnotationHint]
54-
# flags: --no-force-uppercase-builtins
25+
[case testLowercaseTypeAnnotationHint]
5526
x = [] # E: Need type annotation for "x" (hint: "x: list[<type>] = ...")
5627
y = {} # E: Need type annotation for "y" (hint: "y: dict[<type>, <type>] = ...")
5728
z = set() # E: Need type annotation for "z" (hint: "z: set[<type>] = ...")
5829
[builtins fixtures/primitives.pyi]
5930

60-
[case testLowercaseSettingOnRevealTypeType]
61-
# flags: --no-force-uppercase-builtins
31+
[case testLowercaseRevealTypeType]
6232
def f(t: type[int]) -> None:
6333
reveal_type(t) # N: Revealed type is "type[builtins.int]"
6434
reveal_type(f) # N: Revealed type is "def (t: type[builtins.int])"

0 commit comments

Comments
 (0)