From 3086342c9cdf2c3a8d6d382b23572c4712f3fe7e Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Mon, 2 Feb 2026 20:44:08 -0800 Subject: [PATCH 1/4] Make `--local-partial-types` the default --- mypy/dmypy_server.py | 2 ++ mypy/main.py | 8 +++++++- mypy/options.py | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mypy/dmypy_server.py b/mypy/dmypy_server.py index 33a174d0f6a1e..0d41521e8f7df 100644 --- a/mypy/dmypy_server.py +++ b/mypy/dmypy_server.py @@ -150,6 +150,8 @@ def process_start_options(flags: list[str], allow_sources: bool) -> Options: sys.exit("dmypy: start/restart should not disable incremental mode") if options.follow_imports not in ("skip", "error", "normal"): sys.exit("dmypy: follow-imports=silent not supported") + if not options.local_partial_types: + sys.exit("dmypy: disabling local-partial-types not supported") return options diff --git a/mypy/main.py b/mypy/main.py index 926e72515d953..c84251cc8e466 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -1258,7 +1258,13 @@ def add_invertible_flag( parser.add_argument("--test-env", action="store_true", help=argparse.SUPPRESS) # --local-partial-types disallows partial types spanning module top level and a function # (implicitly defined in fine-grained incremental mode) - add_invertible_flag("--local-partial-types", default=False, help=argparse.SUPPRESS) + add_invertible_flag( + "--no-local-partial-types", + inverse="--local-partial-types", + default=True, + dest="local_partial_types", + help=argparse.SUPPRESS, + ) # --logical-deps adds some more dependencies that are not semantically needed, but # may be helpful to determine relative importance of classes and functions for overall # type precision in a code base. It also _removes_ some deps, so this flag should be never diff --git a/mypy/options.py b/mypy/options.py index 9bfbc5f68af8d..0fc9ca1382eef 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -370,7 +370,7 @@ def __init__(self) -> None: self.dump_deps = False self.logical_deps = False # If True, partial types can't span a module top level and a function - self.local_partial_types = False + self.local_partial_types = True # Some behaviors are changed when using Bazel (https://bazel.build). self.bazel = False # If True, export inferred types for all expressions as BuildResult.types From dd193a648cdabf15cbc7be2430616a42c56baf5f Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Mon, 2 Feb 2026 20:57:20 -0800 Subject: [PATCH 2/4] okay tests --- test-data/unit/check-custom-plugin.test | 2 +- test-data/unit/check-errorcodes.test | 3 ++- test-data/unit/check-expressions.test | 3 ++- test-data/unit/check-functions.test | 4 ++-- test-data/unit/check-literal.test | 4 ++-- test-data/unit/check-redefine2.test | 2 +- test-data/unit/check-tuples.test | 2 +- 7 files changed, 11 insertions(+), 9 deletions(-) diff --git a/test-data/unit/check-custom-plugin.test b/test-data/unit/check-custom-plugin.test index 7b1a2c2a91d71..dd1de1265b599 100644 --- a/test-data/unit/check-custom-plugin.test +++ b/test-data/unit/check-custom-plugin.test @@ -996,7 +996,7 @@ class M(type): attr = 'test' class B: - attr = None + attr = b'bytes' class Cls(B, metaclass=M): pass diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 8533dbc6c56c4..60bb02ec6ad3c 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -537,7 +537,8 @@ d: D = {'x': 1, 'y': 2} # type: ignore[typeddict-item] y = x # E: Cannot determine type of "x" [has-type] \ # E: Name "x" is used before definition [used-before-def] reveal_type(y) # N: Revealed type is "Any" -x = None +x = None # E: Need type annotation for "x" (hint: "x: | None = ...") [var-annotated] + [case testErrorCodeRedundantCast] # flags: --warn-redundant-casts diff --git a/test-data/unit/check-expressions.test b/test-data/unit/check-expressions.test index 1acda7079cc85..9500858728206 100644 --- a/test-data/unit/check-expressions.test +++ b/test-data/unit/check-expressions.test @@ -1555,7 +1555,8 @@ from typing import List, Union x = [] y = "" x.append(y) if bool() else x.append(y) -z = x.append(y) if bool() else x.append(y) # E: "append" of "list" does not return a value (it only ever returns None) +z = x.append(y) if bool() else x.append(y) # E: Need type annotation for "z" (hint: "z: | None = ...") \ + # E: "append" of "list" does not return a value (it only ever returns None) [builtins fixtures/list.pyi] [case testConditionalExpressionWithUnreachableBranches] diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index ed2948ccddedc..4bddec8ad7747 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -2622,7 +2622,7 @@ reveal_type(bar(None)) # N: Revealed type is "None" [out] [case testNoComplainInferredNone] -# flags: --no-strict-optional +# flags: --no-strict-optional --no-local-partial-types from typing import TypeVar, Optional T = TypeVar('T') def X(val: T) -> T: ... @@ -2635,7 +2635,7 @@ xx: Optional[int] = X(x_in) from typing import TypeVar, Optional T = TypeVar('T') def X(val: T) -> T: ... -x_in = None +x_in = X(None) def Y(x: Optional[str] = X(x_in)): ... xx: Optional[int] = X(x_in) diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index 0b779f57b6150..3f894709e4ae6 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -997,7 +997,7 @@ bool2 = True bool3: bool = True none1: Literal[None] = None -none2 = None +none2 = None # E: Need type annotation for "none2" (hint: "none2: | None = ...") none3: None = None reveal_type(int1) # N: Revealed type is "Literal[1]" @@ -1026,7 +1026,7 @@ combined: Literal[1, "foo", True, None] a = 1 b = "foo" c = True -d = None +d = None # E: Need type annotation for "d" (hint: "d: | None = ...") w = a # E: Incompatible types in assignment (expression has type "int", variable has type "Literal[1]") x = b # E: Incompatible types in assignment (expression has type "str", variable has type "Literal['foo']") diff --git a/test-data/unit/check-redefine2.test b/test-data/unit/check-redefine2.test index 6e9441151c935..e6448cacbdcd9 100644 --- a/test-data/unit/check-redefine2.test +++ b/test-data/unit/check-redefine2.test @@ -1064,7 +1064,7 @@ if int(): x = "" [file b.py] -# mypy: allow-redefinition-new +# mypy: local-partial-types=false, allow-redefinition-new x = 0 if int(): x = "" diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 9633aae0dba0b..1e5d6c49dfa58 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -954,7 +954,7 @@ for x in t: pass # E: Need type annotation for "x" [case testForLoopOverNoneValuedTuple] import typing -for x in None, None: pass +for x in None, None: pass # E: Need type annotation for "x" (hint: "x: | None = ...") [builtins fixtures/for.pyi] [case testForLoopOverTupleAndSubtyping] From 9f89b9e25026fe574b20eda171e903b4f25e0663 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Fri, 20 Mar 2026 21:21:39 -0700 Subject: [PATCH 3/4] tests --- mypyc/test-data/run-classes.test | 2 +- mypyc/test-data/run-tuples.test | 2 +- test-data/unit/check-errorcodes.test | 3 ++- test-data/unit/check-expressions.test | 4 ++-- test-data/unit/check-literal.test | 4 ++-- test-data/unit/check-tuples.test | 2 +- 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/mypyc/test-data/run-classes.test b/mypyc/test-data/run-classes.test index cd3a0bf349b71..cfceef72d4ab2 100644 --- a/mypyc/test-data/run-classes.test +++ b/mypyc/test-data/run-classes.test @@ -4295,7 +4295,7 @@ from __future__ import annotations from mypy_extensions import mypyc_attr -a = [] +a: list[int] = [] @mypyc_attr(free_list_len=1) class Foo: diff --git a/mypyc/test-data/run-tuples.test b/mypyc/test-data/run-tuples.test index e2e8358bb43e2..b410d8e4ba388 100644 --- a/mypyc/test-data/run-tuples.test +++ b/mypyc/test-data/run-tuples.test @@ -339,7 +339,7 @@ def test_final_tuple_not_in() -> None: assert 'x' not in TUP0 -log = [] +log: list[str] = [] def f_a() -> str: log.append('f_a') diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 1a05f01c80996..f1b596179b5ba 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -537,7 +537,8 @@ d: D = {'x': 1, 'y': 2} # type: ignore[typeddict-item] y = x # E: Cannot determine type of "x" [has-type] \ # E: Name "x" is used before definition [used-before-def] reveal_type(y) # N: Revealed type is "Any" -x = None # E: Need type annotation for "x" (hint: "x: | None = ...") [var-annotated] +x = None + [case testErrorCodeRedundantCast] diff --git a/test-data/unit/check-expressions.test b/test-data/unit/check-expressions.test index 9500858728206..82fb253a6d1d0 100644 --- a/test-data/unit/check-expressions.test +++ b/test-data/unit/check-expressions.test @@ -1555,8 +1555,8 @@ from typing import List, Union x = [] y = "" x.append(y) if bool() else x.append(y) -z = x.append(y) if bool() else x.append(y) # E: Need type annotation for "z" (hint: "z: | None = ...") \ - # E: "append" of "list" does not return a value (it only ever returns None) +z = x.append(y) if bool() else x.append(y) # E: "append" of "list" does not return a value (it only ever returns None) + [builtins fixtures/list.pyi] [case testConditionalExpressionWithUnreachableBranches] diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test index 3f894709e4ae6..0b779f57b6150 100644 --- a/test-data/unit/check-literal.test +++ b/test-data/unit/check-literal.test @@ -997,7 +997,7 @@ bool2 = True bool3: bool = True none1: Literal[None] = None -none2 = None # E: Need type annotation for "none2" (hint: "none2: | None = ...") +none2 = None none3: None = None reveal_type(int1) # N: Revealed type is "Literal[1]" @@ -1026,7 +1026,7 @@ combined: Literal[1, "foo", True, None] a = 1 b = "foo" c = True -d = None # E: Need type annotation for "d" (hint: "d: | None = ...") +d = None w = a # E: Incompatible types in assignment (expression has type "int", variable has type "Literal[1]") x = b # E: Incompatible types in assignment (expression has type "str", variable has type "Literal['foo']") diff --git a/test-data/unit/check-tuples.test b/test-data/unit/check-tuples.test index 739b8da457b30..9653d9d037ce6 100644 --- a/test-data/unit/check-tuples.test +++ b/test-data/unit/check-tuples.test @@ -954,7 +954,7 @@ for x in t: pass # E: Need type annotation for "x" [case testForLoopOverNoneValuedTuple] import typing -for x in None, None: pass # E: Need type annotation for "x" (hint: "x: | None = ...") +for x in None, None: pass [builtins fixtures/for.pyi] [case testForLoopOverTupleAndSubtyping] From b287b626394cb7caaf5345da5c36f256f54c8cd8 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Fri, 20 Mar 2026 21:22:34 -0700 Subject: [PATCH 4/4] newline --- test-data/unit/check-errorcodes.test | 2 -- test-data/unit/check-expressions.test | 1 - 2 files changed, 3 deletions(-) diff --git a/test-data/unit/check-errorcodes.test b/test-data/unit/check-errorcodes.test index 3609017789eb3..f02daea40fd12 100644 --- a/test-data/unit/check-errorcodes.test +++ b/test-data/unit/check-errorcodes.test @@ -539,8 +539,6 @@ y = x # E: Cannot determine type of "x" [has-type] \ reveal_type(y) # N: Revealed type is "Any" x = None - - [case testErrorCodeRedundantCast] # flags: --warn-redundant-casts from typing import cast diff --git a/test-data/unit/check-expressions.test b/test-data/unit/check-expressions.test index 1423acb163ef1..17ce4cd596590 100644 --- a/test-data/unit/check-expressions.test +++ b/test-data/unit/check-expressions.test @@ -1556,7 +1556,6 @@ x = [] y = "" x.append(y) if bool() else x.append(y) z = x.append(y) if bool() else x.append(y) # E: "append" of "list" does not return a value (it only ever returns None) - [builtins fixtures/list.pyi] [case testConditionalExpressionWithUnreachableBranches]