Skip to content

Instantly share code, notes, and snippets.

@kmarekspartz
Created May 2, 2017 22:39
Show Gist options
  • Save kmarekspartz/c0bed39b7de8dee64e0c895b852a850d to your computer and use it in GitHub Desktop.
Save kmarekspartz/c0bed39b7de8dee64e0c895b852a850d to your computer and use it in GitHub Desktop.
mypy typing TextIO bug

I've been having trouble adding types to:

from sys import stdin, stdout

... # import something as TIO... See below.

def main(input_io: TIO=stdin, output_io: TIO=stdout) -> None:
    for line in input_io.readlines():
        output_io.write(line)


if __name__ == '__main__':
    main()

Depending on which class is used for the typing we get different results:

io.TextIO

from io import TextIO as TIO

Type checks but fails at runtime with:

ImportError: cannot import name 'TextIO'

I'd expect this one to fail during type checking. This is a bug, I think. There seems to be issues with https://github.com/python/typeshed/blob/397f99836842494de2e9561001d16cbe64b3b937/stdlib/3/io.pyi and I suspect a change there (possibly breaking it out to minor versions of Python 3) would catch this.

io.TextIOBase

from io import TextIOBase as TIO

Fails at type check:

error: Incompatible types in assignment (expression has type "TextIO", variable has type "TextIOBase")
error: Argument 1 to "write" of "TextIOBase" has incompatible type "bytes"; expected "str"

This is okay, but a poor error message, e.g. "Did you mean typing.TextIO?" might be a better error message. A stretch goal :)

io.TextIOWrapper

from io import TextIOWrapper as TIO

Fails at type check:

error: Incompatible types in assignment (expression has type "TextIO", variable has type "TextIOWrapper")

Also okay.

typing.TextIO

from typing import TextIO as TIO

Works great, but type(sys.stdin) is not TextIO in Python 3.6.

Related issues with TextIO:

python/mypy#2111 python/mypy#2337 python/mypy#266 https://github.com/python/mypy/issues/1462 python/typeshed#163

FROM python:3.6
WORKDIR /mypy-bug
ADD requirements.txt .
RUN pip install -r requirements.txt
ADD typing_text_io.py main.py
RUN mypy --strict main.py
CMD python main.py
from io import TextIO as TIO
from sys import stdin, stdout
def main(input_io: TIO=stdin, output_io: TIO=stdout) -> None:
for line in input_io.readlines():
output_io.write(line)
if __name__ == '__main__':
main()
from io import TextIOBase as TIO
from sys import stdin, stdout
def main(input_io: TIO=stdin, output_io: TIO=stdout) -> None:
for line in input_io.readlines():
output_io.write(line)
if __name__ == '__main__':
main()
from io import TextIOWrapper as TIO
from sys import stdin, stdout
def main(input_io: TIO=stdin, output_io: TIO=stdout) -> None:
for line in input_io.readlines():
output_io.write(line)
if __name__ == '__main__':
main()
from typing import TextIO as TIO
from sys import stdin, stdout
def main(input_io: TIO=stdin, output_io: TIO=stdout) -> None:
for line in input_io.readlines():
output_io.write(line)
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment