Skip to content

Incorrect str-format error for bytes interpolation when __bytes__ method exists #19724

@SteveJones

Description

@SteveJones

When the % operator is used to format a bytes string with a placeholder of %b (bytes) and an argument of type bytearray the interpolation will succeed as bytearray has a __bytes__ method as per PEP 0461. The same is also true of memoryview objects as well as any type with a __bytes__ method.

MyPy will not flag an error for bytearray or memoryview objects but will for classes with a __bytes__ method. If --disable-bytearray-promotion or --disable-memoryview-promotion are used then these string interpolations will be flagged as a str-format error - presumably is it stops silently treating these classes as equivalent to bytes.

PEP 0461 states that %b should be correct for any class with a __bytes__ method.

%b will insert a series of bytes. These bytes are collected in one of two ways:

  • input type supports Py_buffer [4]? use it to collect the necessary bytes
  • input type is something else? use its bytes method [5] ; if there isn’t one, raise a TypeError

To Reproduce

MyPy reports no errors with this code by default.

a = b"foo"
b = bytearray(a)
c = memoryview(a)

x = b"%b" % a
y = b"%b" % b
z = b"%b" % c

With --disable-bytearray-promotion it reports

/tmp/test.py:6: error: Incompatible types in string interpolation (expression has type "bytearray", placeholder has type "bytes") [str-format]

Similarly

class X:
    def __bytes__(self) -> bytes:
        return b"X"


m = b"%b" % X()

Will produce the error

/tmp/test.py:6: error: Incompatible types in string interpolation (expression has type "X", placeholder has type "bytes") [str-format]

Both of these samples run without error and with the expected behaviour.

Expected Behavior

No str-format error reported for interpolating %b placeholder in bytes string for objects with a __bytes__ method.

Your Environment

  • Mypy version used: 1.17.1
  • Mypy command-line flags: Defaults or --disable-bytearrary-promotion or --disable-memoryview-promotion
  • Mypy configuration options from mypy.ini (and other config files):
  • Python version used: 3.13.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugmypy got something wrongtopic-runtime-semanticsmypy doesn't model runtime semantics correctly

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions