diff --git a/CHANGELOG.md b/CHANGELOG.md index 4587a023ab..0b20648f55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ -## [UNRELEASED] +## Unreleased ### Changed +- [#722](https://github.com/plotly/dash/pull/722) Assets are served locally by default. Both JS scripts and CSS files are affected. This improves robustness and flexibility in numerous situations, but in certain cases initial loading could be slowed. To restore the previous CDN serving, set `app.scripts.config.serve_locally = False` (and similarly with `app.css`, but this is generally less important). + - Undo/redo toolbar is removed by default, you can enable it with `app=Dash(show_undo_redo=true)`. The CSS hack `._dash-undo-redo:{display:none;}` is no longer needed [#724](https://github.com/plotly/dash/pull/724) ## [0.43.0] - 2019-04-25 diff --git a/dash/dash.py b/dash/dash.py index 60830d94a1..eab4fd7284 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -1379,9 +1379,12 @@ def enable_dev_tools(self, self._watch_thread.daemon = True self._watch_thread.start() - if debug and self._dev_tools.serve_dev_bundles: + if (debug and self._dev_tools.serve_dev_bundles and + not self.scripts.config.serve_locally): # Dev bundles only works locally. self.scripts.config.serve_locally = True + print('WARNING: dev bundles requested with serve_locally=False.\n' + 'This is not supported, switching to serve_locally=True') return debug diff --git a/dash/resources.py b/dash/resources.py index 5ca7b1f70d..87cd8b3ab1 100644 --- a/dash/resources.py +++ b/dash/resources.py @@ -66,10 +66,17 @@ def get_all_resources(self, dev_bundles=False): return self._filter_resources(all_resources, dev_bundles) +# pylint: disable=too-few-public-methods +class _Config: + def __init__(self, infer_from_layout, serve_locally): + self.infer_from_layout = infer_from_layout + self.serve_locally = serve_locally + + class Css: def __init__(self, layout=None): self._resources = Resources('_css_dist', layout) - self._resources.config = self.config + self._resources.config = self.config = _Config(True, True) def _update_layout(self, layout): self._resources.layout = layout @@ -80,16 +87,11 @@ def append_css(self, stylesheet): def get_all_css(self): return self._resources.get_all_resources() - # pylint: disable=no-init, too-few-public-methods - class config: - infer_from_layout = True - serve_locally = False - class Scripts: def __init__(self, layout=None): self._resources = Resources('_js_dist', layout) - self._resources.config = self.config + self._resources.config = self.config = _Config(True, True) def _update_layout(self, layout): self._resources.layout = layout @@ -99,8 +101,3 @@ def append_script(self, script): def get_all_scripts(self, dev_bundles=False): return self._resources.get_all_resources(dev_bundles) - - # pylint: disable=no-init, too-few-public-methods - class config: - infer_from_layout = True - serve_locally = False diff --git a/tests/IntegrationTests.py b/tests/IntegrationTests.py index 13a69f1f53..be7c4bb9f3 100644 --- a/tests/IntegrationTests.py +++ b/tests/IntegrationTests.py @@ -69,10 +69,9 @@ def tearDown(s): s.server_process.terminate() time.sleep(2) - def startServer(s, dash): + def startServer(s, app): def run(): - dash.scripts.config.serve_locally = True - dash.run_server( + app.run_server( port=8050, debug=False, processes=4, diff --git a/tests/test_integration.py b/tests/test_integration.py index ab66dd0206..b49c53c7d2 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -190,7 +190,7 @@ def callback2(value): output2 = self.wait_for_element_by_id('output2') # callback1 runs 4x (initial page load and 3x through send_keys) - self.assertEqual(callback1_count.value, 4) + wait_for(lambda: callback1_count.value == 4) # callback2 is never triggered, even on initial load self.assertEqual(callback2_count.value, 0) @@ -562,7 +562,6 @@ def create_layout(): def test_multi_output(self): app = Dash(__name__) - app.scripts.config.serve_locally = True app.layout = html.Div([ html.Button('OUTPUT', id='output-btn'), @@ -663,7 +662,6 @@ def overlapping_multi_output(n_clicks): def test_multi_output_no_update(self): app = Dash(__name__) - app.scripts.config.serve_locally = True app.layout = html.Div([ html.Button('B', 'btn'), @@ -696,7 +694,6 @@ def show_clicks(n): def test_no_update_chains(self): app = Dash(__name__) - app.scripts.config.serve_locally = True app.layout = html.Div([ dcc.Input(id='a_in', value='a'), diff --git a/tests/test_resources.py b/tests/test_resources.py index 38b4351f2f..62fe0aaeed 100644 --- a/tests/test_resources.py +++ b/tests/test_resources.py @@ -67,7 +67,9 @@ def test_internal(self): assets_ignore='load_after.+.js' ) app.layout = dcc.Markdown() - app.scripts.config.serve_locally = True + + self.assertEqual(app.scripts.config.serve_locally, True) + self.assertEqual(app.css.config.serve_locally, True) with mock.patch('dash.dash.os.stat', return_value=StatMock()): with mock.patch('dash.dash.importlib.import_module',