You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[this was originally #79, but that thread got taken over by the discussion of whether we can provide better diagnostics on missing await, so I'm moving the umbrella issue here]
This is currently very rough and needs expanding into something we can actually bring to the Python core team, but so I don't forget:
__iterclose__ (PEP 533) – probably the single most important from a user perspective. Unfortunately appears to be stalled; definitely won't happen for 3.7.
can we do anything about how easy it is to forget an await? In retrospect async functions shouldn't implement __call__ IMO... but probably too late to fix that. Still, it kinda sucks that one of first things in our tutorial is a giant warning about this wart, so worth at least checking if anyone has any ideas... [see Can we make forgetting an await be an error? #79 for discussion]
possibly Result should actually be builtin? I think it would actually really simplify CPython's generator API and implementation. (in particular, unifying send and throw could dramatically simplify the implementation of yield from while fixing some of the weird intractable throw bugs that trio currently has to work around)
speaking of which, straightforward bugs that affect us:
issue29600 (this is the worst; it actually blocks us from implementing some useful API, like an async version of MultiError.catch) (now fixed, thanks @1st1!)
issue29590 – fully worked around inside Trio; still affects other libraries like asyncio, but crossing it off our list
issue29587 – fully worked around inside Trio; still affects other libraries like asyncio, but crossing it off our list
better ergonomics for MultiErrors (catching, printing, rethrowing...). Fundamentally the issue here is that in trio, it's effectively possible to call multiple functions in parallel, so we need a way to handle multiple errors raised in parallel. Some clever hacks let us get a long way, but currently this is really stretching the limits of the assumptions baked into Python's exception handling machinery. There are a number of pieces to this; I'm not sure all of them. But:
no brainer: making traceback objects instantiable or mutable (both we and jinja2 are carrying disgusting code to work around this) – this is bpo-30579
would be nice: attaching attributes to tracebacks (probably: subclassing them)
one use case here is to hide/de-emphasize parts of the traceback that are in trio's guts; I think Nick had a similar use case for wanting a way to hide tracebacks inside the import machinery guts?
better control over implicit exception chaining. here's an example where implicit exception chaining corrupts our exception reporting and there's currently nothing we can do about it:
because Python will overwrite the ValueError's __context__ in the catch's __exit__, even though it's already set. There's no way to stop it. [Well... I guess we could exploit issue29587. But that seems a bit evil?] [Update! I actually did find an effective countermeasure – see Correctly preserve exception __context__ in MultiError.catch #165. It's a little bit gross but it's certainly not the worst thing in the multierror code; not sure whether it's worth trying to get a better solution upstream or not.]
better hooks to control exception printing? This is the biggie – overriding sys.excepthook is really tacky, and has major limitations (e.g. ipython and pytest have their own exception printing code). But it's also the vaguest, because I'm not sure what this would look like
better support for safe KeyboardInterrupt management (in particular for __(a)exit__ blocks, with their currently unfixable race condition). This is complicated and gets into the code of the bytecode interpreter. Some notes:
for sync context managers, SETUP_WITH atomically calls __enter__ + sets up the finally block
for async context managers, the async setup stuff is split over multiple bytecodes, so we lose this guarantee -- it's possible for a KI to arrive in between calling __aenter__ and the SETUP_ASYNC_WITH that pushes the finally block
for sync context managers, WITH_CLEANUP_START atomically calls __exit__
for async context managers, there again are multiple bytecodes (WITH_CLEANUP_START calls __aenter__ (i.e., instantiates the coroutine object), then GET_AWAITABLE calls __await__, then LOAD_CONST to get the None to use as the initial send, then YIELD_FROM to actually run the __aenter__ body
and, of course, even once we enter the __(a)exit__, there's currently no way for that entry to atomically enable KI protection.
so, proposals, I think?:
make entering an __aenter__ or __aexit__ a single bytecode, or otherwise atomic WRT KeyboardInterrupt delivery (now filed as issue29988)
add a field to the stack frame that points to the function object (if any). This avoids circular references (unlike putting it on the code object), would make entry/exit atomic, is much more elegant than the way we currently have to hack everyone's locals dicts, would help other projects like pytest with it's __tracebackhide__ hack, and would enable better introspection in general (right now you can't even print __qualname__ in tracebacks!)
[this was originally #79, but that thread got taken over by the discussion of whether we can provide better diagnostics on missing
await, so I'm moving the umbrella issue here]This is currently very rough and needs expanding into something we can actually bring to the Python core team, but so I don't forget:
__iterclose__(PEP 533) – probably the single most important from a user perspective. Unfortunately appears to be stalled; definitely won't happen for 3.7.can we do anything about how easy it is to forget an await? In retrospect async functions shouldn't implement
__call__IMO... but probably too late to fix that. Still, it kinda sucks that one of first things in our tutorial is a giant warning about this wart, so worth at least checking if anyone has any ideas... [see Can we make forgetting an await be an error? #79 for discussion]possibly
Resultshould actually be builtin? I think it would actually really simplify CPython's generator API and implementation. (in particular, unifyingsendandthrowcould dramatically simplify the implementation ofyield fromwhile fixing some of the weird intractablethrowbugs that trio currently has to work around)speaking of which, straightforward bugs that affect us:
issue29600 (this is the worst; it actually blocks us from implementing some useful API, like an async version of(now fixed, thanks @1st1!)MultiError.catch)issue29590– fully worked around inside Trio; still affects other libraries like asyncio, but crossing it off our listissue29587– fully worked around inside Trio; still affects other libraries like asyncio, but crossing it off our listissue29728(fix merged, thanks @Mariatta!)issue29515– worked around inside Trioissue30038 (makes our test suite flaky on windows – see control-C sometimes getting missed on Windows #119. PR submitted and awaiting review)merged, thanks @Haypo!issue30039 (PR submitted and awaiting review)merged, thanks @1st1!issue30050 - PR submittedmerged, thanks @1st1!bpo-30579 - PR submitted for the most important partmerged!better ergonomics for MultiErrors (catching, printing, rethrowing...). Fundamentally the issue here is that in trio, it's effectively possible to call multiple functions in parallel, so we need a way to handle multiple errors raised in parallel. Some clever hacks let us get a long way, but currently this is really stretching the limits of the assumptions baked into Python's exception handling machinery. There are a number of pieces to this; I'm not sure all of them. But:
no brainer: making traceback objects instantiable or mutable (both we and jinja2 are carrying disgusting code to work around this) – this is bpo-30579
would be nice: attaching attributes to tracebacks (probably: subclassing them)
better control over implicit exception chaining. here's an example where implicit exception chaining corrupts our exception reporting and there's currently nothing we can do about it:
because Python will overwrite the ValueError's
__context__in the catch's__exit__, even though it's already set. There's no way to stop it. [Well... I guess we could exploit issue29587. But that seems a bit evil?] [Update! I actually did find an effective countermeasure – see Correctly preserve exception __context__ in MultiError.catch #165. It's a little bit gross but it's certainly not the worst thing in the multierror code; not sure whether it's worth trying to get a better solution upstream or not.]better hooks to control exception printing? This is the biggie – overriding
sys.excepthookis really tacky, and has major limitations (e.g. ipython and pytest have their own exception printing code). But it's also the vaguest, because I'm not sure what this would look likebetter support for safe
KeyboardInterruptmanagement (in particular for__(a)exit__blocks, with their currently unfixable race condition). This is complicated and gets into the code of the bytecode interpreter. Some notes:SETUP_WITHatomically calls__enter__+ sets up the finally block__aenter__and theSETUP_ASYNC_WITHthat pushes the finally blockWITH_CLEANUP_STARTatomically calls__exit__WITH_CLEANUP_STARTcalls__aenter__(i.e., instantiates the coroutine object), thenGET_AWAITABLEcalls__await__, thenLOAD_CONSTto get theNoneto use as the initialsend, thenYIELD_FROMto actually run the__aenter__body__(a)exit__, there's currently no way for that entry to atomically enable KI protection.__aenter__or__aexit__a single bytecode, or otherwise atomic WRTKeyboardInterruptdelivery (now filed as issue29988)__tracebackhide__hack, and would enable better introspection in general (right now you can't even print__qualname__in tracebacks!)