8000 Deprecated --force-uppercase-builtins flag by cdce8p · Pull Request #19176 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Deprecated --force-uppercase-builtins flag #19176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jun 5, 2025
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-uppercase-builtins flag
  • Loading branch information
cdce8p committed May 30, 2025
commit 98d59a280628bccc4320f12e71aea7e083be5e22
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Next Release

### Deprecated Flag: \--force-uppercase-builtins

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.

## Mypy 1.16

We’ve just uploaded mypy 1.16 to the Python Package Index ([PyPI](https://pypi.org/project/mypy/)).
Expand Down
4 changes: 4 additions & 0 deletions mypy/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,7 @@ def add_invertible_flag(
help="Disable strict Optional checks (inverse: --strict-optional)",
)

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

if options.force_uppercase_builtins:
print("Warning: --force-uppercase-builtins is deprecated; Mypy only supports Python 3.9+.")

# Set target.
if special_opts.modules + special_opts.packages:
options.build_type = BuildType.MODULE
Expand Down
28 changes: 8 additions & 20 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -1823,13 +1823,10 @@ def need_annotation_for_var(
recommended_type = f"Optional[{type_dec}]"
elif node.type.type.fullname in reverse_builtin_aliases:
# partial types other than partial None
alias = reverse_builtin_aliases[node.type.type.fullname]
alias = alias.split(".")[-1]
if alias == "Dict":
name = node.type.type.fullname.partition(".")[2]
if name == "dict":
type_dec = f"{type_dec}, {type_dec}"
if self.options.use_lowercase_names():
alias = alias.lower()
recommended_type = f"{alias}[{type_dec}]"
recommended_type = f"{name}[{type_dec}]"
if recommended_type is not None:
hint = f' (hint: "{node.name}: {recommended_type} = ...")'

Expand Down Expand Up @@ -2419,8 +2416,7 @@ def format_long_tuple_type(self, typ: TupleType) -> str:
"""Format very long tuple type using an ellipsis notation"""
item_cnt = len(typ.items)
if item_cnt > MAX_TUPLE_ITEMS:
return "{}[{}, {}, ... <{} more items>]".format(
"tuple" if self.options.use_lowercase_names() else "Tuple",
return "tuple[{}, {}, ... <{} more items>]".format(
format_type_bare(typ.items[0], self.options),
format_type_bare(typ.items[1], self.options),
str(item_cnt - 2),
Expand Down Expand Up @@ -2595,10 +2591,7 @@ def format_literal_value(typ: LiteralType) -> str:
if itype.type.fullname == "typing._SpecialForm":
# This is not a real type but used for some typing-related constructs.
return "<typing special form>"
if itype.type.fullname in reverse_builtin_aliases and not options.use_lowercase_names():
alias = reverse_builtin_aliases[itype.type.fullname]
base_str = alias.split(".")[-1]
elif verbosity >= 2 or (fullnames and itype.type.fullname in fullnames):
if verbosity >= 2 or (fullnames and itype.type.fullname in fullnames):
base_str = itype.type.fullname
else:
base_str = itype.type.name
Expand All @@ -2609,7 +2602,7 @@ def format_literal_value(typ: LiteralType) -> str:
return base_str
elif itype.type.fullname == "builtins.tuple":
item_type_str = format(itype.args[0])
return f"{'tuple' if options.use_lowercase_names() else 'Tuple'}[{item_type_str}, ...]"
return f"tuple[{item_type_str}, ...]"
else:
# There are type arguments. Convert the arguments to strings.
return f"{base_str}[{format_list(itype.args)}]"
Expand Down Expand Up @@ -2645,11 +2638,7 @@ def format_literal_value(typ: LiteralType) -> str:
if typ.partial_fallback.type.fullname != "builtins.tuple":
return format(typ.partial_fallback)
type_items = format_list(typ.items) or "()"
if options.use_lowercase_names():
s = f"tuple[{type_items}]"
else:
s = f"Tuple[{type_items}]"
return s
return f"tuple[{type_items}]"
elif isinstance(typ, TypedDictType):
# If the TypedDictType is named, return the name
if not typ.is_anonymous():
Expand Down Expand Up @@ -2721,8 +2710,7 @@ def format_literal_value(typ: LiteralType) -> str:
elif isinstance(typ, UninhabitedType):
return "Never"
elif isinstance(typ, TypeType):
type_name = "type" if options.use_lowercase_names() else "Type"
return f"{type_name}[{format(typ.item)}]"
return f"type[{format(typ.item)}]"
elif isinstance(typ, FunctionLike):
func = typ
if func.is_type_obj():
Expand Down
7 changes: 7 additions & 0 deletions mypy/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import re
import sys
import sysconfig
import warnings
from collections.abc import Mapping
from re import Pattern
from typing import Any, Callable, Final
Expand Down Expand Up @@ -400,6 +401,7 @@ def __init__(self) -> None:

self.disable_bytearray_promotion = False
self.disable_memoryview_promotion = False
# Deprecated, Mypy only supports Python 3.9+
self.force_uppercase_builtins = False
self.force_union_syntax = False

Expand All @@ -413,6 +415,11 @@ def __init__(self) -> None:
self.mypyc_skip_c_generation = False

def use_lowercase_names(self) -> bool:
warnings.warn(
"options.use_lowercase_names is deprecated and will be removed in a future version",
DeprecationWarning,
stacklevel=2,
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm we don't use the warnings module much since mypy is usually used on the command line. This seems a bit inconsistent with existing behavior, so maybe this should reverted. What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about it. I've removed all calls to this method from the mypy codebase itself. So we could even think about just removing it completely. My intention with the DeprecationWarning was to help plugin developers which might be using it. Then again, I don't know if any plugins actually use it.

if self.python_version >= (3, 9):
return not self.force_uppercase_builtins
return False
Expand Down
11 changes: 3 additions & 8 deletions 11 mypy/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -3455,12 +3455,11 @@ def visit_overloaded(self, t: Overloaded, /) -> str:

def visit_tuple_type(self, t: TupleType, /) -> str:
s = self.list_str(t.items) or "()"
tuple_name = "tuple" if self.options.use_lowercase_names() else "Tuple"
if t.partial_fallback and t.partial_fallback.type:
fallback_name = t.partial_fallback.type.fullname
if fallback_name != "builtins.tuple":
return f"{tuple_name}[{s}, fallback={t.partial_fallback.accept(self)}]"
return f"{tuple_name}[{s}]"
return f"tuple[{s}, fallback={t.partial_fallback.accept(self)}]"
return f"tuple[{s}]"

def visit_typeddict_type(self, t: TypedDictType, /) -> str:
def item_str(name: str, typ: str) -> str:
Expand Down Expand Up @@ -3502,11 +3501,7 @@ def visit_ellipsis_type(self, t: EllipsisType, /) -> str:
return "..."

def visit_type_type(self, t: TypeType, /) -> str:
if self.options.use_lowercase_names():
type_name = "type"
else:
type_name = "Type"
return f"{type_name}[{t.item.accept(self)}]"
return f"type[{t.item.accept(self)}]"

def visit_placeholder_type(self, t: PlaceholderType, /) -> str:
return f"<placeholder {t.fullname}>"
Expand Down
44 changes: 7 additions & 37 deletions test-data/unit/check-lowercase.test
Original file line number Diff line number Diff line change
@@ -1,64 +1,34 @@

[case testTupleLowercaseSettingOff]
# flags: --force-uppercase-builtins
x = (3,)
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "Tuple[int]")
[builtins fixtures/tuple.pyi]

[case testTupleLowercaseSettingOn]
# flags: --no-force-uppercase-builtins
[case testTupleLowercase]
x = (3,)
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "tuple[int]")
[builtins fixtures/tuple.pyi]

[case testListLowercaseSettingOff]
# flags: --force-uppercase-builtins
x = [3]
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "List[int]")

[case testListLowercaseSettingOn]
# flags: --no-force-uppercase-builtins
[case testListLowercase]
x = [3]
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "list[int]")

[case testDictLowercaseSettingOff]
# flags: --force-uppercase-builtins
x = {"key": "value"}
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "Dict[str, str]")

[case testDictLowercaseSettingOn]
# flags: --no-force-uppercase-builtins
[case testDictLowercase]
x = {"key": "value"}
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "dict[str, str]")

[case testSetLowercaseSettingOff]
# flags: --force-uppercase-builtins
x = {3}
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "Set[int]")
[builtins fixtures/set.pyi]

[case testSetLowercaseSettingOn]
# flags: --no-force-uppercase-builtins
[case testSetLowercase]
x = {3}
x = 3 # E: Incompatible types in assignment (expression has type "int", variable has type "set[int]")
[builtins fixtures/set.pyi]

[case testTypeLowercaseSettingOff]
# flags: --no-force-uppercase-builtins
[case testTypeLowercase]
x: type[type]
y: int

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

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

[case testLowercaseSettingOnRevealTypeType]
# flags: --no-force-uppercase-builtins
[case testLowercaseRevealTypeType]
def f(t: type[int]) -> None:
reveal_type(t) # N: Revealed type is "type[builtins.int]"
reveal_type(f) # N: Revealed type is "def (t: type[builtins.int])"
Expand Down
0