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

Add typing.Reader and typing.Writer #564

Open
ilevkivskyi opened this issue Jun 16, 2018 · 10 comments
Open

Add typing.Reader and typing.Writer #564

ilevkivskyi opened this issue Jun 16, 2018 · 10 comments
Labels
topic: feature Discussions about new features for Python's type annotations

Comments

@ilevkivskyi
Copy link
Member

I recently stumbled at a TODO in typeshed that proposes to split IO[AnyStr] into smaller pieces. I think it is a good idea and propose to add two protocols:

class Reader(Protocol[AnyStr]):
    def read(self, n: int = ...) -> AnyStr: ...
    def readlines(self) -> List[AnyStr]: ...
    def close(self) -> None: ...

class Writer(Protocol[AnyStr]):
    def write(self, s: AnyStr) -> int: ...
    def writelines(self, lines: List[AnyStr]) -> None: ...
    def close(self) -> None: ...

Then IO[AnyStr] can subclass both, plus add some less often used methods (also IO should stay nominal). What do you think?

@JelleZijlstra
Copy link
Member

I like this idea. Using the current IO classes in type annotations is a bit problematic because many types are kind of like files, but don't fulfill the entire IO interface (typing.IO has 23 methods and properties). If we add Reader and Writer, many argument type annotations could be changed to just one of these two.

@gvanrossum
Copy link
Member

Of course many duck type providers for files don't even support close() or readlines(), so even the proposed Reader protocol may be too wide. (Those libraries can of course define their own Readable protocol.)

I think that close() should not be a part of these protocols -- typically closing a stream is up to the owner, i.e. the party that created (opened) it.

Also you've left out readline() -- that seems a mistake, it's probably the most commonly called I/O method.

Finally this doesn't help much for return types -- we often also want to describe that something returns a readable stream (or a writable one) but the interface promised by many APIs is much wider than the minimal protocols proposed here. This is one of the reasons I punted on this when originally designing the IO API -- the other reason was of course that we didn't have protocols then.

(There are other things one might want to express in the type system too, esp. whether seek() and tell() should work.)

@srittau
Copy link
Collaborator

srittau commented Jun 18, 2018

Maybe a good way to go about this is to start replacing argument types in typeshed with custom protocols in the respective modules (marked private so they do not get reused outside the module) to get a feeling what is required in practice.

@JukkaL
Copy link
Contributor

JukkaL commented Jun 18, 2018

Maybe a good way to go about this is to start replacing argument types in typeshed with custom protocols in the respective modules (marked private so they do not get reused outside the module) to get a feeling what is required in practice.

I like this idea. If we don't do this, we risk implementing something that won't be that useful and will mostly confuse users.

srittau added a commit to srittau/typeshed that referenced this issue Jun 28, 2018
@srittau
Copy link
Collaborator

srittau commented Jun 28, 2018

As seen above I submitted a first pull request implementing my last suggestion. Maybe it would be a good idea to mark those somehow, for example with a link to this issue, to be able to grep them easily later?

@ilevkivskyi
Copy link
Member Author

I think just adding a link to this issue would be enough.

@srittau
Copy link
Collaborator

srittau commented Jun 28, 2018

@ilevkivskyi You mean in the commit message like above?

@ilevkivskyi
Copy link
Member Author

You mean in the commit message like above?

I think adding the link in PR description may be better. GitHub only uses the commit message for PR description if there is a single commit in your PR, and as you can see the links to PRs are bigger than to commits.

JelleZijlstra pushed a commit to python/typeshed that referenced this issue Jun 28, 2018
srittau added a commit to srittau/typeshed that referenced this issue Aug 14, 2018
* loads() only accepts str as first argument for Python < 3.6
* Use a protocol for the first argument to load() (cf python/typing#564)
JelleZijlstra pushed a commit to python/typeshed that referenced this issue Aug 14, 2018
* loads() only accepts str as first argument for Python < 3.6
* Use a protocol for the first argument to load() (cf python/typing#564)
yedpodtrzitko pushed a commit to yedpodtrzitko/typeshed that referenced this issue Jan 23, 2019
yedpodtrzitko pushed a commit to yedpodtrzitko/typeshed that referenced this issue Jan 23, 2019
* loads() only accepts str as first argument for Python < 3.6
* Use a protocol for the first argument to load() (cf python/typing#564)
@kkirsche
Copy link
Contributor

kkirsche commented May 31, 2021

I think that close() should not be a part of these protocols -- typically, closing a stream is up to the owner, i.e., the party that created (opened) it.

This seems like an area where Python could look at Golang's interfaces. In the case of IO, they have (concerning this)

  • io.Reader
  • io.ReadCloser
  • io.ReadWriter
  • io.ReadWriteCloser
  • ....

This allows the end-user to operate with the specificity needed for the problem space at the cost of a more complex interface system. Personally, I've stayed away from Python's IO as it's never been clear to me what the intended use is from the docs.

References

@srittau
Copy link
Collaborator

srittau commented May 31, 2021

We have a good starting point for useful protocols already in the _typeshed module. These are based on the actual need of the standard library. I see the future in easy composing of protocols rather than adding various protocol with different permutations of methods. For example using intersection types (#213): SupportsRead[str] & SupportsClose.

@srittau srittau added topic: feature Discussions about new features for Python's type annotations and removed enhancement labels Nov 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: feature Discussions about new features for Python's type annotations
Projects
None yet
Development

No branches or pull requests

6 participants