Skip to content

Commit 5d3d945

Browse files
authored
Merge pull request #687 from plotly/flag-for-props-check
Flag for props check
2 parents 2e78ef2 + 02a0bb7 commit 5d3d945

File tree

5 files changed

+177
-126
lines changed

5 files changed

+177
-126
lines changed

Diff for: CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## Unreleased
2+
3+
### Added
4+
- Added `dev_tools_props_check` config flag in `app.run_server` to enable or explicitly disable the forthcoming Component Validation in Dash's front-end /(dash-renderer). Note this will only be effective with dash version bumping to React 16 [#687](https://github.com/plotly/dash/pull/687)
5+
16
## [0.41.0] - 2019-04-10
27
### Added
38
- Support for "Clientside Callbacks" - an escape hatch to execute your callbacks in JavaScript instead of Python [#672](https://github.com/plotly/dash/pull/672)

Diff for: dash/_configs.py

+54-49
Original file line numberDiff line numberDiff line change
@@ -5,46 +5,56 @@
55
from ._utils import AttributeDict
66

77

8-
def env_configs():
9-
"""
10-
Configs from the environ.
11-
12-
:return: A dict with the dash environ vars
13-
"""
14-
return AttributeDict({x: os.getenv(x, os.getenv(x.lower())) for x in (
15-
'DASH_APP_NAME',
16-
'DASH_URL_BASE_PATHNAME',
17-
'DASH_ROUTES_PATHNAME_PREFIX',
18-
'DASH_REQUESTS_PATHNAME_PREFIX',
19-
'DASH_SUPPRESS_CALLBACK_EXCEPTIONS',
20-
'DASH_ASSETS_EXTERNAL_PATH',
21-
'DASH_INCLUDE_ASSETS_FILES',
22-
'DASH_COMPONENTS_CACHE_MAX_AGE',
23-
'DASH_INCLUDE_ASSETS_FILES',
24-
'DASH_SERVE_DEV_BUNDLES',
25-
'DASH_DEBUG',
26-
'DASH_HOT_RELOAD',
27-
'DASH_HOT_RELOAD_INTERVAL',
28-
'DASH_HOT_RELOAD_WATCH_INTERVAL',
29-
'DASH_HOT_RELOAD_MAX_RETRY',
30-
'DASH_SILENCE_ROUTES_LOGGING'
31-
)})
32-
33-
34-
def get_config(config_name, init, env, default=None, is_bool=False):
35-
if init is not None:
36-
return init
37-
38-
env_value = env.get('DASH_{}'.format(config_name.upper()))
39-
if env_value is None:
8+
def load_dash_env_vars():
9+
return AttributeDict(
10+
{
11+
var: os.getenv(var, os.getenv(var.lower()))
12+
for var in (
13+
'DASH_APP_NAME',
14+
'DASH_URL_BASE_PATHNAME',
15+
'DASH_ROUTES_PATHNAME_PREFIX',
16+
'DASH_REQUESTS_PATHNAME_PREFIX',
17+
'DASH_SUPPRESS_CALLBACK_EXCEPTIONS',
18+
'DASH_ASSETS_EXTERNAL_PATH',
19+
'DASH_INCLUDE_ASSETS_FILES',
20+
'DASH_COMPONENTS_CACHE_MAX_AGE',
21+
'DASH_INCLUDE_ASSETS_FILES',
22+
'DASH_SERVE_DEV_BUNDLES',
23+
'DASH_DEBUG',
24+
'DASH_DEV_TOOLS_UI',
25+
'DASH_DEV_TOOLS_PROPS_CHECK',
26+
'DASH_HOT_RELOAD',
27+
'DASH_HOT_RELOAD_INTERVAL',
28+
'DASH_HOT_RELOAD_WATCH_INTERVAL',
29+
'DASH_HOT_RELOAD_MAX_RETRY',
30+
'DASH_SILENCE_ROUTES_LOGGING',
31+
)
32+
}
33+
)
34+
35+
36+
DASH_ENV_VARS = load_dash_env_vars()
37+
38+
39+
def get_combined_config(name, val, default=None):
40+
'''consolidate the config with priority from high to low
41+
provided init value > OS environ > default
42+
'''
43+
if val is not None:
44+
return val
45+
46+
env = load_dash_env_vars().get('DASH_{}'.format(name.upper()))
47+
if env is None:
4048
return default
41-
return env_value if not is_bool else env_value.lower() == 'true'
4249

50+
return env.lower() == 'true' if env.lower() in {'true', 'false'} \
51+
else env
4352

44-
def pathname_configs(url_base_pathname=None,
45-
routes_pathname_prefix=None,
46-
requests_pathname_prefix=None,
47-
environ_configs=None):
53+
54+
def pathname_configs(
55+
url_base_pathname=None,
56+
routes_pathname_prefix=None,
57+
requests_pathname_prefix=None):
4858
_pathname_config_error_message = '''
4959
{} This is ambiguous.
5060
To fix this, set `routes_pathname_prefix` instead of `url_base_pathname`.
@@ -58,19 +68,14 @@ def pathname_configs(url_base_pathname=None,
5868
`requests_pathname_prefix` and `routes_pathname_prefix`,
5969
not `url_base_pathname`.
6070
'''
61-
environ_configs = environ_configs or env_configs()
62-
63-
url_base_pathname = get_config('url_base_pathname',
64-
url_base_pathname,
65-
environ_configs)
71+
url_base_pathname = get_combined_config(
72+
'url_base_pathname', url_base_pathname)
6673

67-
routes_pathname_prefix = get_config('routes_pathname_prefix',
68-
routes_pathname_prefix,
69-
environ_configs)
74+
routes_pathname_prefix = get_combined_config(
75+
'routes_pathname_prefix', routes_pathname_prefix)
7076

71-
requests_pathname_prefix = get_config('requests_pathname_prefix',
72-
requests_pathname_prefix,
73-
environ_configs)
77+
requests_pathname_prefix = get_combined_config(
78+
'requests_pathname_prefix', requests_pathname_prefix)
7479

7580
if url_base_pathname is not None and requests_pathname_prefix is not None:
7681
raise exceptions.InvalidConfig(
@@ -99,7 +104,7 @@ def pathname_configs(url_base_pathname=None,
99104
raise exceptions.InvalidConfig(
100105
'`routes_pathname_prefix` needs to end with `/`')
101106

102-
app_name = environ_configs.DASH_APP_NAME
107+
app_name = load_dash_env_vars().DASH_APP_NAME
103108

104109
if not requests_pathname_prefix and app_name:
105110
requests_pathname_prefix = '/' + app_name + routes_pathname_prefix

Diff for: dash/dash.py

+61-55
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
from . import _watch
3636
from ._utils import get_asset_path as _get_asset_path
3737
from ._utils import create_callback_id as _create_callback_id
38-
from . import _configs
38+
from ._configs import (get_combined_config, pathname_configs)
3939

4040
_default_index = '''<!DOCTYPE html>
4141
<html>
@@ -126,33 +126,29 @@ def __init__(
126126
# allow users to supply their own flask server
127127
self.server = server or Flask(name, static_folder=static_folder)
128128

129-
env_configs = _configs.env_configs()
130-
131129
url_base_pathname, routes_pathname_prefix, requests_pathname_prefix = \
132-
_configs.pathname_configs(
130+
pathname_configs(
133131
url_base_pathname,
134132
routes_pathname_prefix,
135-
requests_pathname_prefix,
136-
environ_configs=env_configs)
133+
requests_pathname_prefix
134+
)
137135

138136
self.url_base_pathname = url_base_pathname
139137
self.config = _AttributeDict({
140-
'suppress_callback_exceptions': _configs.get_config(
138+
'suppress_callback_exceptions': get_combined_config(
141139
'suppress_callback_exceptions',
142-
suppress_callback_exceptions, env_configs, False
143-
),
140+
suppress_callback_exceptions,
141+
False),
144142
'routes_pathname_prefix': routes_pathname_prefix,
145143
'requests_pathname_prefix': requests_pathname_prefix,
146-
'include_assets_files': _configs.get_config(
147-
'include_assets_files',
148-
include_assets_files,
149-
env_configs,
150-
True),
151-
'assets_external_path': _configs.get_config(
152-
'assets_external_path', assets_external_path, env_configs, ''),
153-
'components_cache_max_age': int(_configs.get_config(
154-
'components_cache_max_age', components_cache_max_age,
155-
env_configs, 2678400))
144+
'include_assets_files': get_combined_config(
145+
'include_assets_files', include_assets_files, True),
146+
'assets_external_path': get_combined_config(
147+
'assets_external_path', assets_external_path, ''),
148+
'components_cache_max_age': int(get_combined_config(
149+
'components_cache_max_age',
150+
components_cache_max_age,
151+
2678400))
156152
})
157153

158154
assets_blueprint_name = '{}{}'.format(
@@ -248,6 +244,7 @@ def _handle_error(_):
248244
'hot_reload_watch_interval': 0.5,
249245
'hot_reload_max_retry': 8,
250246
'dev_tools_ui': False,
247+
'dev_tools_props_check': False,
251248
})
252249

253250
# add a handler for components suites errors to return 404
@@ -330,8 +327,7 @@ def serve_layout(self):
330327

331328
# TODO - Set browser cache limit - pass hash into frontend
332329
return flask.Response(
333-
json.dumps(layout,
334-
cls=plotly.utils.PlotlyJSONEncoder),
330+
json.dumps(layout, cls=plotly.utils.PlotlyJSONEncoder),
335331
mimetype='application/json'
336332
)
337333

@@ -340,6 +336,7 @@ def _config(self):
340336
'url_base_pathname': self.url_base_pathname,
341337
'requests_pathname_prefix': self.config.requests_pathname_prefix,
342338
'dev_tools_ui': self._dev_tools.dev_tools_ui,
339+
'dev_tools_props_check': self._dev_tools.dev_tools_props_check,
343340
}
344341
if self._dev_tools.hot_reload:
345342
config['hot_reload'] = {
@@ -365,8 +362,7 @@ def serve_reload_hash(self):
365362

366363
def serve_routes(self):
367364
return flask.Response(
368-
json.dumps(self.routes,
369-
cls=plotly.utils.PlotlyJSONEncoder),
365+
json.dumps(self.routes, cls=plotly.utils.PlotlyJSONEncoder),
370366
mimetype='application/json'
371367
)
372368

@@ -1235,9 +1231,11 @@ def _serve_default_favicon(self):
12351231
'Cache-Control': 'public, max-age={}'.format(
12361232
self.config.components_cache_max_age)
12371233
}
1238-
return flask.Response(pkgutil.get_data('dash', 'favicon.ico'),
1239-
headers=headers,
1240-
content_type='image/x-icon')
1234+
return flask.Response(
1235+
pkgutil.get_data('dash', 'favicon.ico'),
1236+
headers=headers,
1237+
content_type='image/x-icon',
1238+
)
12411239

12421240
def get_asset_url(self, path):
12431241
asset = _get_asset_path(
@@ -1250,6 +1248,8 @@ def get_asset_url(self, path):
12501248

12511249
def enable_dev_tools(self,
12521250
debug=False,
1251+
dev_tools_ui=None,
1252+
dev_tools_props_check=None,
12531253
dev_tools_serve_dev_bundles=None,
12541254
dev_tools_hot_reload=None,
12551255
dev_tools_hot_reload_interval=None,
@@ -1267,6 +1267,8 @@ def enable_dev_tools(self,
12671267
Available dev_tools environment variables:
12681268
12691269
- DASH_DEBUG
1270+
- DASH_DEV_TOOLS_UI
1271+
- DASH_DEV_TOOLS_PROPS_CHECK
12701272
- DASH_SERVE_DEV_BUNDLES
12711273
- DASH_HOT_RELOAD
12721274
- DASH_HOT_RELOAD_INTERVAL
@@ -1278,6 +1280,11 @@ def enable_dev_tools(self,
12781280
disabled by the arguments or by environ variables. Available as
12791281
`DASH_DEBUG` environment variable.
12801282
:type debug: bool
1283+
:param dev_tools_ui: Switch the dev tools UI in debugger mode
1284+
:type dev_tools_ui: bool
1285+
:param dev_tools_props_check: Validate the properties of
1286+
the Dash components
1287+
:type dev_tools_props_check: bool
12811288
:param dev_tools_serve_dev_bundles: Serve the dev bundles. Available
12821289
as `DASH_SERVE_DEV_BUNDLES` environment variable.
12831290
:type dev_tools_serve_dev_bundles: bool
@@ -1302,46 +1309,40 @@ def enable_dev_tools(self,
13021309
:type dev_tools_silence_routes_logging: bool
13031310
:return: debug
13041311
"""
1305-
env = _configs.env_configs()
1306-
debug = debug or _configs.get_config('debug', None, env, debug,
1307-
is_bool=True)
1308-
1309-
self._dev_tools.dev_tools_ui = debug
1312+
debug = debug or get_combined_config('debug', None, debug)
13101313

1311-
self._dev_tools['serve_dev_bundles'] = _configs.get_config(
1312-
'serve_dev_bundles', dev_tools_serve_dev_bundles, env,
1313-
default=debug,
1314-
is_bool=True
1314+
self._dev_tools['dev_tools_ui'] = get_combined_config(
1315+
'dev_tools_ui', dev_tools_ui, default=debug
13151316
)
1316-
self._dev_tools['hot_reload'] = _configs.get_config(
1317-
'hot_reload', dev_tools_hot_reload, env,
1318-
default=debug,
1319-
is_bool=True
1317+
self._dev_tools['dev_tools_props_check'] = get_combined_config(
1318+
'dev_tools_props_check', dev_tools_props_check, default=debug
13201319
)
1321-
self._dev_tools['hot_reload_interval'] = int(_configs.get_config(
1322-
'hot_reload_interval', dev_tools_hot_reload_interval, env,
1323-
default=3000
1320+
self._dev_tools['serve_dev_bundles'] = get_combined_config(
1321+
'serve_dev_bundles', dev_tools_serve_dev_bundles, default=debug)
1322+
1323+
self._dev_tools['hot_reload'] = get_combined_config(
1324+
'hot_reload', dev_tools_hot_reload, default=debug)
1325+
self._dev_tools['hot_reload_interval'] = int(get_combined_config(
1326+
'hot_reload_interval', dev_tools_hot_reload_interval, default=3000
13241327
))
13251328
self._dev_tools['hot_reload_watch_interval'] = float(
1326-
_configs.get_config(
1329+
get_combined_config(
13271330
'hot_reload_watch_interval',
13281331
dev_tools_hot_reload_watch_interval,
1329-
env,
13301332
default=0.5
13311333
)
13321334
)
13331335
self._dev_tools['hot_reload_max_retry'] = int(
1334-
_configs.get_config(
1336+
get_combined_config(
13351337
'hot_reload_max_retry',
13361338
dev_tools_hot_reload_max_retry,
1337-
env,
13381339
default=8
13391340
)
13401341
)
1341-
self._dev_tools['silence_routes_logging'] = _configs.get_config(
1342-
'silence_routes_logging', dev_tools_silence_routes_logging, env,
1342+
self._dev_tools['silence_routes_logging'] = get_combined_config(
1343+
'silence_routes_logging',
1344+
dev_tools_silence_routes_logging,
13431345
default=debug,
1344-
is_bool=True,
13451346
)
13461347

13471348
if self._dev_tools.silence_routes_logging:
@@ -1425,6 +1426,8 @@ def delete_resource(resources):
14251426
def run_server(self,
14261427
port=8050,
14271428
debug=False,
1429+
dev_tools_ui=None,
1430+
dev_tools_props_check=None,
14281431
dev_tools_serve_dev_bundles=None,
14291432
dev_tools_hot_reload=None,
14301433
dev_tools_hot_reload_interval=None,
@@ -1440,6 +1443,11 @@ def run_server(self,
14401443
:type port: int
14411444
:param debug: Set the debug mode of flask and enable the dev tools.
14421445
:type debug: bool
1446+
:param dev_tools_ui: Switch the dev tools UI in debugger mode
1447+
:type dev_tools_ui: bool
1448+
:param dev_tools_props_check: Validate the properties of
1449+
the Dash components
1450+
:type dev_tools_props_check: bool
14431451
:param dev_tools_serve_dev_bundles: Serve the dev bundles of components
14441452
:type dev_tools_serve_dev_bundles: bool
14451453
:param dev_tools_hot_reload: Enable the hot reload.
@@ -1458,6 +1466,8 @@ def run_server(self,
14581466
"""
14591467
debug = self.enable_dev_tools(
14601468
debug,
1469+
dev_tools_ui,
1470+
dev_tools_props_check,
14611471
dev_tools_serve_dev_bundles,
14621472
dev_tools_hot_reload,
14631473
dev_tools_hot_reload_interval,
@@ -1483,10 +1493,6 @@ def run_server(self,
14831493
for _ in range(3))
14841494
)
14851495

1486-
self.logger.info(
1487-
'Debugger PIN: %s',
1488-
debugger_pin
1489-
)
1496+
self.logger.info('Debugger PIN: %s', debugger_pin)
14901497

1491-
self.server.run(port=port, debug=debug,
1492-
**flask_run_options)
1498+
self.server.run(port=port, debug=debug, **flask_run_options)

0 commit comments

Comments
 (0)