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

How do I type a "file object"? #482

Closed
Michael0x2a opened this issue Aug 18, 2016 · 4 comments · Fixed by #3057
Closed

How do I type a "file object"? #482

Michael0x2a opened this issue Aug 18, 2016 · 4 comments · Fixed by #3057

Comments

@Michael0x2a
Copy link
Contributor

I'm currently trying to add types for the selectors module, and am running into some difficulty figuring out the correct way to type a "file object".

The documentation for BaseSelector states that...

fileobj is the file object to monitor. It may either be an integer file descriptor or an object with a fileno() method.

However, the problem is that there doesn't seem to an ABC that exactly describes "an object with a fileno() method". I initially tried using io.IOBase and typing.IO, but the socket class doesn't seem to extend either base class (or share many of the methods, for that matter).

What is the correct course of action here? Should I try and petition to add a new ABC/modify the io module to try and unify all these different kinds of "file-like objects", or should I just settle for something more ad-hoc like the following?

from socket import socket
from io import IOBase
from typing import AnyStr, IO, Union

FileObj = Union[int, socket, IOBase, IO[AnyStr]]

(Oddly, io.IOBase and typing.IO also seem to be two distinct classes despite them being fairly similar -- I'm not sure if that was intentional or not)

@gvanrossum
Copy link
Member

This is one more use case for structural typing, but in the meantime I would do something ad-hoc like you describe rather than make yet another custom ABC (those are hard to introduce and hard to get rid of).

I actually expect that the only real use cases are sockets and ints -- by the time someone has an IOBase or IO[...] instance they are probably talking about a disk file, which selectors don't support. Also most subclasses of IOBase do some form of buffering which makes using a selector a no-no. Calling fileno() isn't really a hardship, and callers that don't have any other reference to the object wouldn't know what to do when they got called back.

Regarding IOBase vs. IO[...], that area is a bit of a mess, but basically the concrete implementation classes don't really have a proper subtyping relationship, so for the type system we are probably wise to ignore them.

@Michael0x2a
Copy link
Contributor Author

Thanks for the clarifications!

@Eric-Arellano
Copy link
Contributor

Could this be revisited now that protocols are supported in MyPy and Python 3.8? Make the type be Union[int, SupportsFileNo], where SupportsFileNo is a custom protocol that checks for the function fileno().

I'd be happy to submit a patch if you all would like.

@srittau
Copy link
Collaborator

srittau commented Jun 13, 2019

Please go ahead. This sounds like the right solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants