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
In a large codebase, you're going to have some functions which are slow, and so you don't want them to be called from an async task (without using trio.to_thread.run_sync(slow_fn), anyway). flake8-trio's TRIO200 error can help find direct calls, but indirect calls are really hard to find via static analysis.
As I mentioned in my PyCon talk, and work we've implemented a decorator to mark sync functions which can be called in a sync context, but must be delegated to a worker thread instead of being called in an async context - no matter how many sync functions are in the intermediate call chain. Simple implementation:
defnot_in_async_task(fn):
"""Decorator for sync functions which should not be called in an async context. <detailed docstring here> """@functools.wraps(fn)defdecorator(*args, **kwargs):
try:
# Identical logic to trio.lowlevel.current_task()GLOBAL_RUN_CONTEXT.taskexceptAttributeError:
passelse:
raiseRuntimeError(
f"{fn.__name__} should not be called in an async context. "f"Use an async alternative, or trio.to_thread.run_sync({fn.__name__})."
)
returnfn(*args, *kwargs)
returndecorator
Should we include this in trio itself? I've certainly found the pattern useful, and upstreaming it would encourage wider use of the pattern. On the other hand it's not entirely clear where this would fit, and it's neither hard to implement nor something which benefits much from standardization.
The text was updated successfully, but these errors were encountered:
Perhaps the more fundamental primitive here is trio.in_trio_context(), which returns a bool. You can write it yourself using only public APIs, but it's weird:
The private implementation could check for the existence of GLOBAL_RUN_CONTEXT.runner.
(There is a subtle difference between checking for runner and checking for task: the former exists even in Trio context outside of a task, which you can observe in abort_fns and instrument calls. I think the runner version is more correct for this need.)
In a large codebase, you're going to have some functions which are slow, and so you don't want them to be called from an async task (without using
trio.to_thread.run_sync(slow_fn)
, anyway).flake8-trio
'sTRIO200
error can help find direct calls, but indirect calls are really hard to find via static analysis.As I mentioned in my PyCon talk, and work we've implemented a decorator to mark sync functions which can be called in a sync context, but must be delegated to a worker thread instead of being called in an async context - no matter how many sync functions are in the intermediate call chain. Simple implementation:
Should we include this in
trio
itself? I've certainly found the pattern useful, and upstreaming it would encourage wider use of the pattern. On the other hand it's not entirely clear where this would fit, and it's neither hard to implement nor something which benefits much from standardization.The text was updated successfully, but these errors were encountered: