Issue25749
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2015-11-27 19:28 by Ron Frederick, last changed 2022-04-11 14:58 by admin.
Messages (14) | |||
---|---|---|---|
msg255476 - (view) | Author: Ron Frederick (Ron Frederick) * | Date: 2015-11-27 19:28 | |
The asyncio documentation defines the class 'asyncio.Server' in section 18.5.1.15. However, this class is not exported by asyncio. It is defined in base_events.py but not in the __all__ list. The only class exported at the asyncio top level is asyncio.AbstractServer, defined in events.py. I think the documentation should match the exports. Either Server should be exported out of base_events.py, or the documentation should only refer to asyncio.AbstractServer. |
|||
msg255477 - (view) | Author: Yury Selivanov (yselivanov) * | Date: 2015-11-27 19:32 | |
Let's not export the Server class -- in uvloop, for instance, I have a completely different internal implementation of Server (I can't use the one from asyncio). |
|||
msg255497 - (view) | Author: STINNER Victor (vstinner) * | Date: 2015-11-27 22:18 | |
Yeah, I recall this point. The doc points to Server, but Guido didn't want to expose "implementation details" of Server like sockets. Different implementations of event loops (Yury gave the good example of uvloop based on libuv) don't give (direct) access to sockets. The problem is maybe that we try to document two different things at the same place: asyncio "portable" API (the PEP 3156), and the implementation of "default" event loops. Even if it's not possible to directly use server sockets, it's kind of useful to get them. What do you think? Server.sockets is documented at: https://docs.python.org/dev/library/asyncio-eventloop.html#asyncio.Server.sockets Server.sockets is explicitly documented at: https://docs.python.org/dev/library/asyncio-eventloop.html#asyncio.BaseEventLoop.create_server I would prefer to keep the Server.sockets doc, but explain better that it's an "implementation detail". We already have something similar for "CPython" implementation details in the doc. Examples: - https://docs.python.org/dev/library/sys.html#sys._debugmallocstats - https://docs.python.org/dev/library/sys.html#sys._getframe - https://docs.python.org/dev/library/dis.html#module-dis - etc. What do you think of reusing the ".. impl-detail:" markup? Or do you prefer to write a different kind of box for asyncio? Or just not box and a simple sentence? |
|||
msg255502 - (view) | Author: Yury Selivanov (yselivanov) * | Date: 2015-11-27 22:55 | |
> Yeah, I recall this point. The doc points to Server, but Guido didn't want to expose "implementation details" of Server like sockets. Different implementations of event loops (Yury gave the good example of uvloop based on libuv) don't give (direct) access to sockets. I actually found a way to extract a fileno (there is an API for that). But Ron suggested to actually export the Server class, so that it's available as 'asyncio.Server'. And I think that *that* is a bad idea, since the actual implementation of Server is tied to event loop and transports, which may be implemented differently (as in uvloop) |
|||
msg255505 - (view) | Author: STINNER Victor (vstinner) * | Date: 2015-11-27 22:59 | |
Yury Selivanov added the comment: > But Ron suggested to actually export the Server class, so that it's available as 'asyncio.Server'. And I think that *that* is a bad idea, (...) I know, but IMHO the issue is wider than just exporting or not the symbol. Right now, create_server() doc explicitly says that the list of sockets is available in server.sockets attribute. We should mention that it's not always the case, it's only available on "some" implementations of event loops. |
|||
msg308827 - (view) | Author: Yury Selivanov (yselivanov) * | Date: 2017-12-20 21:37 | |
There's no point in exporting the Server class as "asyncio.Server". It'd created and managed by the event loop, and there's no point to instantiate it in user code. We can add an abstract base class AbstractServer though, similar to AbstractFuture and AbstractTask proposed in https://bugs.python.org/issue32364. This is a low priority feature and can probably wait till 3.8 though. |
|||
msg308840 - (view) | Author: Ron Frederick (Ron Frederick) * | Date: 2017-12-21 02:54 | |
In my original report, I suggested _either_ exporting asyncio.Server since that's what was documented elsewhere _OR_ adding AbstractServer to the documentation and changing existing references to asyncio.Server to point at asyncio.AbstractServer instead, as that symbol is already exported but is not currently documented. There appear to be good reasons for hiding the implementation details of Server, and I'm good with that. I just think the docs and the exports need to agree on one or the other. I originally had references to AbstractServer in my project docs, but changed them to Server after seeing that only Server was currently in the public Python documentation. As for references to the "sockets" member of Server, I'm not currently relying on that in my code. I have code that can handle getaddrinfo() returning more than one address to listen on, but I create separate Server instances for each individual address right now, as this gives me better control when a caller asks to listen on a dynamic port on multiple interfaces at once. |
|||
msg308841 - (view) | Author: Yury Selivanov (yselivanov) * | Date: 2017-12-21 03:08 | |
Server.sockets property will be a public API and defined in the AbstractServer, so you can start using them. Just don't try to call socket.send() or socket.accept() as that will break things. |
|||
msg308843 - (view) | Author: Ron Frederick (Ron Frederick) * | Date: 2017-12-21 03:32 | |
Thanks. Unfortunately, in the case of the way SSH listeners with dynamic ports, the protocol only allows a single port number to be returned. So, when binding on multiple interfaces there's a requirement that the SAME port be chosen for all of the socket bindings, which can't easily be done today with a single asyncio.Server object. That's a bit off-topic for this issue, though. Regarding exposing the sockets, it would never really make sense to directly call send() on a listening socket, and I can see why it also wouldn't make sense to allow calling accept(). I'm really not sure there's ANY call other than getsockaddr() that really makes sense here, though, so perhaps it would be better to evolve the API in AbstractServer into returning a list of sockaddr tuples rather than sockets. |
|||
msg308845 - (view) | Author: Yury Selivanov (yselivanov) * | Date: 2017-12-21 03:45 | |
> I'm really not sure there's ANY call other than getsockaddr() that really makes sense here, though, so perhaps it would be better to evolve the API in AbstractServer into returning a list of sockaddr tuples rather than sockets. Right, that's why uvloop exposes only SocketLike objects, that have getsockaddr() and getsockopt(), but raise when sock.send() is called. Maybe we'll do the same thing in asyncio. |
|||
msg308848 - (view) | Author: Yury Selivanov (yselivanov) * | Date: 2017-12-21 03:54 | |
> _OR_ adding AbstractServer to the documentation and changing existing references to asyncio.Server to point at asyncio.AbstractServer instead, as that symbol is already exported but is not currently documented. I completely missed the fact that we already export AbstractServer and that the documentation doesn't actually refer to it, and that it has less APIs than Server. Thanks for reminding me of that, Ron. I'll try to address the docs part before 3.7 comes out. > So, when binding on multiple interfaces there's a requirement that the SAME port be chosen for all of the socket bindings, which can't easily be done today with a single asyncio.Server object. That's a bit off-topic for this issue, though. And why do you need a single Server object? |
|||
msg308849 - (view) | Author: Ron Frederick (Ron Frederick) * | Date: 2017-12-21 04:09 | |
That'd be great if you could add AbstractServer to the 3.7 docs - thanks! Regarding the other issue, I'm already set up to use multiple asyncio.Server objects to deal with the shared port issue and it's working fine. It did mean duplicating a handful of lines of code from asyncio to iterate over the getaddrinfo() results (creating one asyncio.Server per sockaddr instead of letting asyncio create a single asyncio.Server with multiple listening sockets) and there are some other minor details like cleaning up if the kernel-selected dynamic port chosen for the first interface is not actually free on all other interfaces, but I'm not actually looking for any changes in how that's working right now. Here's the code I'm referring to if you're curious: https://github.com/ronf/asyncssh/blob/master/asyncssh/listener.py#L192 |
|||
msg308850 - (view) | Author: Yury Selivanov (yselivanov) * | Date: 2017-12-21 04:19 | |
> It did mean duplicating a handful of lines of code from asyncio to iterate over the getaddrinfo() results (creating one asyncio.Server per sockaddr instead of letting asyncio create a single asyncio.Server with multiple listening sockets) and there are some other minor details like cleaning up if the kernel-selected dynamic port chosen for the first interface is not actually free on all other interfaces, but I'm not actually looking for any changes in how that's working right now. I think you're doing it the right way. It's a rather niche requirement, so I don't think we should make create_server to somehow support this use case. asyncssh looks absolutely amazing, btw. |
|||
msg308868 - (view) | Author: Ron Frederick (Ron Frederick) * | Date: 2017-12-21 12:38 | |
> I think you're doing it the right way. It's a rather niche requirement, so I don't think we should make create_server to somehow support this use case. Agreed. > asyncssh looks absolutely amazing, btw. Thanks so much! |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:58:24 | admin | set | github: 69935 |
2017-12-21 12:38:39 | Ron Frederick | set | messages: + msg308868 |
2017-12-21 04:19:02 | yselivanov | set | messages: + msg308850 |
2017-12-21 04:09:50 | Ron Frederick | set | messages: + msg308849 |
2017-12-21 03:54:34 | yselivanov | set | messages:
+ msg308848 versions: + Python 3.7 |
2017-12-21 03:45:43 | yselivanov | set | messages: + msg308845 |
2017-12-21 03:32:58 | Ron Frederick | set | messages: + msg308843 |
2017-12-21 03:08:13 | yselivanov | set | messages: + msg308841 |
2017-12-21 02:54:20 | Ron Frederick | set | messages: + msg308840 |
2017-12-20 21:37:43 | yselivanov | set | messages:
+ msg308827 versions: + Python 3.8, - Python 3.6, Python 3.7 |
2017-12-20 20:57:36 | asvetlov | set | versions: + Python 3.7, - Python 3.4, Python 3.5 |
2017-12-20 20:57:20 | asvetlov | set | assignee: asvetlov nosy: + asvetlov |
2015-11-27 22:59:16 | vstinner | set | messages: + msg255505 |
2015-11-27 22:55:07 | yselivanov | set | messages: + msg255502 |
2015-11-27 22:18:54 | vstinner | set | messages: + msg255497 |
2015-11-27 19:32:26 | yselivanov | set | messages: + msg255477 |
2015-11-27 19:28:36 | Ron Frederick | create |