Skip to content

Removed continued parametrization of FilePathOrBuffer #27719

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

Closed
wants to merge 2 commits into from

Conversation

WillAyd
Copy link
Member

@WillAyd WillAyd commented Aug 2, 2019

follow up to #27598 to simplify things a bit. I think it was a mistake to add IO[AnyStr] as AnyStr is a TypeVar and not something to actually parametrize with. The source for IO already does this:

https://github.com/python/cpython/blob/8990ac0ab0398bfb9c62031288030fe7c630c2c7/Lib/typing.py#L1452

I'm not sure why mypy doesn't error on this.

@simonjayhawkins

@WillAyd WillAyd added the Typing type annotations, mypy/pyright type checking label Aug 2, 2019
@simonjayhawkins
Copy link
Member

i don't follow why we would want to reduce the strictness of the type checks and miss potential runtime errors

from io import StringIO
from pathlib import Path
from typing import IO, Union

FilePathOrBuffer = Union[str, Path, IO]

reveal_type(FilePathOrBuffer)


def common_function(filepath_or_buf: FilePathOrBuffer) -> FilePathOrBuffer:
    return filepath_or_buf


buf = common_function(StringIO())
reveal_type(buf)

buf.write(b"foo")
$ mypy notypevar.py
notypevar.py:7: error: Revealed type is 'Any'
notypevar.py:7: error: The type alias to Union is invalid in runtime context
notypevar.py:15: error: Revealed type is 'Union[builtins.str, pathlib.Path, typing.IO[Any]]'
notypevar.py:17: error: Item "str" of "Union[str, Path, IO[Any]]" has no attribute "write"
notypevar.py:17: error: Item "Path" of "Union[str, Path, IO[Any]]" has no attribute "write"
(pandas-dev) 
from io import StringIO
from pathlib import Path
from typing import IO, AnyStr, Union

FilePathOrBuffer = Union[str, Path, IO[AnyStr]]

reveal_type(FilePathOrBuffer)


def common_function(
    filepath_or_buf: FilePathOrBuffer[AnyStr]
) -> FilePathOrBuffer[AnyStr]:
    return filepath_or_buf


buf = common_function(StringIO())
reveal_type(buf)

buf.write(b"foo")
$ mypy typevar.py
typevar.py:7: error: Revealed type is 'Any'
typevar.py:7: error: The type alias to Union is invalid in runtime context
typevar.py:17: error: Revealed type is 'Union[builtins.str, pathlib.Path, typing.IO[builtins.str*]]'
typevar.py:19: error: Item "str" of "Union[str, Path, IO[str]]" has no attribute "write"
typevar.py:19: error: Item "Path" of "Union[str, Path, IO[str]]" has no attribute "write"
typevar.py:19: error: Argument 1 to "write" of "IO" has incompatible type "bytes"; expected "str"
(pandas-dev) 

@jreback jreback added this to the 1.0 milestone Aug 4, 2019
@WillAyd
Copy link
Member Author

WillAyd commented Aug 5, 2019

Yea my main motivation here is that I think this only works as is because of potentially buggy Mypy behavior. For instance, this passes type checking:

from typing import TypeVar

T = TypeVar("T", int, str)
X = TypeVar("X", float, dict)  # just picking random types here

def same_thing(obj: T) -> T:
    return obj

same_thing("a")  # passes as expected
same_thing(1)    # passes as expected
same_thing(X)    # passes?

Though I think it should fail since it's not parametrizing an int or a str in the last case. Seems like TypeVars (or anything with type Any) can be chained without impunity though also without a very obvious indication as to what is going on.

I brought it up on the mypy Gitter so will share any info I have. If it is in fact buggy I think better to just simplify.

Also thanks for the examples! Is there something you can think of in practice that would show up though? Since FilePathOrBuffer is a Union the returned type wouldn't match the type of the argument to these functions (noting the failures for str and Path not having a write attribute). I think the additional failure may just be coming from some deep parametrization of AnyStr but in a way that is not obvious

@simonjayhawkins
Copy link
Member

an example from typeshed where a alias to a union that includes a generic subscripted with a typevar. The continued use of the alias also includes subscription.

https://github.com/python/typeshed/blob/3c4141982e22aba6966daba5785d1ba959d7fc49/stdlib/3/asyncio/tasks.pyi#L18-L42

@WillAyd
Copy link
Member Author

WillAyd commented Aug 25, 2019

Thanks for the example, though I still think that is a more common case and not really intended for IO. In any case I think we always need to consider the complexity and readability of annotations versus incremental benefit. I personally think this current design is less readable and confusing to people not fully invested in annotations, hence the PR

In any case we have a rather large queue at the moment and this isn't a huge priority. Closing for now can come back at a later date

@WillAyd WillAyd closed this Aug 25, 2019
@WillAyd WillAyd deleted the remove-anystr branch January 16, 2020 00:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Typing type annotations, mypy/pyright type checking
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants