Skip to content

Commit

Permalink
Merge pull request #342 from emilhe/blocking_callback_wildcard
Browse files Browse the repository at this point in the history
Preparing 1.0.18 release
  • Loading branch information
emilhe authored Jul 15, 2024
2 parents 4a460a1 + 8d38b01 commit 59a2443
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 7 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,5 @@ NAMESPACE
DESCRIPTION
jsconfig.json
tmp**.py

nodesource_setup.sh
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

All notable changes to this project will be documented in this file.

## [1.0.18] - 15-07-24

### Changed

- Fix bug in `BlockingCallbackTransform` which occurred when a multi-output was targeted (i.e. using the `ALL` wildcard)

## [1.0.17] - 28-06-24

### Added
Expand Down
15 changes: 14 additions & 1 deletion dash_extensions/enrich.py
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,7 @@ def decorated_function(*args, **kwargs):
outputs = f(*args, **kwargs)
except Exception:
logging.exception(f"Exception raised in blocking callback [{f.__name__}]")
outputs = no_update if single_output else [no_update] * num_outputs
outputs = _determine_outputs(single_output)

return _append_output(outputs, datetime.utcnow().timestamp(), single_output, out_flex_key)

Expand All @@ -694,6 +694,19 @@ def decorated_function(*args, **kwargs):
return wrapper


def _determine_outputs(single_output: bool):
output_spec = dash.callback_context.outputs_list[:-1]
if single_output:
return [no_update] * len(output_spec[0]) if isinstance(output_spec[0], list) else no_update
outputs = []
for entry in output_spec:
if isinstance(entry, list):
outputs.append([dash.no_update] * len(entry))
else:
outputs.append(dash.no_update)
return outputs


# endregion

# region Log transform
Expand Down
6 changes: 3 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "dash-extensions",
"version": "1.0.17",
"version": "1.0.18",
"description": "Extensions for Plotly Dash.",
"main": "build/index.js",
"scripts": {
Expand Down Expand Up @@ -62,4 +62,4 @@
"node": ">=8.11.0",
"npm": ">=6.1.0"
}
}
}
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "dash-extensions"
version = "1.0.17"
version = "1.0.18"
description = "Extensions for Plotly Dash."
authors = ["emher <[email protected]>"]
license = "MIT"
Expand Down
39 changes: 39 additions & 0 deletions tests/test_enrich.py
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,45 @@ def update(tick):
assert dash_duo.find_element("#log").text == msg


@pytest.mark.parametrize(
"args, kwargs, port",
[
([Output(dict(type="log", index=ALL), "children"), Input("trigger", "n_intervals")], dict(), 4757),
(
[],
dict(
output=[Output(dict(type="log", index=ALL), "children")],
inputs=dict(tick=Input("trigger", "n_intervals")),
),
4758,
),
],
)
def test_blocking_callback_wildcard(dash_duo, args, kwargs, port):
app = DashProxy(transforms=[BlockingCallbackTransform(timeout=5)])
app.layout = html.Div(
[html.Div(id=dict(type="log", index=i)) for i in range(5)] + [dcc.Interval(id="trigger", interval=500)]
)
msg = "Hello world!"

@app.callback(*args, **kwargs, blocking=True)
def update(tick):
print(tick)
if tick is None:
raise PreventUpdate
time.sleep(1)
return [msg] * 5

# Check that stuff works. It doesn't using a normal Dash object.
dash_duo.start_server(app, port=port)
selector = _css_selector(dict(type="log", index=0))
dash_duo.wait_for_text_to_equal(selector, msg, timeout=5)
assert dash_duo.find_element(selector).text == msg
# Check that we didn't get any errors.
logs = [entry for entry in dash_duo.driver.get_log("browser") if entry["timestamp"] > dash_duo._last_ts]
assert len([l for l in logs if "INTERNAL SERVER ERROR" in l["message"]]) == 0


def test_blocking_callback_transform_final_invocation(dash_duo):
app = DashProxy(transforms=[BlockingCallbackTransform(timeout=5)])
app.layout = html.Div([html.Div(id="log"), dcc.Input(id="input")])
Expand Down

0 comments on commit 59a2443

Please sign in to comment.