Repository navigation
Closed
Labels
3.8 (EOL)end of lifeend of lifeinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancementA feature request or enhancement
Description
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = None
closed_at = <Date 2019-05-21.20:13:44.377>
created_at = <Date 2018-09-09.21:57:12.220>
labels = ['interpreter-core', 'type-feature', '3.8']
title = 'implement "Async exec"'
updated_at = <Date 2019-05-22.19:38:51.480>
user = 'https://github.com/Carreau'bugs.python.org fields:
activity = <Date 2019-05-22.19:38:51.480>
actor = 'miss-islington'
assignee = 'none'
closed = True
closed_date = <Date 2019-05-21.20:13:44.377>
closer = 'yselivanov'
components = ['Interpreter Core']
creation = <Date 2018-09-09.21:57:12.220>
creator = 'mbussonn'
dependencies = []
files = []
hgrepos = []
issue_num = 34616
keywords = ['patch']
message_count = 40.0
messages = ['324900', '324915', '324925', '325339', '331525', '331526', '331529', '331531', '331535', '331539', '341202', '341203', '341209', '341222', '341224', '341230', '341232', '341388', '341396', '341409', '341681', '341823', '342598', '342602', '342604', '343089', '343090', '343099', '343109', '343111', '343112', '343113', '343116', '343117', '343118', '343119', '343120', '343121', '343146', '343231']
nosy_count = 12.0
nosy_names = ['brett.cannon', 'vstinner', 'ned.deily', 'njs', 'asvetlov', 'pmpp', 'yselivanov', 'willingc', 'minrk', 'mbussonn', 'miss-islington', 'xtreak']
pr_nums = ['13148', '13473', '13484']
priority = 'normal'
resolution = 'fixed'
stage = 'resolved'
status = 'closed'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue34616'
versions = ['Python 3.8']Metadata
Metadata
Assignees
Labels
3.8 (EOL)end of lifeend of lifeinterpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-featureA feature request or enhancementA feature request or enhancement
Activity
Carreau commentedon Sep 9, 2018
Hi,
This is an issue, prompted by twitter (https://twitter.com/Mbussonn/status/1038866329971961859) and by the imminent release of IPython 7.0 that provides an async REPL to discuss the introducion of something I'll call "Async exec", the exact form can vary, but I believe the name si relatively self explanatory.
The short description would be to allow something akin to
execbut for asynchronous code. Typically for one to be able to write an async-repl in the generic sens that is not say not obviously liked to asyncio.For example IPython 7.0 (current master branch) allow the following:
Sleep is here and example, but you can play with aoihttp, asks, and other library and it "just works". Alternatively when using IPython via Jupyter, you can also schedule background tasks that will execute in the currently running loop.
To reach this, we had to work around a large number of roadblock, and there is a number of missing pieces (or things especially prevented) in core Python we had to work around. To see how we did that see ipython/ipython#11265
The core being if we have a block of async code like
await sleep(0), we need an asynchronous way to exec it without blocking, hence the proposal for async-exec.During the development and test of the above feature of IPython here are some of the challenges we got with top-level async code.
It make sens for a module for this to be invalid syntax, but not in a repl.
Since Python 3.7 we can (at least) compile it to AST, but not to bytecode.
So far in IPython we have to carry-over and recompute whether to actually run the compiled byte code in classical
execor our pseudo async-exec. You may think thatawait exec()always cover the case, but when you are already running under asyncio, you may want to tell user "no you can't run async code", and use the normalexecpath.Have distinction in this
async exec/compilebetween "I am compiling a module", currentlyexecmode for both exec and compile, and a "I'm compiling a multiline interactive statement".Not be coupled to a specific async library.
Allow new AIO library like trio/curio/... to use this.
Note that despite both using IPython, the above cover 2 use cases.
AFAICT, this would also be of potential use for other REPL (Xonsh, Bpython).
I'm happy to give more details, but I think that's a enough of a broad overview, as we should be releasing this in IPython in a few days/week, we will likely have further feedback from a wider range of users that can inform the design.
njsmith commentedon Sep 10, 2018
I think the first thing is to add async "modes" to compile: in particular "async-exec" and "async-single". These would be like the current "exec" and "single" modes respectively, except that they act like the code is inside an "async def", so "await" is allowed, and executing the resulting code object produces a coroutine object that has to be iterated to actually run the code.
I guess we might want "async-eval" too just for completeness, though I'm not currently aware of any use cases for that.
A utility to check whether an AST requires async mode should be fairly straightforward. So if you want to choose on the fly, you would do:
Once you have a code object, I think it's too late: if you use "async-exec" mode to compile a code object that doesn't actually use 'await', then it should still return a coroutine object that needs iterating, etc., just like an 'async def' that has no 'await' in it. So if you want to do this check, the AST phase is the time to do it. Maybe ast.is_ast_async(ast_obj)?
This seems like a separate problem from the async stuff... I'm curious to hear how what distinction you want to make between 'exec' and a new 'multi-single' (?) mode, but maybe that should be a new issue?
Carreau commentedon Sep 10, 2018
Mell, in classical
execthere is always a tension between "this is for a module" and "this is for REPL". We saw that close to 3.7 release where strings literal were moved into the AST Moduledocstringattribute.In IPython[1] we also have to dance to trigger the display hook in a multi-line context by executing each top-level node one by one. So while we are designing a new
async-execwhile not tackle that issue at the same time and cover both use case ? That should let one category of user do the optimization they wish and get aModuleobject, without being slow down by the other.1: https://github.com/ipython/ipython/blob/869480ed70944ca70ad9ed70779b9c3e4320adb7/IPython/core/interactiveshell.py#L3179-L3190
Carreau commentedon Sep 14, 2018
Here is one case we forgot in IPython apparently :
In [1]: x = 1
...: def f():
...: nonlocal x
...: x = 10000
This is not detected as a syntax error, but considered as asyn, we took an approach that prefer false positive (try to run invalid syntax as async) than false negative (reject valid async-code). Add this to the test suite for this feature.
Carreau commentedon Dec 10, 2018
So through time our heuristic to check wether a code should be async or not grew:
https://github.com/ipython/ipython/blob/320d21bf56804541b27deb488871e488eb96929f/IPython/core/async_helpers.py#L94-L165
There also seem to be some code that uses
codeop.compile_commandto figure out wether the user code is valid syntax (or not), so that would need some update too.I'm thinking of submitting a talk at PyCon to explain what we've discover so far in IPython.
pmp-p commentedon Dec 10, 2018
indeed adding async flag to compile and providing some 'aexec' is a very good idea !
*an async repl is really usefull when stuck with a threadless python*
( specific engines, or emscripten cpython )
"top-level async is invalid syntax" :
Rewinding the readline history stack to get code "async'ified" is probably not the best way : readline is specific to some platforms.
see https://github.com/pmp-p/aioprompt for a hack using that.
First raising an exception "top level code is async" and allowing user to get source code from exception would maybe a nice start to an async repl.
Carreau commentedon Dec 10, 2018
In IPython we use
prompt_toolkitwhich does already provide a async readline alternative.Also have a look at https://github.com/ipython/ipython/blob/320d21bf56804541b27deb488871e488eb96929f/IPython/core/interactiveshell.py#L121-L150
Seem to be equivalent to what you aare trying to do with updating your locals here https://github.com/pmp-p/aioprompt/blob/93a25ea8753975be6ed891e8d45f22db91c52200/aioprompt/__init__.py#L78-L94
It just sets the function to not create a new local scope
pmp-p commentedon Dec 10, 2018
i already use prompt_toolkit on droid as it uses concurrent futures for completion and threads are allowed on that platform, and yeah it is quite good.
but no way to use it on emscripten where cpython is 100% async ( it uses dummy_threading to load asyncio ). best you can do is fill an history buffer with the indented input, eval the whole thing when it's done with PyRun_SimpleString.
having cpython storing code until sync/async path can be choosen could save a lot of external hacks with minimal impact on original repl loop, unless somebody is willing to make it *fully* async ( i know i can't ).
The original repl input loop is really not made for async and i don't know if Sylvain Beuclair's work on "emterpreted" cpython covers also python3.
thx for the pointers anyway and your article on async and ast was inspiration.
njsmith commentedon Dec 10, 2018
You totally should!
Or actually there are two options to think about: you can submit a general talk, or submit a talk to the language summit. (Or write two talks and do both, I guess.) They're pretty different – the summit is a more informal thing (no video, smaller room), mostly just core devs, more of a working meeting kind of thing where you can argue about technical details.
Carreau commentedon Dec 10, 2018
Thanks, I may do that then – if a core dev invite me to do so – I wouldn't have dared otherwise. I'm not even sure you can suggest a language summit proposal yet.
For the normal talk proposal here is what I have so far:
https://gist.github.com/Carreau/20881c6c70f1cde9878db7aa247d432a
Carreau commentedon May 1, 2019
Slides and demo (videos) during PyCon2019 Language Summit: https://github.com/Carreau/talks/tree/master/2019-05-01-Language-Summit
One question was how to handle non-asyncio in Core Python, REPL.
My response was to not take care of that in the first time, but provide the building blocks for alternative REPL, in a second time provide an async-input, and a way to register runner for alternative async libraries.
njsmith commentedon May 1, 2019
Yeah, I think this is pretty simple: the runtime/stdlib should provide the primitives to compile top-level async code, get coroutines, etc., and then a REPL like ipython can take care of handing that off to asyncio or whatever library they want.
Maybe in the long run the builtin REPL should get async support "out of the box", but that's much less clear, and anyway we should split that off into a separate issue if we want to discuss it.
async-input isn't even useful for ipython, is it? you use prompt-toolkit :-)
15 remaining items
asvetlov commentedon May 21, 2019
Great!
ned-deily commentedon May 21, 2019
New changeset eca18aa by Ned Deily (Yury Selivanov) in branch 'master':
bpo-34616: Fix code style and unbreak buildbots (GH-13473)
eca18aa
vstinner commentedon May 21, 2019
Would it be possible to document this change in What's New in Python 3.8?
1st1 commentedon May 21, 2019
Yes, Elvis and I will take care of that later.
vstinner commentedon May 21, 2019
Any idea why PR 13148 has been linked to unrelated bugs.python.org issues? I saw 3 of them: bpo-35363, bpo-25234, bpo-33725.
https://mail.python.org/pipermail/python-dev/2019-May/157592.html
vstinner commentedon May 21, 2019
Well, it would be nice to get a first mention before the next release, to see all new shiny Python 3.8 features ;-) The text can be reworded later if needed ;-)
Carreau commentedon May 21, 2019
Could it be due to rebasing and force-pushing ? Cause I did force-push on this branch a couple of times...
Carreau commentedon May 21, 2019
And I'm guessing you will collect what's in NEWS.d ? Otherwise I'm happy to contribute some text. let me know the best way.
vstinner commentedon May 21, 2019
Maybe you used "git merge" and your PR "contained" changes from other issues?
1st1 commentedon May 21, 2019
Would be great if you could make a PR to add an entry to whatsnew/3.8.rst (as Victor suggests)
vstinner commentedon May 21, 2019
One option to document it is to add a new "builtins" section to document the new flag inside "Improved Modules" category:
https://docs.python.org/dev/whatsnew/3.8.html#improved-modules
Carreau commentedon May 21, 2019
I quasi-nerver merge, either
rebase interactiveorreset --hard HEAD... I even proscribed "git pull" from my CLI.. but you know everybody does mistakes.Ok, i'll do this.
Carreau commentedon May 22, 2019
Done in #13484
miss-islington commentedon May 22, 2019
New changeset 2ddbd21 by Miss Islington (bot) (Matthias Bussonnier) in branch 'master':
bpo-34616: Document top level async in whatsnew/3.8. (GH-13484)
2ddbd21