Issue30300
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 2017-05-07 18:24 by barry, last changed 2022-04-11 14:58 by admin. This issue is now closed.
Pull Requests | |||
---|---|---|---|
URL | Status | Linked | Edit |
PR 1492 | closed | barry, 2017-05-07 18:26 |
Messages (17) | |||
---|---|---|---|
msg293205 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2017-05-07 18:24 | |
Over in https://github.com/aio-libs/aiosmtpd we have a Controller class which is very handy for testing and other cases. I realized that this isn't really aiosmtpd specific, and with just a few tweaks it could be appropriate for the stdlib. I have a branch ready for a pull request. This is the tracking/discussion issue. |
|||
msg293260 - (view) | Author: Nathaniel Smith (njs) * ![]() |
Date: 2017-05-08 23:06 | |
Looks interesting! What's the advantage over running the server and the test in the same loop? The ability to use blocking operations in the tests, and to re-use an expensive-to-start server over multiple tests? (I've mostly used threads in tests to run blocking code for interoperability testing, and kept the async code in the main thread, so this is a bit novel to me.) |
|||
msg293264 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2017-05-09 00:44 | |
On May 08, 2017, at 11:06 PM, Nathaniel Smith wrote: >Looks interesting! What's the advantage over running the server and the test >in the same loop? The ability to use blocking operations in the tests, and to >re-use an expensive-to-start server over multiple tests? So, the ability to re-use expensive-to-start servers is definitely one of the advantages. I use nose2's layers, but test fixtures would fall into the same category. As for running the server and tests in the same loop; I haven't tried that, but it seems like it would be more complicated to set up (maybe that's dependent on the code under test). More important is that I want to block the tests until the server starts up. I'm not sure (haven't tried) whether that's possible when running them all in the same loop. One other use case I have is for the LMTP server in Mailman 3. The controller turns out to be useful based on the start/stop framework for MM3 "runners". That's probably strictly doable without the controller, but it's convenient, readable, and a nice reuse. |
|||
msg293464 - (view) | Author: STINNER Victor (vstinner) * ![]() |
Date: 2017-05-11 00:09 | |
I'm not sure that Controller is generic enough to be part of asyncio. I'm not sure about the cancellation of all pending tasks on stop(). Why not starting by putting this class in a library to mature its API? |
|||
msg293465 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2017-05-11 00:26 | |
On May 11, 2017, at 12:09 AM, STINNER Victor wrote: >Why not starting by putting this class in a library to mature its API? It's already part of aiosmtpd although not with the small amount of generic-ness included here. It's been useful and stable. So this is just refactoring out the aiosmtpd-ness of it. It doesn't seem big enough to put into yet another separate library. |
|||
msg294638 - (view) | Author: Antoine Pitrou (pitrou) * ![]() |
Date: 2017-05-28 11:07 | |
I think the API is too specific. Instead of requiring hostname and port, why not let the user override setup and teardown coroutines? In your case, this could be: async def setup(self): self.server = await self.loop.create_server(...) async def teardown(self): await self.server.wait_closed() |
|||
msg294666 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2017-05-29 00:47 | |
Hi Antoine, On May 28, 2017, at 11:07 AM, Antoine Pitrou wrote: >I think the API is too specific. Can you elaborate? What's too specific about it? Do you have in mind a use case where you wouldn't need to provide hostname and port? >Instead of requiring hostname and port, why not let the user override setup >and teardown coroutines? > >In your case, this could be: > >async def setup(self): > self.server = await self.loop.create_server(...) > >async def teardown(self): > await self.server.wait_closed() It's certainly possible to factor those out so they could be overridden, I'm just not sure why that's needed. |
|||
msg294675 - (view) | Author: Antoine Pitrou (pitrou) * ![]() |
Date: 2017-05-29 07:07 | |
> Can you elaborate? What's too specific about it? Do you have in mind a use case where you wouldn't need to provide hostname and port? Any use case where setup is more elaborate than calling create_server(...). For example I might write a UDP server. Or a distributed system that listens to several ports at once, or launches a thread pool. etc. |
|||
msg294698 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2017-05-29 15:23 | |
On May 29, 2017, at 07:07 AM, Antoine Pitrou wrote: >For example I might write a UDP server. Or a distributed system that listens >to several ports at once, or launches a thread pool. etc. Thanks, those are nice motivational examples. |
|||
msg294725 - (view) | Author: Yury Selivanov (yselivanov) * ![]() |
Date: 2017-05-29 23:42 | |
I'm not sure we want this to be in asyncio: it's a very high-level object somewhere in between the low-level and the application level. Some things off the top of my head that users will want from this API: - detailed logging or hooks to implement it - hooks on thread start / stop - coroutines to run before starting the server - coroutines to run before stopping the loop - custom undhandled exceptions handlers - type of the server created: TCP/UDP/Unix - ability to configure SSL - etc Since asyncio is no longer provisional, it won't be possible to evolve the API in bugfix releases, which will likely make it impossible to use for many users until 3.8. In general, the advice for things like this is to put them on PyPI, gather some feedback, and sort out the API details. -1 to add this in 3.7 in its current state. P.S. It would be interesting to try to evolve the idea a bit further: it would be interesting if Controller was a high-level description of a service and we had a separate concept of ControllerRunner to run Controllers in threads, processes and corotuines. Maybe build something like erlang supervisor trees out of them. |
|||
msg294767 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2017-05-30 16:56 | |
On May 29, 2017, at 11:42 PM, Yury Selivanov wrote: >- detailed logging or hooks to implement it >- hooks on thread start / stop >- coroutines to run before starting the server >- coroutines to run before stopping the loop >- custom undhandled exceptions handlers >- type of the server created: TCP/UDP/Unix >- ability to configure SSL >- etc > >P.S. It would be interesting to try to evolve the idea a bit further: it >would be interesting if Controller was a high-level description of a service >and we had a separate concept of ControllerRunner to run Controllers in >threads, processes and corotuines. Maybe build something like erlang >supervisor trees out of them. There's also value in doing one simple thing that adds convenience for users. I don't personally have any interest in building something as elaborate as the above, but I've used the simple idea here several times in different projects. |
|||
msg294790 - (view) | Author: STINNER Victor (vstinner) * ![]() |
Date: 2017-05-30 21:57 | |
Barry: would you be ok to start by adding Controller to asyncio.test_utils, and wait later to expose it in the public API? |
|||
msg294794 - (view) | Author: Yury Selivanov (yselivanov) * ![]() |
Date: 2017-05-30 22:36 | |
> STINNER Victor added the comment: > > Barry: would you be ok to start by adding Controller to asyncio.test_utils, > and wait later to expose it in the public API? Sorry, but we are going to deprecate and remove test_utils soon. It's a bunch of internal unit test helpers used privately by asyncio. They are not documented and not supported. Now that asyncio repo is in CPython repo and we don't release it on its own, i see no reason to keep test_utils (we can move it to 'Lib/test'. Again, the natural way of something like Controller to end up in asyncio is to either go through full PEP process, or live some time on PyPI and prove to be useful. |
|||
msg294798 - (view) | Author: Yury Selivanov (yselivanov) * ![]() |
Date: 2017-05-30 23:10 | |
> There's also value in doing one simple thing that adds convenience for users. > I don't personally have any interest in building something as elaborate as the > above, but I've used the simple idea here several times in different projects. Yeah, I understand. I totally see how Controller can be useful, moreover, I've implemented something like it bunch of times (usually for running tests). But with Guido no longer actively involved with asyncio, and me being the only one who is actively working on/supporting asyncio, I think we need to go through the full PEP process when we want to add new APIs. bpo simply does not provide enough exposure: guys from Twisted and Tornado, for instance, won't see this discussion. I'd be glad to assist you with the PEP though! |
|||
msg294801 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2017-05-30 23:55 | |
On May 30, 2017, at 10:36 PM, Yury Selivanov wrote: >Again, the natural way of something like Controller to end up in asyncio is >to either go through full PEP process, or live some time on PyPI and prove to >be useful. A PEP feels like overkill; we don't require PEPs for every addition to an existing stdlib module or package. My worry too is that a PEP tends to evoke endless bikeshedding. I appreciate that you want to be careful not to saddle asyncio with too much baggage, or that you don't feel Controller is significant enough to generalize and put in the package. Perhaps a middle ground would be to label parts of the asyncio API provisional, and add Controller to that? |
|||
msg294803 - (view) | Author: Yury Selivanov (yselivanov) * ![]() |
Date: 2017-05-31 00:19 | |
> I appreciate that you want to be careful not to saddle asyncio with too much > baggage, or that you don't feel Controller is significant enough to generalize > and put in the package. Perhaps a middle ground would be to label parts of > the asyncio API provisional, and add Controller to that? Thing is, when asyncio was provisional, we still couldn't significantly change it or break it. Never in asyncio stdlib era had we removed or redesigned some APIs. Only small additions and bug fixes. And honestly, maintaining something provisional and changing it in bugfix releases is too much stress: we managed to break `loop.connect_socket` once because nobody tests bugfix RCs. It was broken for ~6 months. IMHO: the design of Controller is currently incomplete (see one of my previous comments). Even in this thread two other core devs raised a question that the API isn't generic enough to be part of asyncio. Right now it's not flexible and tailored for one specific use case. Should the user need slightly more, they will have to copy/paste it, or, worse, inherit from it and use its private APIs. |
|||
msg311558 - (view) | Author: Barry A. Warsaw (barry) * ![]() |
Date: 2018-02-03 14:48 | |
There doesn't seem to be much appetite for this in the stdlib, so closing. It'll just have to live in a third party module. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:58:46 | admin | set | github: 74486 |
2018-02-03 14:48:37 | barry | set | status: open -> closed resolution: wont fix messages: + msg311558 stage: resolved |
2017-05-31 00:19:50 | yselivanov | set | messages: + msg294803 |
2017-05-30 23:55:19 | barry | set | messages: + msg294801 |
2017-05-30 23:10:09 | yselivanov | set | messages: + msg294798 |
2017-05-30 22:36:38 | yselivanov | set | messages: + msg294794 |
2017-05-30 21:57:00 | vstinner | set | messages: + msg294790 |
2017-05-30 16:56:07 | barry | set | messages: + msg294767 |
2017-05-29 23:42:32 | yselivanov | set | messages: + msg294725 |
2017-05-29 15:23:56 | barry | set | messages: + msg294698 |
2017-05-29 07:07:38 | pitrou | set | messages: + msg294675 |
2017-05-29 00:47:21 | barry | set | messages: + msg294666 |
2017-05-28 11:07:59 | pitrou | set | nosy:
+ pitrou, yselivanov, giampaolo.rodola messages: + msg294638 |
2017-05-11 00:26:59 | barry | set | messages: + msg293465 |
2017-05-11 00:09:41 | vstinner | set | nosy:
+ vstinner messages: + msg293464 |
2017-05-09 00:44:57 | barry | set | messages: + msg293264 |
2017-05-08 23:06:28 | njs | set | nosy:
+ njs messages: + msg293260 |
2017-05-07 18:26:25 | barry | set | pull_requests: + pull_request1594 |
2017-05-07 18:24:57 | barry | create |