Skip to content

Commit

Permalink
Add configs from init or env, add pathname configs tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
T4rk1n committed Aug 13, 2018
1 parent cc2b065 commit ccec5e5
Show file tree
Hide file tree
Showing 4 changed files with 232 additions and 11 deletions.
105 changes: 105 additions & 0 deletions dash/_configs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import os

# noinspection PyCompatibility
from . import exceptions
from ._utils import AttributeDict


def env_configs():
"""
Configs from the environ.
:return: A dict with the dash environ vars
"""
return AttributeDict({x: os.getenv(x, os.getenv(x.lower())) for x in (
'DASH_APP_NAME',
'DASH_URL_BASE_PATHNAME',
'DASH_ROUTES_PATHNAME_PREFIX',
'DASH_REQUESTS_PATHNAME_PREFIX',
'DASH_SUPPRESS_CALLBACK_EXCEPTIONS',
'DASH_ASSETS_EXTERNAL_PATH',
'DASH_INCLUDE_ASSETS_FILES'
)})


def choose_config(config_name, init, env, default=None):
if init is not None:
return init

env_value = env.get('DASH_{}'.format(config_name.upper()))
if env_value is None:
return default
return env_value


def pathname_configs(url_base_pathname=None,
routes_pathname_prefix=None,
requests_pathname_prefix=None,
environ_configs=None):
_pathname_config_error_message = '''
{} This is ambiguous.
To fix this, set `routes_pathname_prefix` instead of `url_base_pathname`.
Note that `requests_pathname_prefix` is the prefix for the AJAX calls that
originate from the client (the web browser) and `routes_pathname_prefix` is
the prefix for the API routes on the backend (this flask server).
`url_base_pathname` will set `requests_pathname_prefix` and
`routes_pathname_prefix` to the same value.
If you need these to be different values then you should set
`requests_pathname_prefix` and `routes_pathname_prefix`,
not `url_base_pathname`.
'''
environ_configs = environ_configs or env_configs()

url_base_pathname = choose_config('url_base_pathname',
url_base_pathname,
environ_configs)

routes_pathname_prefix = choose_config('routes_pathname_prefix',
routes_pathname_prefix,
environ_configs)

requests_pathname_prefix = choose_config('requests_pathname_prefix',
requests_pathname_prefix,
environ_configs)

if url_base_pathname is not None and requests_pathname_prefix is not None:
raise exceptions.InvalidConfig(
_pathname_config_error_message.format(
'You supplied `url_base_pathname` and '
'`requests_pathname_prefix`.'
)
)
elif url_base_pathname is not None and routes_pathname_prefix is not None:
raise exceptions.InvalidConfig(
_pathname_config_error_message.format(
'You supplied `url_base_pathname` and '
'`routes_pathname_prefix`.')
)
elif url_base_pathname is not None and routes_pathname_prefix is None:
routes_pathname_prefix = url_base_pathname
elif routes_pathname_prefix is None:
routes_pathname_prefix = '/'

if not routes_pathname_prefix.startswith('/'):
raise exceptions.InvalidConfig(
'`routes_pathname_prefix` needs to start with `/`')
if not routes_pathname_prefix.endswith('/'):
raise exceptions.InvalidConfig(
'`routes_pathname_prefix` needs to end with `/`')

app_name = environ_configs.DASH_APP_NAME

if not requests_pathname_prefix and app_name:
requests_pathname_prefix = '/' + app_name + routes_pathname_prefix
elif requests_pathname_prefix is None:
requests_pathname_prefix = routes_pathname_prefix

if not requests_pathname_prefix.endswith(routes_pathname_prefix):
raise exceptions.InvalidConfig(
'`requests_pathname_prefix` needs to ends with '
'`routes_pathname_prefix`.'
)

return url_base_pathname, routes_pathname_prefix, requests_pathname_prefix

41 changes: 30 additions & 11 deletions dash/dash.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
from ._utils import AttributeDict as _AttributeDict
from ._utils import interpolate_str as _interpolate
from ._utils import format_tag as _format_tag
from . import _configs


