Problem
The public checks API is async-only. In a normal Python script, users must write asyncio.run(scenario.run()) (and the same applies to Suite and TestCase). This is boilerplate for a common synchronous entry point.
Proposed change
Add run_sync(...) to the public, user-facing runnable types in giskard-checks:
Keep the existing async run(...) API unchanged. Use one shared internal helper or mixin so the loop-detection behavior and error message stay consistent.
Example:
result = scenario.run_sync()
results = suite.run_sync(parallel=True, verbose=False)
Required behavior
- In a plain synchronous script or synchronous test,
run_sync(*args, **kwargs) returns the same result as asyncio.run(self.run(*args, **kwargs)).
- It forwards all positional and keyword arguments exactly to
run.
- It must work from a non-main thread that has no running event loop.
- If called while an asyncio event loop is already running (Jupyter/IPython notebooks, async pytest tests, async web handlers, or an
async def function), it must raise a clear RuntimeError that tells the user to call await obj.run(...) instead. It must not patch, nest, stop, or run the existing loop in another thread.
- Do not add
nest_asyncio or another runtime dependency.
Docs and tests
-
Update the checks README next to the current async script example. Show both forms:
# Script / no running event loop
result = scenario.run_sync()
# Notebook, pytest async test, or async function
result = await scenario.run()
-
Add unit tests for each supported type: successful synchronous execution, argument forwarding, result/exception propagation, and the active-loop error path.
Out of scope
- Do not change
run() to be synchronous.
- Do not try to make synchronous blocking calls work inside a running loop.
- Do not expand this issue to low-level
Check.run() or agent workflow/tool APIs; those may need a separate API-design decision.
Problem
The public checks API is async-only. In a normal Python script, users must write
asyncio.run(scenario.run())(and the same applies toSuiteandTestCase). This is boilerplate for a common synchronous entry point.Proposed change
Add
run_sync(...)to the public, user-facing runnable types ingiskard-checks:ScenarioSuiteTestCaseKeep the existing async
run(...)API unchanged. Use one shared internal helper or mixin so the loop-detection behavior and error message stay consistent.Example:
Required behavior
run_sync(*args, **kwargs)returns the same result asasyncio.run(self.run(*args, **kwargs)).run.async deffunction), it must raise a clearRuntimeErrorthat tells the user to callawait obj.run(...)instead. It must not patch, nest, stop, or run the existing loop in another thread.nest_asyncioor another runtime dependency.Docs and tests
Update the checks README next to the current async script example. Show both forms:
Add unit tests for each supported type: successful synchronous execution, argument forwarding, result/exception propagation, and the active-loop error path.
Out of scope
run()to be synchronous.Check.run()or agent workflow/tool APIs; those may need a separate API-design decision.