Skip to content

Commit 4ac19fe

Browse files
delsimMark Gibbs
andauthored
Move to Dash v2.0 (#402)
* Move to Dash v2.0 * Bump version to 2.0.0 * Update readme * Add sandbox attributes to boostrap template * Record environment used to develop v2.0.0 of dpd * Fix development status Co-authored-by: Mark Gibbs <[email protected]>
1 parent c7914b5 commit 4ac19fe

24 files changed

+326
-142
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,7 @@ Taking a very simple example inspired by the excellent [getting started](https:/
9090

9191
```python
9292
import dash
93-
import dash_core_components as dcc
94-
import dash_html_components as html
93+
from dash import dcc, html
9594

9695
from django_plotly_dash import DjangoDash
9796

demo/demo/assets/image_two.png

989 Bytes
Loading

demo/demo/dash_apps.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@
77
#pylint: disable=no-member
88

99
import dash
10-
import dash_core_components as dcc
11-
import dash_html_components as html
10+
from dash import dcc, html
1211
import plotly.graph_objs as go
1312
#import dpd_components as dpd
1413
import numpy as np

demo/demo/plotly_apps.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,8 @@
3434
from django.core.cache import cache
3535

3636
import dash
37+
from dash import dcc, html
3738
from dash.dependencies import MATCH, ALL
38-
import dash_core_components as dcc
39-
import dash_html_components as html
4039

4140
import plotly.graph_objs as go
4241

demo/demo/settings.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,8 @@
196196
# be handled by the Django staticfiles infrastructure
197197

198198
PLOTLY_COMPONENTS = [
199-
'dash_core_components',
200-
'dash_html_components',
199+
201200
'dash_bootstrap_components',
202-
'dash_renderer',
203201
'dpd_components',
204202
'dpd_static_support',
205203
]

dev_requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pytest-cov
1818
python-coveralls
1919
pytz
2020
redis
21+
setuptools
2122
sphinx
2223
sphinx-autobuild
2324
sphinx_rtd_theme

django_plotly_dash/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,7 @@
2929
from .version import __version__
3030

3131
from .dash_wrapper import DjangoDash
32+
33+
# Monkeypatching
34+
35+
import django_plotly_dash._callback

django_plotly_dash/_callback.py

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#
2+
# Monkey patching of register_callback
3+
#
4+
5+
import dash._callback
6+
7+
from dash._callback import (handle_grouped_callback_args,
8+
insert_callback,
9+
NoUpdate,
10+
)
11+
import collections
12+
from functools import wraps
13+
14+
from dash.dependencies import (
15+
handle_callback_args,
16+
handle_grouped_callback_args,
17+
Output,
18+
)
19+
from dash.exceptions import PreventUpdate
20+
21+
from dash._grouping import (
22+
flatten_grouping,
23+
make_grouping_by_index,
24+
grouping_len,
25+
)
26+
from dash._utils import (
27+
create_callback_id,
28+
stringify_id,
29+
to_json,
30+
)
31+
32+
from dash import _validate
33+
34+
35+
def register_callback(
36+
callback_list, callback_map, config_prevent_initial_callbacks, *_args, **_kwargs
37+
):
38+
(
39+
output,
40+
flat_inputs,
41+
flat_state,
42+
inputs_state_indices,
43+
prevent_initial_call,
44+
) = handle_grouped_callback_args(_args, _kwargs)
45+
if isinstance(output, Output):
46+
# Insert callback with scalar (non-multi) Output
47+
insert_output = output
48+
multi = False
49+
else:
50+
# Insert callback as multi Output
51+
insert_output = flatten_grouping(output)
52+
multi = True
53+
54+
output_indices = make_grouping_by_index(output, list(range(grouping_len(output))))
55+
callback_id = insert_callback(
56+
callback_list,
57+
callback_map,
58+
config_prevent_initial_callbacks,
59+
insert_output,
60+
output_indices,
61+
flat_inputs,
62+
flat_state,
63+
inputs_state_indices,
64+
prevent_initial_call,
65+
)
66+
67+
# pylint: disable=too-many-locals
68+
def wrap_func(func):
69+
@wraps(func)
70+
def add_context(*args, **kwargs):
71+
output_spec = kwargs.pop("outputs_list")
72+
_validate.validate_output_spec(insert_output, output_spec, Output)
73+
74+
func_args, func_kwargs = _validate.validate_and_group_input_args(
75+
args, inputs_state_indices
76+
)
77+
78+
func_kwargs = {**func_kwargs,
79+
**kwargs}
80+
81+
# don't touch the comment on the next line - used by debugger
82+
output_value = func(*func_args, **func_kwargs) # %% callback invoked %%
83+
84+
if isinstance(output_value, NoUpdate):
85+
raise PreventUpdate
86+
87+
if not multi:
88+
output_value, output_spec = [output_value], [output_spec]
89+
flat_output_values = output_value
90+
else:
91+
if isinstance(output_value, (list, tuple)):
92+
# For multi-output, allow top-level collection to be
93+
# list or tuple
94+
output_value = list(output_value)
95+
96+
# Flatten grouping and validate grouping structure
97+
flat_output_values = flatten_grouping(output_value, output)
98+
99+
_validate.validate_multi_return(
100+
output_spec, flat_output_values, callback_id
101+
)
102+
103+
component_ids = collections.defaultdict(dict)
104+
has_update = False
105+
for val, spec in zip(flat_output_values, output_spec):
106+
if isinstance(val, NoUpdate):
107+
continue
108+
for vali, speci in (
109+
zip(val, spec) if isinstance(spec, list) else [[val, spec]]
110+
):
111+
if not isinstance(vali, NoUpdate):
112+
has_update = True
113+
id_str = stringify_id(speci["id"])
114+
component_ids[id_str][speci["property"]] = vali
115+
116+
if not has_update:
117+
raise PreventUpdate
118+
119+
response = {"response": component_ids, "multi": True}
120+
121+
try:
122+
jsonResponse = to_json(response)
123+
except TypeError:
124+
_validate.fail_callback_output(output_value, output)
125+
126+
return jsonResponse
127+
128+
callback_map[callback_id]["callback"] = add_context
129+
130+
return func
131+
132+
return wrap_func
133+
134+
135+
dash._callback.register_callback = register_callback

django_plotly_dash/finders.py

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,20 @@ def __init__(self):
5656
except:
5757
components = []
5858

59+
built_ins = [('dash', ['dcc', 'html', 'dash_table', 'deps', 'dash-renderer', 'dash-renderer/build']), ]
60+
5961
for component_name in components:
6062

61-
module = importlib.import_module(component_name)
62-
path_directory = os.path.dirname(module.__file__)
63+
split_name = component_name.split('/')
64+
try:
65+
module_name = ".".join(split_name)
66+
module = importlib.import_module(module_name)
67+
path_directory = os.path.dirname(module.__file__)
68+
except:
69+
module_name = ".".join(split_name[:-1])
70+
module = importlib.import_module(module_name)
71+
path_directory = os.path.join(os.path.dirname(module.__file__),
72+
split_name[-1])
6373

6474
root = path_directory
6575
storage = FileSystemStorage(location=root)
@@ -76,6 +86,29 @@ def __init__(self):
7686
self.storages[component_name] = storage
7787
self.components[path] = component_name
7888

89+
for module_name, component_list in built_ins:
90+
91+
module = importlib.import_module(module_name)
92+
93+
for specific_component in component_list:
94+
95+
path_directory = os.path.join(os.path.dirname(module.__file__),
96+
specific_component)
97+
98+
root = path_directory
99+
component_name = f"{module_name}/{specific_component}"
100+
path = f"dash/component/{component_name}"
101+
102+
if path not in self.components:
103+
104+
storage = FileSystemStorage(location=root)
105+
storage.prefix = path
106+
107+
self.locations.append(component_name)
108+
109+
self.storages[component_name] = storage
110+
self.components[path] = component_name
111+
79112
super().__init__()
80113

81114
def find(self, path, all=False):
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
<div class="embed-responsive embed-responsive-{{aspect}}">
2-
<iframe src="{{app.base_url}}" class="embed-responsive-item"></iframe>
2+
<iframe src="{{app.base_url}}" class="embed-responsive-item" sandbox="allow-downloads allow-scripts allow-same-origin"></iframe>
33
</div>

0 commit comments

Comments
 (0)