Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

## 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.

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

## Mypy 1.16

We’ve just uploaded mypy 1.16 to the Python Package Index ([PyPI](https://pypi.org/project/mypy/)).
Expand Down
5 changes: 0 additions & 5 deletions docs/source/command_line.rst
Original file line number Diff line number Diff line change
Expand Up @@ -936,11 +936,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-uppercase-builtins

Always use ``List`` instead of ``list`` in error messages,
even on Python 3.9+.

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

Always use ``Union[]`` and ``Optional[]`` for union types
Expand Down
8 changes: 0 additions & 8 deletions docs/source/config_file.rst
Original file line number Diff line number Diff line change
Expand Up @@ -922,14 +922,6 @@ These options may only be set in the global section (``[mypy]``).

Show absolute paths to files.

.. confval:: force_uppercase_builtins

:type: boolean
:default: False

Always use ``List`` instead of ``list`` in error messages,
even on Python 3.9+.

.. confval:: force_union_syntax

:type: boolean
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
11 changes: 8 additions & 3 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,9 +415,12 @@ def __init__(self) -> None:
self.mypyc_skip_c_generation = False

def use_lowercase_names(self) -> bool:
if self.python_version >= (3, 9):
return not self.force_uppercase_builtins
return False
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.

return True

def use_or_syntax(self) -> bool:
if self.python_version >= (3, 10):
Expand Down
11 changes: 3 additions & 8 deletions 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