|
3 | 3 | from __future__ import annotations |
4 | 4 |
|
5 | 5 | import json |
| 6 | +from contextvars import copy_context |
6 | 7 | from typing import TYPE_CHECKING, Any |
7 | 8 |
|
8 | 9 | from dash import get_app |
|
16 | 17 | def run_callback( |
17 | 18 | callback: CallbackAdapter, kwargs: dict[str, Any] |
18 | 19 | ) -> CallbackExecutionResponse: |
19 | | - """Execute a callback via the framework.""" |
20 | | - body = callback.as_callback_body(kwargs) |
| 20 | + """Execute a callback via the framework. |
21 | 21 |
|
| 22 | + Must be called from inside an active request handler; the backend's |
| 23 | + request adapter reads cookies/headers/args from the current request. |
| 24 | + """ |
| 25 | + body = callback.as_callback_body(kwargs) |
22 | 26 | app = get_app() |
23 | | - with app.server.test_request_context( |
24 | | - "/_dash-update-component", |
25 | | - method="POST", |
26 | | - data=json.dumps(body, default=str), |
27 | | - content_type="application/json", |
28 | | - ): |
29 | | - response = app.dispatch() |
30 | | - |
31 | | - response_text = response.get_data(as_text=True) |
32 | | - if response.status_code != 200: |
| 27 | + |
| 28 | + try: |
| 29 | + # pylint: disable=protected-access |
| 30 | + cb_ctx = app._initialize_context(body) |
| 31 | + func = app._prepare_callback(cb_ctx, body) |
| 32 | + args = app._inputs_to_vals(cb_ctx.inputs_list + cb_ctx.states_list) |
| 33 | + ctx = copy_context() |
| 34 | + partial_func = app._execute_callback(func, args, cb_ctx.outputs_list, cb_ctx) |
| 35 | + response_text = ctx.run(partial_func) |
| 36 | + except Exception as err: |
33 | 37 | raise CallbackExecutionError( |
34 | | - f"Callback {callback.output_id} failed " |
35 | | - f"(HTTP {response.status_code}): {response_text[:500]}" |
36 | | - ) |
| 38 | + f"Callback {callback.output_id} failed: {err}" |
| 39 | + ) from err |
37 | 40 |
|
38 | 41 | return json.loads(response_text) |
0 commit comments