microsoft / pyright

Static Type Checker for Python
Other
13.12k stars 1.4k forks source link

`bytes | str` incorrectly interpreted as `bytes | bytearray | memoryview[_I@memoryview] | str` #8834

Closed pavel-wmt closed 2 weeks ago

pavel-wmt commented 2 weeks ago

Describe the bug bytes | str incorrectly interpreted as bytes | bytearray | memoryview[_I@memoryview] | str

Code or Screenshots This should type check

def fn(arg: bytes | str) -> str:
    if isinstance(arg, bytes):
        return arg.decode()
    return arg

But it produces error:

/home/pavelaslanov/bytes-or-str-error.py
  /home/pavelaslanov/bytes-or-str-error.py:4:12 - error: Expression of type "bytearray | memoryview[_I@memoryview] | str" is incompatible with return type "str"
    Type "bytearray | memoryview[_I@memoryview] | str" is incompatible with type "str"
      "bytearray" is incompatible with "str" (reportReturnType)
1 error, 0 warnings, 0 informations 

VS Code extension or command-line pyright 1.1.377

erictraut commented 2 weeks ago

Pyright's behavior here is correct here, so this isn't a bug.

Traditionally, bytes has been treated as a "promotion type". When used in a type annotation, bytes implies the union bytes | bytearray | memoryview. This is similar to float implying the type float | int. PEP 688 deprecated bytes as a promotion type, but existing code bases still rely on this behavior, so pyright honors it by default. If you don't want this behavior, you can set disableBytesTypePromotions to true in your config file. This will eventually become the default setting.

erictraut commented 2 weeks ago

It has been more than two years since PEP 688 was accepted, so I think it's reasonable at this point to change the default for disableBytesTypePromotions from false to true. This will be included in the next release of pyright.