pythonpython-typingpyright

How do I add a type hint for a WriteableBuffer parameter?


I'm trying to add a parameter type to the readinto() method declared in a custom class that derives from RawIOBase, like this:

from io import RawIOBase

class Reader(RawIOBase):
    def readinto(self, buf: bytearray) -> int:
        pass  # actual implementation omitted

But pyright complains:

io.py:6:9 - error: Method "readinto" overrides class "_RawIOBase" in an incompatible manner
    Parameter 2 type mismatch: base parameter is type "WriteableBuffer", override parameter is type "bytearray"
      "Buffer" is not assignable to "bytearray" (reportIncompatibleMethodOverride)
1 error, 0 warnings, 0 informations 

How do I fix this? Note: I know I can remove the type hint entirely. I want to assign it the correct type instead.

I'm using Python 3.13.3 and pyright 1.1.400.


Solution

  • You need to use the same type definition as your base. You can use the same type alias here by importing it from _typeshed package, provided you put it under a TYPE_CHECKING guard:

    from io import RawIOBase
    from typing import TYPE_CHECKING
    
    if TYPE_CHECKING:
        from _typeshed import MaybeNone, WriteableBuffer
    
    class Reader(RawIOBase):
        def readinto(self, buf: WriteableBuffer) -> int | MaybeNone:
            ...
    

    You can count on the _typeshed package existing when running under a type checker, because the type checker brings along that package. This is how pyright knows what the signature for RawIOBase.readinto() is, for example. I added MaybeNone to the above for the same reason, because that's also part of the documented signature.

    Alternatively, because WriteableBuffer is just a type alias for collections.abc.Buffer, the following also works (replacing MaybeNone with a redefinition):

    from collections.abc import Buffer
    from io import RawIOBase
    from typing import Any, TypeAlias
    
    type MaybeNone = Any
    
    class Reader(RawIOBase):
        def readinto(self, buf: Buffer) -> int | MaybeNone:
            ...
    

    See The Any Trick for an explanation as to why MaybeNone is an alias for Any.