Skip to content

open() returns IO[str] instead of io.TextIOWrapper #1229

Closed

Description

@jcrmatos

Hello,

My env is Win7P+SP1 x64, Py 3.5.2 32b, Mypy 0.501.

I opened this issue (#3286) in mypy, but GVR told me to open it here because it was a "(complex) typeshed issue".

The var used in the with context is of type <class '_io.TextIOWrapper'>.

with open(pathname, encoding='utf-8') as f_in:
    print(type(f_in))

<class '_io.TextIOWrapper'>

But when I try to set it's type, mypy returns the following error

from io import TextIOWrapper
with open(pathname, encoding='utf-8') as f_in:  # type: TextIOWrapper
    print(type(f_in))

data_processing.py:917: error: Incompatible types in assignment (expression has type IO[Any], variable has type "TextIOWrapper")

If I try to use module typing's own TextIO type it returns

from typing import TextIO
with open(pathname, encoding='utf-8') as f_in:  # type: TextIO
    print(type(f_in))

data_processing.py:917: error: Incompatible types in assignment (expression has type IO[Any], variable has type "TextIO")

It only works if I do

from typing import IO
with open(pathname, encoding='utf-8') as f_in:  # type: IO[Any]
    print(type(f_in))

Best regards,

JM

Activity

  1. lincolnq commented on May 30, 2017

    @lincolnq
    Contributor

    The solution to your problem is probably to use IO[str], which is compatible with the IO[Any] returned by open() and has (most of) the right methods. It doesn't have the TextIO specific ones (like .encoding, .line_buffering, etc.), so if you want those you should use cast(TextIO, open(...)).

    However, I agree that this is an interesting problem and worth thinking about. It means TextIO and BinaryIO are annoyingly impractical to use in real code (a cast is necessary whenever open() is called). The documentation doesn't give many examples or suggest that IO[str] is what most people should use.

  2. gvanrossum commented on May 30, 2017

    @gvanrossum
    Member

    Yeah, this is not one of the smoothest APIs. Note that in master, open(fn, 'rb') will now return IO[bytes] while open(fn, 'r') will return IO[str]. (However, if the mode argument is a variable, it returns IO[Any]; and in PY2 they all return BinaryIO regardless of the mode.)

    I think this is still wrong though. open() with a recognized mode argument should return BinaryIO or TextIO. That way you can write

    f: TextIO = open(fn, 'rb')

    Some classes used by the implementation in the io module are subclasses of TextIO or BinaryIO, but you're better off not referencing them.

    (Another note: it's not great to use runtime inspection to come up with type names to put into annotations -- things at runtime are a bit different from how things are dine on the static typing side of things.)

  3. srittau commented on Sep 11, 2018

    @srittau
    Collaborator

    I think any further improvements in typeshed for this are dependent on implementing dependent types, see python/mypy#3062.

  4. changed the title [-]Mypy assumes and only accepts type IO[Any] when it is _io.TextIOWrapper (GVR told me to open this here)[/-] [+]open() returns IO[str] instead of io.TextIOWrapper[/+] on Oct 28, 2018
  5. srittau commented on Oct 28, 2018

    @srittau
    Collaborator

    This is part of the IO classes restructuring.

  6. added a commit that references this issue on Feb 8, 2020
  7. hauntsaninja commented on Jun 11, 2020

    @hauntsaninja
    Collaborator

    This was fixed in #4146 and others!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions