Skip to content

Commit 844fe40

Browse files
delsimMark Gibbs
andauthored
Add output_list to callbacks for compatibility with Dash 1.11 (#244)
* First steps towards working with dash 1.11 by adding outputs_list to callback arguments * Set minimum version level for dash to 1.11 * Bump version to 1.4.0 Co-authored-by: Mark Gibbs <mark@gibbs.consulting>
1 parent bd1fb7e commit 844fe40

File tree

6 files changed

+41
-19
lines changed

6 files changed

+41
-19
lines changed

dev_requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dpd-static-support>=0.0.4
1111
grip
1212
pandas
1313
pylint
14-
pytest>=3.6
14+
pytest>=4.6
1515
pytest-django
1616
pytest-cov
1717
python-coveralls

django_plotly_dash/dash_wrapper.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import inspect
3030

3131
from dash import Dash
32+
from dash._utils import split_callback_id
3233
from flask import Flask
3334

3435
from django.urls import reverse
@@ -288,7 +289,9 @@ def __init__(self):
288289
def after_request(self, *args, **kwargs):
289290
pass
290291
def errorhandler(self, *args, **kwargs): # pylint: disable=no-self-use
291-
return args[0]
292+
def eh_func(f):
293+
return args[0]
294+
return eh_func
292295
def add_url_rule(self, *args, **kwargs):
293296
route = kwargs['endpoint']
294297
self.endpoints[route] = kwargs
@@ -555,6 +558,10 @@ def dispatch_with_args(self, body, argMap):
555558
if da:
556559
da.update_current_state(c['id'], c['property'], v)
557560

561+
# Dash 1.11 introduces a set of outputs
562+
outputs_list = body.get('outputs') or split_callback_id(output)
563+
argMap['outputs_list'] = outputs_list
564+
558565
# Special: intercept case of insufficient arguments
559566
# This happens when a propery has been updated with a pipe component
560567
# TODO see if this can be attacked from the client end

django_plotly_dash/tests.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#pylint: disable=bare-except
3434

35+
3536
def test_dash_app():
3637
'Test the import and formation of the dash app orm wrappers'
3738

@@ -42,6 +43,7 @@ def test_dash_app():
4243
assert stateless_a.app_name
4344
assert str(stateless_a) == stateless_a.app_name
4445

46+
4547
def test_util_error_cases(settings):
4648
'Test handling of missing settings'
4749

@@ -61,13 +63,15 @@ def test_util_error_cases(settings):
6163
assert http_endpoint("fred") == '^dpd/views/fred/$'
6264
assert not insert_demo_migrations()
6365

66+
6467
def test_demo_routing():
6568
'Test configuration options for the demo'
6669

6770
from django_plotly_dash.util import pipe_ws_endpoint_name, insert_demo_migrations
6871
assert pipe_ws_endpoint_name() == 'ws/channel'
6972
assert insert_demo_migrations()
7073

74+
7175
def test_local_serving(settings):
7276
'Test local serve settings'
7377

@@ -76,6 +80,7 @@ def test_local_serving(settings):
7680
assert static_asset_root() == 'dpd/assets'
7781
assert full_asset_path('fred.jim', 'harry') == 'dpd/assets/fred/jim/harry'
7882

83+
7984
@pytest.mark.django_db
8085
def test_direct_access(client):
8186
'Check direct use of a stateless application using demo test data'
@@ -106,6 +111,7 @@ def test_direct_access(client):
106111

107112
assert did_fail
108113

114+
109115
@pytest.mark.django_db
110116
def test_updating(client):
111117
'Check updating of an app using demo test data'
@@ -118,7 +124,7 @@ def test_updating(client):
118124
('', {'ident':'simpleexample-1'}),]:
119125
url = reverse('the_django_plotly_dash:%s%s' % (prefix, route_name), kwargs=arg_map)
120126

121-
response = client.post(url, json.dumps({'output':{'id':'output-size', 'property':'children'},
127+
response = client.post(url, json.dumps({'output': 'output-size.children',
122128
'inputs':[{'id':'dropdown-color',
123129
'property':'value',
124130
'value':'blue'},
@@ -127,9 +133,10 @@ def test_updating(client):
127133
'value':'medium'},
128134
]}), content_type="application/json")
129135

130-
assert response.content == b'{"response": {"props": {"children": "The chosen T-shirt is a medium blue one."}}}'
136+
assert response.content == b'{"response": {"output-size": {"children": "The chosen T-shirt is a medium blue one."}}, "multi": true}'
131137
assert response.status_code == 200
132138

139+
133140
@pytest.mark.django_db
134141
def test_injection_app_access(client):
135142
'Check direct use of a stateless application using demo test data'
@@ -160,6 +167,7 @@ def test_injection_app_access(client):
160167

161168
assert did_fail
162169

170+
163171
@pytest.mark.django_db
164172
def test_injection_updating_multiple_callbacks(client):
165173
'Check updating of an app using demo test data for multiple callbacks'
@@ -192,6 +200,7 @@ def test_injection_updating_multiple_callbacks(client):
192200
assert 'children' in resp_detail['output-two']
193201
assert resp_detail['output-two']['children'] == "Output 2: 10 purple-ish yellow with a hint of greeny orange"
194202

203+
195204
@pytest.mark.django_db
196205
def test_injection_updating(client):
197206
'Check updating of an app using demo test data'
@@ -203,13 +212,14 @@ def test_injection_updating(client):
203212
for prefix, arg_map in [('app-', {'ident':'dash_example_1'}),]:
204213
url = reverse('the_django_plotly_dash:%s%s' % (prefix, route_name), kwargs=arg_map)
205214

206-
response = client.post(url, json.dumps({'output':{'id':'test-output-div', 'property':'children'},
215+
response = client.post(url, json.dumps({#'output':{'id':'test-output-div', 'property':'children'},
216+
'output': "test-output-div.children",
207217
'inputs':[{'id':'my-dropdown1',
208218
'property':'value',
209219
'value':'TestIt'},
210220
]}), content_type="application/json")
211221

212-
rStart = b'{"response": {"props": {"children":'
222+
rStart = b'{"response": {"test-output-div": {"children": [{"props": {"id": "line-area-graph2"'
213223

214224
assert response.content[:len(rStart)] == rStart
215225
assert response.status_code == 200
@@ -221,27 +231,27 @@ def test_injection_updating(client):
221231
'value':'TestIt'},
222232
]}), content_type="application/json")
223233

