-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
json.load can also take IO[bytes] in py36+ #2188
Conversation
hmm, it appears there's still more to fix -- still not getting this to resolve correctly: import json
import urllib.request
json.load(urllib.request.urlopen('https://pypi.org/pypi/pre-commit/json')) $ mypy --custom-typeshed-dir . test2.py
test2.py:3: error: Argument 1 to "load" has incompatible type "Union[HTTPResponse, addinfourl]"; expected "IO[Any]" |
stdlib/3/json/__init__.pyi
Outdated
@@ -41,7 +41,11 @@ def loads(s: Union[str, bytes, bytearray], | |||
object_pairs_hook: Optional[Callable[[List[Tuple[Any, Any]]], Any]] = ..., | |||
**kwds: Any) -> Any: ... | |||
|
|||
def load(fp: IO[str], | |||
if sys.version_info >= (3, 6): | |||
_LoadIO = IO[AnyStr] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AnyStr is not correct here, since it is a typevar and there is nothing by which to constrain the typevar. You probably want IO[Any]
or Union[IO[str], IO[bytes]]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmmm, the comment above AnyStr
seems to indicate "with constraints" -- I can't say I know what that means specifically but it does seem to indicate that it is not "nothing by which to constrain" -- please help me understand your comment :)
### (from cpython 3.6.5)
# A useful type variable with constraints. This represents string types.
# (This one *is* for export!)
AnyStr = TypeVar('AnyStr', bytes, str)
IO
is also defined by default as:
### (from cpython 3.6.5)
class IO(Generic[AnyStr]):
Is IO
~= IO[Any]
~= IO[AnyStr]
?
You probably want
IO[Any]
orUnion[IO[str], IO[bytes]]
If IO
or IO[AnyStr]
is not appropriate, which of these suggestions would you prefer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeVars are used when there are multiple types involved in a signature that need to have the same value. For example, a function that takes either str or bytes and returns the same type could be usefully as typed as def f(s: AnyStr) -> AnyStr: ...
.
In the definition of IO, the fact that it is generic over AnyStr means that its type argument is constrained to be either str or bytes. IO
is the same as IO[Any]
; IO[AnyStr]
is probably equivalent in practice, but doesn't make sense in most contexts.
I think IO[Any]
is best.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
neat, I tried to convince myself of the same thing:
import io
from typing import IO, Any, AnyStr, Union
io_nothing: IO
io_any: IO[Any]
io_union: Union[IO[str], IO[bytes]]
io_nothing = io_any = io_union = io.BytesIO(b'')
io_nothing = io_any = io_union = io.StringIO('')
def f_takes_nothing(x: IO): ...
def f_takes_any(x: IO[Any]): ...
def f_takes_union(x: Union[IO[str], IO[bytes]]): ...
f_takes_nothing(io.BytesIO(b''))
f_takes_any(io.BytesIO(b''))
f_takes_union(io.BytesIO(b''))
f_takes_nothing(io.StringIO(''))
f_takes_any(io.StringIO(''))
f_takes_union(io.StringIO(''))
# error: Invalid type "typing.AnyStr"
#io_anystr: IO[AnyStr] = io.BytesIO(b'')
#io_anystr: IO[AnyStr] = io.StringIO('')
# why does this pass mypy?
def f_takes_anystr(x: IO[AnyStr]): ...
f_takes_anystr(io.BytesIO(b''))
f_takes_anystr(io.StringIO(''))
oddly enough, I get an error in one spot for IO[AnyStr]
but not in a function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my view mypy is less strict than it should be in rejecting certain usages of type variables.
testcase
before
after