_default_index = '''
<!DOCTYPE html>
Expand Down Expand Up @@ -71,14 +73,17 @@ def __init__(
static_folder='static',
assets_folder=None,
assets_url_path='/assets',
include_assets_files=True,
url_base_pathname='/',
requests_pathname_prefix='',
assets_external_path=None,
include_assets_files=None,
url_base_pathname=None,
requests_pathname_prefix=None,
routes_pathname_prefix=None,
compress=True,
meta_tags=None,
index_string=_default_index,
external_scripts=None,
external_stylesheets=None,
suppress_callback_exceptions=None,
**kwargs):

# pylint-disable: too-many-instance-attributes
Expand All @@ -102,16 +107,30 @@ def __init__(
static_folder=self._assets_folder,
static_url_path=assets_url_path))

env_configs = _configs.env_configs()

url_base_pathname, routes_pathname_prefix, requests_pathname_prefix = \
_configs.pathname_configs(
url_base_pathname,
routes_pathname_prefix,
requests_pathname_prefix,
environ_configs=env_configs)

self.url_base_pathname = url_base_pathname
self.config = _AttributeDict({
'suppress_callback_exceptions': False,
'routes_pathname_prefix': url_base_pathname,
'requests_pathname_prefix': requests_pathname_prefix or os.getenv(
'DASH_REQUESTS_PATHNAME_PREFIX',
'/{}'.format(os.environ['DASH_APP_NAME'])
if 'DASH_APP_NAME' in os.environ else '') + url_base_pathname,
'include_assets_files': include_assets_files,
'assets_external_path': '',
'suppress_callback_exceptions': _configs.choose_config(
'suppress_callback_exceptions',
suppress_callback_exceptions, env_configs, False
),
'routes_pathname_prefix': routes_pathname_prefix,
'requests_pathname_prefix': requests_pathname_prefix,
'include_assets_files': _configs.choose_config(
'include_assets_files',
include_assets_files,
env_configs,
True),
'assets_external_path': _configs.choose_config(
'assets_external_path', assets_external_path, env_configs, ''),
})

# list of dependencies
Expand Down
4 changes: 4 additions & 0 deletions dash/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ class PreventUpdate(CallbackException):

class InvalidCallbackReturnValue(CallbackException):
pass


class InvalidConfig(DashException):
pass
93 changes: 93 additions & 0 deletions tests/test_configs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import unittest
# noinspection PyProtectedMember
from dash import _configs
from dash import exceptions as _exc
import os


class MyTestCase(unittest.TestCase):

def setUp(self):
environ = _configs.env_configs()

for k in environ.keys():
if k in os.environ:
os.environ.pop(k)

def test_valid_pathname_prefix_init(self):
_, routes, req = _configs.pathname_configs()

self.assertEqual('/', routes)
self.assertEqual('/', req)

_, routes, req = _configs.pathname_configs(
routes_pathname_prefix='/dash/')

self.assertEqual('/dash/', req)

_, routes, req = _configs.pathname_configs(
requests_pathname_prefix='/my-dash-app/',
)

self.assertEqual(routes, '/')
self.assertEqual(req, '/my-dash-app/')

_, routes, req = _configs.pathname_configs(
routes_pathname_prefix='/dash/',
requests_pathname_prefix='/my-dash-app/dash/'
)

self.assertEqual('/dash/', routes)
self.assertEqual('/my-dash-app/dash/', req)

def test_invalid_pathname_prefix(self):
with self.assertRaises(_exc.InvalidConfig) as context:
_, _, _ = _configs.pathname_configs('/my-path', '/another-path')

self.assertTrue('url_base_pathname' in str(context.exception))

with self.assertRaises(_exc.InvalidConfig) as context:
_, _, _ = _configs.pathname_configs(
url_base_pathname='/invalid',
routes_pathname_prefix='/invalid')

self.assertTrue(str(context.exception).split('.')[0]
.endswith('`routes_pathname_prefix`'))

with self.assertRaises(_exc.InvalidConfig) as context:
_, _, _ = _configs.pathname_configs(
url_base_pathname='/my-path',
requests_pathname_prefix='/another-path')

self.assertTrue(str(context.exception).split('.')[0]
.endswith('`requests_pathname_prefix`'))

with self.assertRaises(_exc.InvalidConfig) as context:
_, _, _ = _configs.pathname_configs('my-path')

self.assertTrue('start with `/`' in str(context.exception))

with self.assertRaises(_exc.InvalidConfig) as context:
_, _, _ = _configs.pathname_configs('/my-path')

self.assertTrue('end with `/`' in str(context.exception))

def test_pathname_prefix_from_environ_app_name(self):
os.environ['DASH_APP_NAME'] = 'my-dash-app'
_, routes, req = _configs.pathname_configs()
self.assertEqual('/my-dash-app/', req)
self.assertEqual('/', routes)

def test_pathname_prefix_environ_routes(self):
os.environ['DASH_ROUTES_PATHNAME_PREFIX'] = '/routes/'
_, routes, req = _configs.pathname_configs()
self.assertEqual('/routes/', routes)

def test_pathname_prefix_environ_requests(self):
os.environ['DASH_REQUESTS_PATHNAME_PREFIX'] = '/requests/'
_, routes, req = _configs.pathname_configs()
self.assertEqual('/requests/', req)


if __name__ == '__main__':
unittest.main()

0 comments on commit ccec5e5

Please sign in to comment.