Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ dpd-static-support>=0.0.4
grip
pandas
pylint
pytest>=3.6
pytest>=4.6
pytest-django
pytest-cov
python-coveralls
Expand Down
9 changes: 8 additions & 1 deletion django_plotly_dash/dash_wrapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import inspect

from dash import Dash
from dash._utils import split_callback_id
from flask import Flask

from django.urls import reverse
Expand Down Expand Up @@ -288,7 +289,9 @@ def __init__(self):
def after_request(self, *args, **kwargs):
pass
def errorhandler(self, *args, **kwargs): # pylint: disable=no-self-use
return args[0]
def eh_func(f):
return args[0]
return eh_func
def add_url_rule(self, *args, **kwargs):
route = kwargs['endpoint']
self.endpoints[route] = kwargs
Expand Down Expand Up @@ -555,6 +558,10 @@ def dispatch_with_args(self, body, argMap):
if da:
da.update_current_state(c['id'], c['property'], v)

# Dash 1.11 introduces a set of outputs
outputs_list = body.get('outputs') or split_callback_id(output)
argMap['outputs_list'] = outputs_list

# Special: intercept case of insufficient arguments
# This happens when a propery has been updated with a pipe component
# TODO see if this can be attacked from the client end
Expand Down
35 changes: 25 additions & 10 deletions django_plotly_dash/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

#pylint: disable=bare-except


def test_dash_app():
'Test the import and formation of the dash app orm wrappers'

Expand All @@ -42,6 +43,7 @@ def test_dash_app():
assert stateless_a.app_name
assert str(stateless_a) == stateless_a.app_name


def test_util_error_cases(settings):
'Test handling of missing settings'

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


def test_demo_routing():
'Test configuration options for the demo'

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


def test_local_serving(settings):
'Test local serve settings'

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


@pytest.mark.django_db
def test_direct_access(client):
'Check direct use of a stateless application using demo test data'
Expand Down Expand Up @@ -106,6 +111,7 @@ def test_direct_access(client):

assert did_fail


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

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

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


@pytest.mark.django_db
def test_injection_app_access(client):
'Check direct use of a stateless application using demo test data'
Expand Down Expand Up @@ -160,6 +167,7 @@ def test_injection_app_access(client):

assert did_fail


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


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

response = client.post(url, json.dumps({'output':{'id':'test-output-div', 'property':'children'},
response = client.post(url, json.dumps({#'output':{'id':'test-output-div', 'property':'children'},
'output': "test-output-div.children",
'inputs':[{'id':'my-dropdown1',
'property':'value',
'value':'TestIt'},
]}), content_type="application/json")

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

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

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

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

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

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

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

have_thrown = False

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

response3 = client.post(url, json.dumps({'output':{'id':'test-output-div2', 'property':'children'},
response3 = client.post(url, json.dumps({'output': 'test-output-div2.children',
'inputs':[{'id':'my-dropdown2',
'property':'value',
'value':'TestIt'},
]}), content_type="application/json")
rStart3 = b'{"response": {"props": {"children":'
rStart3 = b'{"response": {"test-output-div2": {"children": [{"props": {"children": ["You have '

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

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


@pytest.mark.django_db
def test_argument_settings(settings, client):
'Test the setting that controls how initial arguments are propagated through to the dash app'
Expand Down Expand Up @@ -308,6 +319,7 @@ def test_argument_settings(settings, client):
assert store_initial_arguments(client, None) is None
assert get_initial_arguments(client, None) is None


def test_stateless_lookup_noop():
'Test no-op stateless lookup'

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


def test_middleware_artifacts():
'Import and vaguely exercise middleware objects'

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

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


def test_finders():
'Import and vaguely exercise staticfiles finders'

Expand All @@ -347,6 +361,7 @@ def test_finders():
assert dadf is not None
assert daf is not None


@pytest.mark.django_db
def test_app_loading(client):

Expand Down
2 changes: 1 addition & 1 deletion django_plotly_dash/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@

'''

__version__ = "1.3.1"
__version__ = "1.4.0"
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
dash<1.11
dash-core-components==1.9.0
dash>=1.11
dash-core-components
dash-html-components
dash-renderer==1.3.0
dash-renderer
plotly
dpd-components

Expand Down
6 changes: 3 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@
'Documentation': 'http://django-plotly-dash.readthedocs.io/',
},
install_requires = ['plotly',
'dash<1.11',
'dash-core-components==1.9.0',
'dash>=1.11',
'dash-core-components',
'dash-html-components',
'dash-renderer==1.3.0',
'dash-renderer',
'dpd-components',
'Django>=3',
'Flask>=1.0.2'],
Expand Down