Skip to content

Commit 6427ef1

Browse files
authored
Add --strict-bytes flag (#18263)
Closes #18256
1 parent 568648d commit 6427ef1

File tree

5 files changed

+68
-0
lines changed

5 files changed

+68
-0
lines changed

docs/source/command_line.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,35 @@ of the above sections.
659659
660660
assert text is not None # OK, check against None is allowed as a special case.
661661
662+
663+
.. option:: --strict-bytes
664+
665+
By default, mypy treats ``bytearray`` and ``memoryview`` as subtypes of ``bytes`` which
666+
is not true at runtime. Use this flag to disable this behavior. ``--strict-bytes`` will
667+
be enabled by default in *mypy 2.0*.
668+
669+
.. code-block:: python
670+
671+
def f(buf: bytes) -> None:
672+
assert isinstance(buf, bytes) # Raises runtime AssertionError with bytearray/memoryview
673+
with open("binary_file", "wb") as fp:
674+
fp.write(buf)
675+
676+
f(bytearray(b"")) # error: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes"
677+
f(memoryview(b"")) # error: Argument 1 to "f" has incompatible type "memoryview"; expected "bytes"
678+
679+
# If `f` accepts any object that implements the buffer protocol, consider using:
680+
from collections.abc import Buffer # "from typing_extensions" in Python 3.11 and earlier
681+
682+
def f(buf: Buffer) -> None:
683+
with open("binary_file", "wb") as fp:
684+
fp.write(buf)
685+
686+
f(b"") # Ok
687+
f(bytearray(b"")) # Ok
688+
f(memoryview(b"")) # Ok
689+
690+
662691
.. option:: --extra-checks
663692

664693
This flag enables additional checks that are technically correct but may be

docs/source/config_file.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,14 @@ section of the command line docs.
778778
Prohibit equality checks, identity checks, and container checks between
779779
non-overlapping types.
780780

781+
.. confval:: strict_bytes
782+
783+
:type: boolean
784+
:default: False
785+
786+
Disable treating ``bytearray`` and ``memoryview`` as subtypes of ``bytes``.
787+
This will be enabled by default in *mypy 2.0*.
788+
781789
.. confval:: strict
782790

783791
:type: boolean

mypy/main.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -859,6 +859,14 @@ def add_invertible_flag(
859859
group=strictness_group,
860860
)
861861

862+
add_invertible_flag(
863+
"--strict-bytes",
864+
default=False,
865+
strict_flag=False,
866+
help="Disable treating bytearray and memoryview as subtypes of bytes",
867+
group=strictness_group,
868+
)
869+
862870
add_invertible_flag(
863871
"--extra-checks",
864872
default=False,
@@ -1386,6 +1394,11 @@ def set_strict_flags() -> None:
13861394

13871395
process_cache_map(parser, special_opts, options)
13881396

1397+
# Process --strict-bytes
1398+
if options.strict_bytes:
1399+
options.disable_bytearray_promotion = True
1400+
options.disable_memoryview_promotion = True
1401+
13891402
# An explicitly specified cache_fine_grained implies local_partial_types
13901403
# (because otherwise the cache is not compatible with dmypy)
13911404
if options.cache_fine_grained:

mypy/options.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class BuildType:
6767
"plugins",
6868
"disable_bytearray_promotion",
6969
"disable_memoryview_promotion",
70+
"strict_bytes",
7071
}
7172
) - {"debug_cache"}
7273

@@ -215,6 +216,9 @@ def __init__(self) -> None:
215216
# This makes 1 == '1', 1 in ['1'], and 1 is '1' errors.
216217
self.strict_equality = False
217218

219+
# Disable treating bytearray and memoryview as subtypes of bytes
220+
self.strict_bytes = False
221+
218222
# Deprecated, use extra_checks instead.
219223
self.strict_concatenate = False
220224

test-data/unit/check-flags.test

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2393,6 +2393,20 @@ def f(x: bytes, y: bytearray, z: memoryview) -> None:
23932393
x in z
23942394
[builtins fixtures/primitives.pyi]
23952395

2396+
[case testStrictBytes]
2397+
# flags: --strict-bytes
2398+
def f(x: bytes) -> None: ...
2399+
f(bytearray(b"asdf")) # E: Argument 1 to "f" has incompatible type "bytearray"; expected "bytes"
2400+
f(memoryview(b"asdf")) # E: Argument 1 to "f" has incompatible type "memoryview"; expected "bytes"
2401+
[builtins fixtures/primitives.pyi]
2402+
2403+
[case testNoStrictBytes]
2404+
# flags: --no-strict-bytes
2405+
def f(x: bytes) -> None: ...
2406+
f(bytearray(b"asdf"))
2407+
f(memoryview(b"asdf"))
2408+
[builtins fixtures/primitives.pyi]
2409+
23962410
[case testNoCrashFollowImportsForStubs]
23972411
# flags: --config-file tmp/mypy.ini
23982412
{**{"x": "y"}}

0 commit comments

Comments
 (0)