| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| __all__ = 'run', | ||
|
|
||
| from . import coroutines | ||
| from . import events | ||
|
|
||
|
|
||
| def run(main, *, debug=False): | ||
| """Run a coroutine. | ||
|
|
||
| This function runs the passed coroutine, taking care of | ||
| managing the asyncio event loop and finalizing asynchronous | ||
| generators. | ||
|
|
||
| This function cannot be called when another asyncio event loop is | ||
| running in the same thread. | ||
|
|
||
| If debug is True, the event loop will be run in debug mode. | ||
|
|
||
| This function always creates a new event loop and closes it at the end. | ||
| It should be used as a main entry point for asyncio programs, and should | ||
| ideally only be called once. | ||
|
|
||
| Example: | ||
|
|
||
| async def main(): | ||
| await asyncio.sleep(1) | ||
| print('hello') | ||
|
|
||
| asyncio.run(main()) | ||
| """ | ||
| if events._get_running_loop() is not None: | ||
| raise RuntimeError( | ||
| "asyncio.run() cannot be called from a running event loop") | ||
|
|
||
| if not coroutines.iscoroutine(main): | ||
| raise ValueError("a coroutine was expected, got {!r}".format(main)) | ||
|
|
||
| loop = events.new_event_loop() | ||
| try: | ||
| events.set_event_loop(loop) | ||
|
Comment thread
Copy link
Copy Markdown
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualityset_event_loop() cannot fail (it has a couple asserts but we can neglect this fact).
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualitySure it can. It calls policy.set_event_loop(), and given the fact that users can provide their own buggy policies, we can't really say that set_event_loop is 100% safe.
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityIt's a flag of broken third party loop implementation, not user code problem.
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityWhat's your point? The point of this code is to always close the loop, no matter what. What benefit is there in moving set_event_loop() one line up?
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityAnyways, if you think that the code will read better if set_event_loop is outside of the try block I can move it. We call set_event_loop in the finally block along with the loop.close(), so as you say: if these things are broken then nothing will actually work anyways.
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityWell, it is very minor thing.
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityI'll merge as-is then.
Sorry, something went wrong.
All reactions
|
||
| loop.set_debug(debug) | ||
|
Comment thread
Copy link
Copy Markdown
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityNever fails
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityAgain, it can, if, say, I have a bug in uvloop.Loop.set_debug method. I prefer to assume nothing, when it's possible to set custom policies and custom event loops.
Sorry, something went wrong.
All reactions
|
||
| return loop.run_until_complete(main) | ||
| finally: | ||
| try: | ||
| loop.run_until_complete(loop.shutdown_asyncgens()) | ||
| finally: | ||
| events.set_event_loop(None) | ||
| loop.close() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| import asyncio | ||
| import unittest | ||
|
|
||
| from unittest import mock | ||
|
|
||
|
|
||
| class TestPolicy(asyncio.AbstractEventLoopPolicy): | ||
|
|
||
| def __init__(self, loop_factory): | ||
| self.loop_factory = loop_factory | ||
| self.loop = None | ||
|
|
||
| def get_event_loop(self): | ||
| # shouldn't ever be called by asyncio.run() | ||
| raise RuntimeError | ||
|
|
||
| def new_event_loop(self): | ||
| return self.loop_factory() | ||
|
|
||
| def set_event_loop(self, loop): | ||
| if loop is not None: | ||
| # we want to check if the loop is closed | ||
| # in BaseTest.tearDown | ||
| self.loop = loop | ||
|
|
||
|
|
||
| class BaseTest(unittest.TestCase): | ||
|
|
||
| def new_loop(self): | ||
| loop = asyncio.BaseEventLoop() | ||
| loop._process_events = mock.Mock() | ||
| loop._selector = mock.Mock() | ||
| loop._selector.select.return_value = () | ||
| loop.shutdown_ag_run = False | ||
|
|
||
| async def shutdown_asyncgens(): | ||
| loop.shutdown_ag_run = True | ||
| loop.shutdown_asyncgens = shutdown_asyncgens | ||
|
|
||
| return loop | ||
|
|
||
| def setUp(self): | ||
| super().setUp() | ||
|
|
||
| policy = TestPolicy(self.new_loop) | ||
| asyncio.set_event_loop_policy(policy) | ||
|
|
||
| def tearDown(self): | ||
| policy = asyncio.get_event_loop_policy() | ||
| if policy.loop is not None: | ||
| self.assertTrue(policy.loop.is_closed()) | ||
| self.assertTrue(policy.loop.shutdown_ag_run) | ||
|
|
||
| asyncio.set_event_loop_policy(None) | ||
| super().tearDown() | ||
|
|
||
|
|
||
| class RunTests(BaseTest): | ||
|
|
||
| def test_asyncio_run_return(self): | ||
| async def main(): | ||
| await asyncio.sleep(0) | ||
| return 42 | ||
|
|
||
| self.assertEqual(asyncio.run(main()), 42) | ||
|
|
||
| def test_asyncio_run_raises(self): | ||
| async def main(): | ||
| await asyncio.sleep(0) | ||
| raise ValueError('spam') | ||
|
|
||
| with self.assertRaisesRegex(ValueError, 'spam'): | ||
| asyncio.run(main()) | ||
|
|
||
| def test_asyncio_run_only_coro(self): | ||
| for o in {1, lambda: None}: | ||
| with self.subTest(obj=o), \ | ||
| self.assertRaisesRegex(ValueError, | ||
| 'a coroutine was expected'): | ||
| asyncio.run(o) | ||
|
|
||
| def test_asyncio_run_debug(self): | ||
| async def main(expected): | ||
| loop = asyncio.get_event_loop() | ||
| self.assertIs(loop.get_debug(), expected) | ||
|
|
||
| asyncio.run(main(False)) | ||
| asyncio.run(main(True), debug=True) | ||
|
|
||
| def test_asyncio_run_from_running_loop(self): | ||
| async def main(): | ||
| coro = main() | ||
| try: | ||
| asyncio.run(coro) | ||
| finally: | ||
| coro.close() # Suppress ResourceWarning | ||
|
|
||
| with self.assertRaisesRegex(RuntimeError, | ||
| 'cannot be called from a running'): | ||
| asyncio.run(main()) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Implement asyncio.run(). |
| Back | FazBrowse Home | New Git URL |
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.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualitythis is a bit more concise
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
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.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityWe can replace this while loop with for _ in range(5) and the example will only become clearer.
We'll have a separate pass over asyncio docs before 3.7 is released. We'll try to come up with better examples and improve the current ones. So for now, I'd keep this snippet as is.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.