From c39f0265dbad7658d9d1c9407db7cbe93b19d68b Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 29 Dec 2024 19:04:50 -0800 Subject: [PATCH 1/5] Enable strict_bytes by default --- mypy/main.py | 6 +++--- mypy/options.py | 6 +++--- mypy/test/testargs.py | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/mypy/main.py b/mypy/main.py index 9873907ddf03a..241a37dc2cc0d 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -870,9 +870,9 @@ def add_invertible_flag( ) add_invertible_flag( - "--strict-bytes", - default=False, - strict_flag=False, + "--no-strict-bytes", + default=True, + dest="strict_bytes", help="Disable treating bytearray and memoryview as subtypes of bytes", group=strictness_group, ) diff --git a/mypy/options.py b/mypy/options.py index eb3d389b5d8a5..10a24bb433212 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -217,7 +217,7 @@ def __init__(self) -> None: self.strict_equality = False # Disable treating bytearray and memoryview as subtypes of bytes - self.strict_bytes = False + self.strict_bytes = True # Deprecated, use extra_checks instead. self.strict_concatenate = False @@ -386,8 +386,8 @@ def __init__(self) -> None: # (undocumented feature). self.export_ref_info = False - self.disable_bytearray_promotion = False - self.disable_memoryview_promotion = False + self.disable_bytearray_promotion = True + self.disable_memoryview_promotion = True self.force_uppercase_builtins = False self.force_union_syntax = False diff --git a/mypy/test/testargs.py b/mypy/test/testargs.py index 7c139902fe902..b86769246f263 100644 --- a/mypy/test/testargs.py +++ b/mypy/test/testargs.py @@ -12,7 +12,7 @@ from mypy.main import infer_python_executable, process_options from mypy.options import Options -from mypy.test.helpers import Suite, assert_equal +from mypy.test.helpers import Suite class ArgSuite(Suite): @@ -21,7 +21,7 @@ def test_coherence(self) -> None: _, parsed_options = process_options([], require_targets=False) # FIX: test this too. Requires changing working dir to avoid finding 'setup.cfg' options.config_file = parsed_options.config_file - assert_equal(options.snapshot(), parsed_options.snapshot()) + assert options.snapshot() == parsed_options.snapshot() def test_executable_inference(self) -> None: """Test the --python-executable flag with --python-version""" From b6528b56e65a96d95c5149828c6690d0e514455c Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Sun, 29 Dec 2024 21:29:43 -0800 Subject: [PATCH 2/5] patch --- mypy/main.py | 6 +++--- mypyc/test-data/fixtures/ir.py | 8 ++++++-- mypyc/test-data/run-bytes.test | 20 ++++++++++---------- test-data/unit/check-flags.test | 19 +++---------------- test-data/unit/check-type-promotion.test | 2 ++ 5 files changed, 24 insertions(+), 31 deletions(-) diff --git a/mypy/main.py b/mypy/main.py index 241a37dc2cc0d..62718feccb3b2 100644 --- a/mypy/main.py +++ b/mypy/main.py @@ -1405,9 +1405,9 @@ def set_strict_flags() -> None: process_cache_map(parser, special_opts, options) # Process --strict-bytes - if options.strict_bytes: - options.disable_bytearray_promotion = True - options.disable_memoryview_promotion = True + if not options.strict_bytes: + options.disable_bytearray_promotion = False + options.disable_memoryview_promotion = False # An explicitly specified cache_fine_grained implies local_partial_types # (because otherwise the cache is not compatible with dmypy) diff --git a/mypyc/test-data/fixtures/ir.py b/mypyc/test-data/fixtures/ir.py index be66307286fc2..d1b5cc9c01438 100644 --- a/mypyc/test-data/fixtures/ir.py +++ b/mypyc/test-data/fixtures/ir.py @@ -149,7 +149,7 @@ class bytes: def __init__(self) -> None: ... @overload def __init__(self, x: object) -> None: ... - def __add__(self, x: bytes) -> bytes: ... + def __add__(self, x: bytes | bytearray) -> bytes: ... def __mul__(self, x: int) -> bytes: ... def __rmul__(self, x: int) -> bytes: ... def __eq__(self, x: object) -> bool: ... @@ -168,10 +168,14 @@ def __init__(self) -> None: pass def __init__(self, x: object) -> None: pass @overload def __init__(self, string: str, encoding: str, err: str = ...) -> None: pass - def __add__(self, s: bytes) -> bytearray: ... + def __add__(self, s: bytes | bytearray) -> bytearray: ... def __setitem__(self, i: int, o: int) -> None: ... + @overload def __getitem__(self, i: int) -> int: ... + @overload + def __getitem__(self, i: slice) -> bytes: ... def decode(self, x: str = ..., y: str = ...) -> str: ... + def join(self, x: Iterable[object]) -> bytes: ... class bool(int): def __init__(self, o: object = ...) -> None: ... diff --git a/mypyc/test-data/run-bytes.test b/mypyc/test-data/run-bytes.test index fa63c46a67983..323f6778970a6 100644 --- a/mypyc/test-data/run-bytes.test +++ b/mypyc/test-data/run-bytes.test @@ -79,8 +79,8 @@ def test_concat() -> None: assert type(b1) == bytes assert type(b2) == bytes assert type(b3) == bytes - brr1: bytes = bytearray(3) - brr2: bytes = bytearray(range(5)) + brr1: bytes | bytearray = bytearray(3) + brr2: bytes | bytearray = bytearray(range(5)) b4 = b1 + brr1 assert b4 == b'123\x00\x00\x00' assert type(brr1) == bytearray @@ -171,23 +171,23 @@ def test_bytes_slicing() -> None: from typing import Any def test_basics() -> None: - brr1: bytes = bytearray(3) + brr1: bytes | bytearray = bytearray(3) assert brr1 == bytearray(b'\x00\x00\x00') assert brr1 == b'\x00\x00\x00' l = [10, 20, 30, 40] - brr2: bytes = bytearray(l) + brr2: bytes | bytearray = bytearray(l) assert brr2 == bytearray(b'\n\x14\x1e(') assert brr2 == b'\n\x14\x1e(' - brr3: bytes = bytearray(range(5)) + brr3: bytes | bytearray = bytearray(range(5)) assert brr3 == bytearray(b'\x00\x01\x02\x03\x04') assert brr3 == b'\x00\x01\x02\x03\x04' - brr4: bytes = bytearray('string', 'utf-8') + brr4: bytes | bytearray = bytearray('string', 'utf-8') assert brr4 == bytearray(b'string') assert brr4 == b'string' assert len(brr1) == 3 assert len(brr2) == 4 -def f(b: bytes) -> bool: +def f(b: bytes | bytearray) -> bool: return True def test_bytearray_passed_into_bytes() -> None: @@ -197,7 +197,7 @@ def test_bytearray_passed_into_bytes() -> None: [case testBytearraySlicing] def test_bytearray_slicing() -> None: - b: bytes = bytearray(b'abcdefg') + b: bytes | bytearray = bytearray(b'abcdefg') zero = int() ten = 10 + zero two = 2 + zero @@ -231,7 +231,7 @@ def test_bytearray_slicing() -> None: from testutil import assertRaises def test_bytearray_indexing() -> None: - b: bytes = bytearray(b'\xae\x80\xfe\x15') + b: bytes | bytearray = bytearray(b'\xae\x80\xfe\x15') assert b[0] == 174 assert b[1] == 128 assert b[2] == 254 @@ -260,7 +260,7 @@ def test_bytes_join() -> None: assert b' '.join([b'a', b'b']) == b'a b' assert b' '.join([]) == b'' - x: bytes = bytearray(b' ') + x: bytes | bytearray = bytearray(b' ') assert x.join([b'a', b'b']) == b'a b' assert type(x.join([b'a', b'b'])) == bytearray diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 86a65d85a8b28..b136d488c281e 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2348,7 +2348,7 @@ x: int = "" # E: Incompatible types in assignment (expression has type "str", v # flags: --disable-bytearray-promotion --strict-equality def f(x: bytes) -> None: ... f(bytearray(b"asdf")) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" -f(memoryview(b"asdf")) + ba = bytearray(b"") if ba == b"": f(ba) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" @@ -2363,25 +2363,12 @@ if bytes() == ba: [case testDisableMemoryviewPromotion] # flags: --disable-memoryview-promotion def f(x: bytes) -> None: ... -f(bytearray(b"asdf")) + f(memoryview(b"asdf")) # E: Argument 1 to "f" has incompatible type "memoryview"; expected "bytes" [builtins fixtures/primitives.pyi] [case testDisableBytearrayMemoryviewPromotionStrictEquality] -# flags: --disable-bytearray-promotion --disable-memoryview-promotion --strict-equality -def f(x: bytes, y: bytearray, z: memoryview) -> None: - x == y - y == z - x == z - 97 in x - 97 in y - 97 in z - x in y - x in z -[builtins fixtures/primitives.pyi] - -[case testEnableBytearrayMemoryviewPromotionStrictEquality] -# flags: --strict-equality +# flags: --strict-equality --strict-bytes def f(x: bytes, y: bytearray, z: memoryview) -> None: x == y y == z diff --git a/test-data/unit/check-type-promotion.test b/test-data/unit/check-type-promotion.test index 1b69174a45454..59b3bff42bd78 100644 --- a/test-data/unit/check-type-promotion.test +++ b/test-data/unit/check-type-promotion.test @@ -22,11 +22,13 @@ f(1) [builtins fixtures/primitives.pyi] [case testPromoteBytearrayToByte] +# flags: --no-strict-bytes def f(x: bytes) -> None: pass f(bytearray(b'')) [builtins fixtures/primitives.pyi] [case testPromoteMemoryviewToBytes] +# flags: --no-strict-bytes def f(x: bytes) -> None: pass f(memoryview(b'')) [builtins fixtures/primitives.pyi] From 04187b7f2bde0504e5b715be36a2e2db4cc23117 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Sun, 1 Feb 2026 20:32:50 -0800 Subject: [PATCH 3/5] fix merge --- mypy/options.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/mypy/options.py b/mypy/options.py index 430c9c9953875..e5d93abd3e25b 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -409,8 +409,6 @@ def __init__(self) -> None: self.disable_bytearray_promotion = True self.disable_memoryview_promotion = True - self.force_uppercase_builtins = False - self.force_union_syntax = False # Sets custom output format self.output: str | None = None From cd0d27cbf008b996fb3d4b06145d13c5232c4e33 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Sun, 1 Feb 2026 20:35:17 -0800 Subject: [PATCH 4/5] add back --- test-data/unit/check-flags.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 94e775a94dde8..68f72b2410765 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2546,7 +2546,7 @@ x: int = "" # E: Incompatible types in assignment (expression has type "str", v # flags: --disable-bytearray-promotion --strict-equality --warn-unreachable def f(x: bytes) -> None: ... f(bytearray(b"asdf")) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" - +f(memoryview(b"asdf")) ba = bytearray(b"") if ba == b"": f(ba) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" @@ -2561,7 +2561,7 @@ if bytes() == ba: [case testDisableMemoryviewPromotion] # flags: --disable-memoryview-promotion def f(x: bytes) -> None: ... - +f(bytearray(b"asdf")) f(memoryview(b"asdf")) # E: Argument 1 to "f" has incompatible type "memoryview"; expected "bytes" [builtins fixtures/primitives.pyi] From 2587d649c3f2cffe185333a7168a2a225c9be880 Mon Sep 17 00:00:00 2001 From: Shantanu Jain Date: Sun, 1 Feb 2026 20:59:11 -0800 Subject: [PATCH 5/5] fix up more --- mypy/options.py | 6 +-- mypyc/test-data/run-bytes.test | 2 +- test-data/unit/check-flags.test | 53 ---------------------- test-data/unit/check-type-promotion.test | 58 ++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 57 deletions(-) diff --git a/mypy/options.py b/mypy/options.py index e5d93abd3e25b..4af07d6cb0491 100644 --- a/mypy/options.py +++ b/mypy/options.py @@ -471,9 +471,9 @@ def process_strict_bytes(self) -> None: # backwards compatibility self.disable_bytearray_promotion = True self.disable_memoryview_promotion = True - elif self.disable_bytearray_promotion and self.disable_memoryview_promotion: - # forwards compatibility - self.strict_bytes = True + else: + self.disable_bytearray_promotion = False + self.disable_memoryview_promotion = False def apply_changes(self, changes: dict[str, object]) -> Options: # Note: effects of this method *must* be idempotent. diff --git a/mypyc/test-data/run-bytes.test b/mypyc/test-data/run-bytes.test index ab3008486f040..f40321a85ae2d 100644 --- a/mypyc/test-data/run-bytes.test +++ b/mypyc/test-data/run-bytes.test @@ -305,7 +305,7 @@ def test_bytearray_type_object() -> None: b = bytearray() assert type(b) is bytearray -def fb(b: bytes | bytearray) -> str: +def fb(b: bytes) -> str: return "xy" def test_bytearray_passed_into_bytes() -> None: diff --git a/test-data/unit/check-flags.test b/test-data/unit/check-flags.test index 68f72b2410765..764bb0bc275b8 100644 --- a/test-data/unit/check-flags.test +++ b/test-data/unit/check-flags.test @@ -2542,42 +2542,6 @@ x: int = "" # E: Incompatible types in assignment (expression has type "str", v # flags: --hide-error-codes x: int = "" # E: Incompatible types in assignment (expression has type "str", variable has type "int") -[case testDisableBytearrayPromotion] -# flags: --disable-bytearray-promotion --strict-equality --warn-unreachable -def f(x: bytes) -> None: ... -f(bytearray(b"asdf")) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" -f(memoryview(b"asdf")) -ba = bytearray(b"") -if ba == b"": - f(ba) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" -if b"" == ba: - f(ba) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" -if ba == bytes(): - f(ba) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" -if bytes() == ba: - f(ba) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" -[builtins fixtures/primitives.pyi] - -[case testDisableMemoryviewPromotion] -# flags: --disable-memoryview-promotion -def f(x: bytes) -> None: ... -f(bytearray(b"asdf")) -f(memoryview(b"asdf")) # E: Argument 1 to "f" has incompatible type "memoryview"; expected "bytes" -[builtins fixtures/primitives.pyi] - -[case testDisableBytearrayMemoryviewPromotionStrictEquality] -# flags: --strict-equality --strict-bytes -def f(x: bytes, y: bytearray, z: memoryview) -> None: - x == y - y == z - x == z - 97 in x - 97 in y - 97 in z - x in y - x in z -[builtins fixtures/primitives.pyi] - [case testStrictBytes] # flags: --strict-bytes def f(x: bytes) -> None: ... @@ -2592,23 +2556,6 @@ f(bytearray(b"asdf")) f(memoryview(b"asdf")) [builtins fixtures/primitives.pyi] -[case testStrictBytesDisabledByDefault] -# TODO: probably change this default in Mypy v2.0, with https://github.com/python/mypy/pull/18371 -# (this would also obsolete the testStrictBytesEnabledByStrict test, below) -def f(x: bytes) -> None: ... -f(bytearray(b"asdf")) -f(memoryview(b"asdf")) -[builtins fixtures/primitives.pyi] - -[case testStrictBytesEnabledByStrict] -# flags: --strict --disable-error-code type-arg -# The type-arg thing is just work around the primitives.pyi isinstance Tuple not having type parameters, -# which isn't important for this. -def f(x: bytes) -> None: ... -f(bytearray(b"asdf")) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" -f(memoryview(b"asdf")) # E: Argument 1 to "f" has incompatible type "memoryview"; expected "bytes" -[builtins fixtures/primitives.pyi] - [case testNoCrashFollowImportsForStubs] # flags: --config-file tmp/mypy.ini {**{"x": "y"}} diff --git a/test-data/unit/check-type-promotion.test b/test-data/unit/check-type-promotion.test index 72ff541c36c8a..2dbfe253c2ea0 100644 --- a/test-data/unit/check-type-promotion.test +++ b/test-data/unit/check-type-promotion.test @@ -33,6 +33,64 @@ def f(x: bytes) -> None: pass f(memoryview(b'')) [builtins fixtures/primitives.pyi] +[case testDisableBytearrayMemoryviewPromotion] +# flags: --strict-bytes --strict-equality --warn-unreachable +def f(x: bytes) -> None: ... +f(bytearray(b"asdf")) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" +f(memoryview(b"asdf")) # E: Argument 1 to "f" has incompatible type "memoryview"; expected "bytes" +ba = bytearray(b"") +if ba == b"": + f(ba) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" +if b"" == ba: + f(ba) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" +if ba == bytes(): + f(ba) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" +if bytes() == ba: + f(ba) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes" +[builtins fixtures/primitives.pyi] + +[case testEnableBytearrayMemoryviewPromotion] +# flags: --no-strict-bytes --strict-equality --warn-unreachable +def f(x: bytes) -> None: ... +f(bytearray(b"asdf")) +f(memoryview(b"asdf")) +ba = bytearray(b"") +if ba == b"": + f(ba) +if b"" == ba: + f(ba) +if ba == bytes(): + f(ba) +if bytes() == ba: + f(ba) +[builtins fixtures/primitives.pyi] + +[case testDisableBytearrayMemoryviewPromotionStrictEquality] +# flags: --strict-equality --strict-bytes +def f(x: bytes, y: bytearray, z: memoryview) -> None: + x == y + y == z + x == z + 97 in x + 97 in y + 97 in z + x in y + x in z +[builtins fixtures/primitives.pyi] + +[case testEnableBytearrayMemoryviewPromotionStrictEquality] +# flags: --strict-equality --no-strict-bytes +def f(x: bytes, y: bytearray, z: memoryview) -> None: + x == y + y == z + x == z + 97 in x + 97 in y + 97 in z + x in y + x in z +[builtins fixtures/primitives.pyi] + [case testNarrowingDownFromPromoteTargetType] y = 0.0 y = 1