224-
rStart = b'{"response": {"props": {"children":'
234+
rStart = b'{"response": {"test-output-div": {"children": [{"props": {"id": "line-area-graph2"'
225235

226236
assert response.content[:len(rStart)] == rStart
227237
assert response.status_code == 200
228238

229-
# Second variant has a single-entry mulitple property output
239+
# Second variant has a single-entry mulitple property output
230240
response = client.post(url, json.dumps({'output':'..test-output-div.children..',
231241
'inputs':[{'id':'my-dropdown1',
232242
'property':'value',
233243
'value':'TestIt'},
234244
]}), content_type="application/json")
235245

236-
rStart = b'{"response": {"props": {"children":'
246+
rStart = b'{"response": {"test-output-div": {"children": {"props": {"id": "line-area-graph2"'
237247

238248
assert response.content[:len(rStart)] == rStart
239249
assert response.status_code == 200
240250

241251
have_thrown = False
242252

243253
try:
244-
client.post(url, json.dumps({'output':{'id':'test-output-div2', 'property':'children'},
254+
client.post(url, json.dumps({'output': 'test-output-div2.children',
245255
'inputs':[{'id':'my-dropdown2',
246256
'property':'value',
247257
'value':'TestIt'},
@@ -255,18 +265,19 @@ def test_injection_updating(client):
255265
session['django_plotly_dash'] = {'django_to_dash_context': 'Test 789 content'}
256266
session.save()
257267

258-
response3 = client.post(url, json.dumps({'output':{'id':'test-output-div2', 'property':'children'},
268+
response3 = client.post(url, json.dumps({'output': 'test-output-div2.children',
259269
'inputs':[{'id':'my-dropdown2',
260270
'property':'value',
261271
'value':'TestIt'},
262272
]}), content_type="application/json")
263-
rStart3 = b'{"response": {"props": {"children":'
273+
rStart3 = b'{"response": {"test-output-div2": {"children": [{"props": {"children": ["You have '
264274

265275
assert response3.content[:len(rStart3)] == rStart3
266276
assert response3.status_code == 200
267277

268278
assert response3.content.find(b'Test 789 content') > 0
269279

280+
270281
@pytest.mark.django_db
271282
def test_argument_settings(settings, client):
272283
'Test the setting that controls how initial arguments are propagated through to the dash app'
@@ -308,6 +319,7 @@ def test_argument_settings(settings, client):
308319
assert store_initial_arguments(client, None) is None
309320
assert get_initial_arguments(client, None) is None
310321

322+
311323
def test_stateless_lookup_noop():
312324
'Test no-op stateless lookup'
313325

@@ -318,6 +330,7 @@ def test_stateless_lookup_noop():
318330
with pytest.raises(ImportError):
319331
lh_hook("not an app")
320332

333+
321334
def test_middleware_artifacts():
322335
'Import and vaguely exercise middleware objects'
323336

@@ -334,6 +347,7 @@ def test_middleware_artifacts():
334347

335348
assert cc._encode("fred") == b'fred'
336349

350+
337351
def test_finders():
338352
'Import and vaguely exercise staticfiles finders'
339353

@@ -347,6 +361,7 @@ def test_finders():
347361
assert dadf is not None
348362
assert daf is not None
349363

364+
350365
@pytest.mark.django_db
351366
def test_app_loading(client):
352367

django_plotly_dash/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@
2323
2424
'''
2525

26-
__version__ = "1.3.1"
26+
__version__ = "1.4.0"

requirements.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
dash<1.11
2-
dash-core-components==1.9.0
1+
dash>=1.11
2+
dash-core-components
33
dash-html-components
4-
dash-renderer==1.3.0
4+
dash-renderer
55
plotly
66
dpd-components
77

setup.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,10 @@
4141
'Documentation': 'http://django-plotly-dash.readthedocs.io/',
4242
},
4343
install_requires = ['plotly',
44-
'dash<1.11',
45-
'dash-core-components==1.9.0',
44+
'dash>=1.11',
45+
'dash-core-components',
4646
'dash-html-components',
47-
'dash-renderer==1.3.0',
47+
'dash-renderer',
4848
'dpd-components',
4949
'Django>=3',
5050
'Flask>=1.0.2'],

0 commit comments

Comments
 (0)