diff --git a/CHANGELOG.md b/CHANGELOG.md index 01d58ce6a1b3..b09916919d8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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/)). diff --git a/docs/source/command_line.rst b/docs/source/command_line.rst index dfed280d12ed..aa19420558ec 100644 --- a/docs/source/command_line.rst +++ b/docs/source/command_line.rst @@ -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 diff --git a/docs/source/config_file.rst b/docs/source/config_file.rst index 9f23617b9481..b4f134f26cb1 100644 --- a/docs/source/config_file.rst +++ b/docs/source/config_file.rst @@ -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 diff --git a/mypy/main.py b/mypy/main.py index 6ebf32ded6e1..16e9e035bf2e 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -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 ) @@ -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 diff --git a/mypy/messages.py b/mypy/messages.py index 2e07d7f63498..567f29261f8d 100644 --- a/mypy/messages.py +++ b/mypy/messages.py @@ -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} = ...")' @@ -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), @@ -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 "" - 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 @@ -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)}]" @@ -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(): @@ -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(): diff --git a/mypy/options.py b/mypy/options.py index 52afd27211ed..4a89ef529c07 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -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 @@ -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 @@ -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, + ) + return True def use_or_syntax(self) -> bool: if self.python_version >= (3, 10): diff --git a/mypy/types.py b/mypy/types.py index 41a958ae93cc..c37e44b183bf 100644 --- a/mypy/types.py +++ b/mypy/types.py @@ -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: @@ -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"" diff --git a/test-data/unit/check-lowercase.test b/test-data/unit/check-lowercase.test index 51a833614a33..d19500327255 100644 --- a/test-data/unit/check-lowercase.test +++ b/test-data/unit/check-lowercase.test @@ -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[] = ...") y = {} # E: Need type annotation for "y" (hint: "y: dict[, ] = ...") z = set() # E: Need type annotation for "z" (hint: "z: set[] = ...") [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])"