Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug(?): GzipFile typing incompatible with io.TextIOWrapper #11418

Closed
jamesbraza opened this issue Feb 13, 2024 · 4 comments · Fixed by #11420
Closed

Bug(?): GzipFile typing incompatible with io.TextIOWrapper #11418

jamesbraza opened this issue Feb 13, 2024 · 4 comments · Fixed by #11420
Labels
topic: io I/O related issues

Comments

@jamesbraza
Copy link
Contributor

jamesbraza commented Feb 13, 2024

Please see the below code with Python 3.12:

import gzip
import io


def gzip_to_list(file: gzip.GzipFile) -> list[str]:
    with io.TextIOWrapper(buffer=file) as f:
        return list(f)

Running mypy==1.8.0, I get this error message:

a.py:6:34: error: Argument "buffer" to "TextIOWrapper" has incompatible type "GzipFile"; expected "IO[bytes]"  [arg-type]

However, running this code, it actually works fine.

I am thinking this is a typeshed bug, but I am not 100% positive. #5491 and #6061 are possibly related

@AlexWaygood AlexWaygood added the topic: io I/O related issues label Feb 14, 2024
@srittau
Copy link
Collaborator

srittau commented Feb 14, 2024

I/O classes are a bit of a mess, since they predate protocols. TextIOWrapper should take a protocol as buffer argument. Someone needs to investigate the implementation of TextIOWrapper (found here: https://github.com/python/cpython/blob/main/Modules/_io/textio.c) to determine, which methods and attributes of buffer are actually accessed and then we could use such a protocol.

In fact, TextIOWrapper should probably be generic over the buffer type, but we can't do that before PEP 696 lands.

@srittau
Copy link
Collaborator

srittau commented Feb 14, 2024

Here is what I found:

  • seekable() -> bool
  • readable() -> bool
  • writable() -> bool
  • tell() -> int
  • write(b: bytes, /) -> object
  • flush() -> object
  • read(size: int = ...) -> bytes
  • seek(offset: Literal[0], whence: Literal[2]) -> int
  • truncate(size: int, /) -> int
  • fileno() -> int
  • isatty() -> int
  • close() -> object
  • name: str
  • closed: bool
  • Optional: read1(size: int, /) -> bytes (strictly speaking Buffer would do as return type, but bytes is safer)

Some of these are only forwarded, so strictly speaking they are not necessary if the method is not called on the wrapper, but not requiring them would be unsafe.

It also checks for buffer.raw to exist and be a FileIO type under certain conditions, but ignores it if it isn't, so this is not part of the protocol.

@AlexWaygood
Copy link
Member

Here is what I found

I found the same.

Links to the source code

@srittau
Copy link
Collaborator

srittau commented Feb 14, 2024

I've opened a draft PR: #11420. Let's see what our tests – especially primer – say.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: io I/O related issues
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants