diff --git a/.circleci/config.yml b/.circleci/config.yml index 60d68cbdae..f91a8a1edb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -35,25 +35,12 @@ jobs: paths: - "venv" - - run: - name: Run lint - command: | - . venv/bin/activate - pylint dash setup.py --rcfile=$PYLINTRC - pylint tests -d all -e C0410,C0411,C0412,C0413,W0109 - flake8 dash setup.py - flake8 --ignore=E123,E126,E501,E722,E731,F401,F841,W503,W504 --exclude=metadata_test.py tests - - run: name: Run tests command: | . venv/bin/activate python --version - python -m unittest tests.development.test_base_component - python -m unittest tests.development.test_component_loader - python -m unittest tests.test_integration - python -m unittest tests.test_resources - python -m unittest tests.test_configs + ./test.sh "python-3.6": <<: *test-template @@ -80,4 +67,4 @@ workflows: jobs: - "python-2.7" - "python-3.6" - - "python-3.7" \ No newline at end of file + - "python-3.7" diff --git a/.circleci/requirements/dev-requirements-py37.txt b/.circleci/requirements/dev-requirements-py37.txt index 5df4164755..f23f28d4a7 100644 --- a/.circleci/requirements/dev-requirements-py37.txt +++ b/.circleci/requirements/dev-requirements-py37.txt @@ -2,7 +2,7 @@ dash_core_components>=0.40.2 dash_html_components==0.12.0rc3 dash-flow-example==0.0.3 dash-dangerously-set-inner-html -dash_renderer +git+git://github.com/plotly/dash-renderer@master#egg=dash_renderer percy selenium mock diff --git a/.circleci/requirements/dev-requirements.txt b/.circleci/requirements/dev-requirements.txt index 961c452091..dce645d828 100644 --- a/.circleci/requirements/dev-requirements.txt +++ b/.circleci/requirements/dev-requirements.txt @@ -2,7 +2,7 @@ dash_core_components>=0.40.2 dash_html_components>=0.12.0rc3 dash_flow_example==0.0.3 dash-dangerously-set-inner-html -dash_renderer +git+git://github.com/plotly/dash-renderer@master#egg=dash_renderer percy selenium mock diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a48a4778a..094305598d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## Unreleased +## Removed +- Removed support for `Event` system. Use event properties instead, for example the `n_clicks` property instead of the `click` event, see [#531](https://github.com/plotly/dash/issues/531) for details. `dash_renderer` MUST be upgraded to >=0.17.0 together with this, and it is recommended to update `dash_core_components` to >=0.43.0 and `dash_html_components` to >=0.14.0. [#550](https://github.com/plotly/dash/pull/550) + ## [0.35.3] - 2019-01-23 ## Fixed - Asset blueprint takes routes prefix into it's static path. [#547](https://github.com/plotly/dash/pull/547) diff --git a/dash/dash.py b/dash/dash.py index e8859e93a5..eb30b2a233 100644 --- a/dash/dash.py +++ b/dash/dash.py @@ -15,13 +15,14 @@ from functools import wraps -import plotly -import dash_renderer import flask from flask import Flask, Response from flask_compress import Compress -from .dependencies import Event, Input, Output, State +import plotly +import dash_renderer + +from .dependencies import Input, Output, State from .resources import Scripts, Css from .development.base_component import Component from . import exceptions @@ -622,7 +623,6 @@ def dependencies(self): }, 'inputs': v['inputs'], 'state': v['state'], - 'events': v['events'] } for k, v in self.callback_map.items() ]) @@ -633,7 +633,7 @@ def react(self, *args, **kwargs): 'Use `callback` instead. `callback` has a new syntax too, ' 'so make sure to call `help(app.callback)` to learn more.') - def _validate_callback(self, output, inputs, state, events): + def _validate_callback(self, output, inputs, state): # pylint: disable=too-many-branches layout = self._cached_layout or self._layout_value() @@ -652,8 +652,7 @@ def _validate_callback(self, output, inputs, state, events): for args, obj, name in [([output], Output, 'Output'), (inputs, Input, 'Input'), - (state, State, 'State'), - (events, Event, 'Event')]: + (state, State, 'State')]: if not isinstance(args, list): raise exceptions.IncorrectTypeException( @@ -721,32 +720,20 @@ def _validate_callback(self, output, inputs, state, events): component.available_properties).replace( ' ', '')) - if (hasattr(arg, 'component_event') and - arg.component_event not in - component.available_events): + if hasattr(arg, 'component_event'): raise exceptions.NonExistentEventException(''' - Attempting to assign a callback with - the event "{}" but the component - "{}" doesn't have "{}" as an event.\n - Here is a list of the available events in "{}": - {} - '''.format( - arg.component_event, - arg.component_id, - arg.component_event, - arg.component_id, - component.available_events).replace(' ', '')) + Events have been removed. + Use the associated property instead. + ''') - if state and not events and not inputs: - raise exceptions.MissingEventsException(''' + if state and not inputs: + raise exceptions.MissingInputsException(''' This callback has {} `State` {} - but no `Input` elements or `Event` elements.\n - Without `Input` or `Event` elements, this callback + but no `Input` elements.\n + Without `Input` elements, this callback will never get called.\n (Subscribing to input components will cause the - callback to be called whenever their values - change and subscribing to an event will cause the - callback to be called whenever the event is fired.) + callback to be called whenever their values change.) '''.format( len(state), 'elements' if len(state) > 1 else 'element' @@ -888,8 +875,8 @@ def _validate_value(val, index=None): # TODO - Check this map for recursive or other ill-defined non-tree # relationships # pylint: disable=dangerous-default-value - def callback(self, output, inputs=[], state=[], events=[]): - self._validate_callback(output, inputs, state, events) + def callback(self, output, inputs=[], state=[]): + self._validate_callback(output, inputs, state) callback_id = '{}.{}'.format( output.component_id, output.component_property @@ -902,10 +889,6 @@ def callback(self, output, inputs=[], state=[], events=[]): 'state': [ {'id': c.component_id, 'property': c.component_property} for c in state - ], - 'events': [ - {'id': c.component_id, 'event': c.component_event} - for c in events ] } diff --git a/dash/dependencies.py b/dash/dependencies.py index 0421860c11..f81007ad40 100644 --- a/dash/dependencies.py +++ b/dash/dependencies.py @@ -17,10 +17,3 @@ class State: def __init__(self, component_id, component_property): self.component_id = component_id self.component_property = component_property - - -# pylint: disable=old-style-class, too-few-public-methods -class Event: - def __init__(self, component_id, component_event): - self.component_id = component_id - self.component_event = component_event diff --git a/dash/development/_py_components_generation.py b/dash/development/_py_components_generation.py index ba58a40854..98b6b7b509 100644 --- a/dash/development/_py_components_generation.py +++ b/dash/development/_py_components_generation.py @@ -3,6 +3,7 @@ import os from dash.development.base_component import _explicitize_args +from dash.exceptions import NonExistentEventException from ._all_keywords import python_keywords from .base_component import Component @@ -27,8 +28,7 @@ def generate_class_string(typename, props, description, namespace): string """ - # TODO _prop_names, _type, _namespace, available_events, - # and available_properties + # TODO _prop_names, _type, _namespace, and available_properties # can be modified by a Dash JS developer via setattr # TODO - Tab out the repr for the repr of these components to make it # look more like a hierarchical tree @@ -52,7 +52,6 @@ def __init__(self, {default_argtext}): self._namespace = '{namespace}' self._valid_wildcard_attributes =\ {list_of_valid_wildcard_attr_prefixes} - self.available_events = {events} self.available_properties = {list_of_valid_keys} self.available_wildcard_properties =\ {list_of_valid_wildcard_attr_prefixes} @@ -101,11 +100,11 @@ def __repr__(self): docstring = create_docstring( component_name=typename, props=filtered_props, - events=parse_events(props), description=description).replace('\r\n', '\n') + prohibit_events(props) + # pylint: disable=unused-variable - events = '[' + ', '.join(parse_events(props)) + ']' prop_keys = list(props.keys()) if 'children' in props: prop_keys.remove('children') @@ -122,7 +121,7 @@ def __repr__(self): for p in prop_keys if not p.endswith("-*") and p not in python_keywords and - p not in ['dashEvents', 'fireEvent', 'setProps']] + ['**kwargs'] + p != 'setProps'] + ['**kwargs'] ) required_args = required_props(props) @@ -233,7 +232,7 @@ def required_props(props): if prop['required']] -def create_docstring(component_name, props, events, description): +def create_docstring(component_name, props, description): """ Create the Dash component docstring @@ -243,8 +242,6 @@ def create_docstring(component_name, props, events, description): Component name props: dict Dictionary with {propName: propMetadata} structure - events: list - List of Dash events description: str Component description @@ -259,9 +256,7 @@ def create_docstring(component_name, props, events, description): return ( """A {name} component.\n{description} -Keyword arguments:\n{args} - -Available events: {events}""" +Keyword arguments:\n{args}""" ).format( name=component_name, description=description, @@ -274,30 +269,26 @@ def create_docstring(component_name, props, events, description): description=prop['description'], indent_num=0, is_flow_type='flowType' in prop and 'type' not in prop) - for p, prop in list(filter_props(props).items())), - events=', '.join(events)) + for p, prop in list(filter_props(props).items()))) -def parse_events(props): +def prohibit_events(props): """ - Pull out the dashEvents from the Component props + Events have been removed. Raise an error if we see dashEvents or fireEvents Parameters ---------- props: dict Dictionary with {propName: propMetadata} structure - Returns + Raises ------- - list - List of Dash event strings + ? """ - if 'dashEvents' in props and props['dashEvents']['type']['name'] == 'enum': - events = [v['value'] for v in props['dashEvents']['type']['value']] - else: - events = [] - - return events + if 'dashEvents' in props or 'fireEvents' in props: + raise NonExistentEventException( + 'Events are no longer supported by dash. Use properties instead, ' + 'eg `n_clicks` instead of a `click` event.') def parse_wildcards(props): @@ -349,7 +340,6 @@ def filter_props(props): Filter props from the Component arguments to exclude: - Those without a "type" or a "flowType" field - Those with arg.type.name in {'func', 'symbol', 'instanceOf'} - - dashEvents as a name Parameters ---------- @@ -415,10 +405,6 @@ def filter_props(props): else: raise ValueError - # dashEvents are a special oneOf property that is used for subscribing - # to events but it's never set as a property - if arg_name in ['dashEvents']: - filtered_props.pop(arg_name) return filtered_props @@ -518,7 +504,7 @@ def map_js_to_py_types_prop_types(type_object): ', '.join( "'{}'".format(t) for t in list(type_object['value'].keys())), - 'Those keys have the following types: \n{}'.format( + 'Those keys have the following types:\n{}'.format( '\n'.join(create_prop_docstring( prop_name=prop_name, type_object=prop, @@ -561,7 +547,7 @@ def map_js_to_py_types_flow_types(type_object): signature=lambda indent_num: 'dict containing keys {}.\n{}'.format( ', '.join("'{}'".format(d['key']) for d in type_object['signature']['properties']), - '{}Those keys have the following types: \n{}'.format( + '{}Those keys have the following types:\n{}'.format( ' ' * indent_num, '\n'.join( create_prop_docstring( diff --git a/dash/exceptions.py b/dash/exceptions.py index 13b4feb044..8ad30d52c6 100644 --- a/dash/exceptions.py +++ b/dash/exceptions.py @@ -30,7 +30,7 @@ class IncorrectTypeException(CallbackException): pass -class MissingEventsException(CallbackException): +class MissingInputsException(CallbackException): pass diff --git a/dash/extract-meta.js b/dash/extract-meta.js index 743d535928..0040b479b4 100644 --- a/dash/extract-meta.js +++ b/dash/extract-meta.js @@ -8,7 +8,7 @@ const componentPaths = process.argv.slice(3); const ignorePattern = new RegExp(process.argv[2]); const excludedDocProps = [ - 'setProps', 'id', 'className', 'style', 'dashEvents', 'fireEvent' + 'setProps', 'id', 'className', 'style' ]; if (!componentPaths.length) { diff --git a/test.sh b/test.sh new file mode 100755 index 0000000000..48f97a1cc5 --- /dev/null +++ b/test.sh @@ -0,0 +1,20 @@ +EXIT_STATE=0 + +python -m unittest tests.development.test_base_component || EXIT_STATE=$? +python -m unittest tests.development.test_component_loader || EXIT_STATE=$? +python -m unittest tests.test_integration || EXIT_STATE=$? +python -m unittest tests.test_resources || EXIT_STATE=$? +python -m unittest tests.test_configs || EXIT_STATE=$? + +pylint dash setup.py --rcfile=$PYLINTRC || EXIT_STATE=$? +pylint tests -d all -e C0410,C0411,C0412,C0413,W0109 || EXIT_STATE=$? +flake8 dash setup.py || EXIT_STATE=$? +flake8 --ignore=E123,E126,E501,E722,E731,F401,F841,W503,W504 --exclude=metadata_test.py tests || EXIT_STATE=$? + +if [ $EXIT_STATE -ne 0 ]; then + echo "One or more tests failed" +else + echo "All tests passed!" +fi + +exit $EXIT_STATE diff --git a/tests/development/TestReactComponent.react.js b/tests/development/TestReactComponent.react.js index 5c45fed8c6..cc42763aa4 100644 --- a/tests/development/TestReactComponent.react.js +++ b/tests/development/TestReactComponent.react.js @@ -91,19 +91,9 @@ ReactComponent.propTypes = { } }), - // special dash events - children: React.PropTypes.node, id: React.PropTypes.string, - - - // dashEvents is a special prop that is used to events validation - dashEvents: React.PropTypes.oneOf([ - 'restyle', - 'relayout', - 'click' - ]) }; ReactComponent.defaultProps = { diff --git a/tests/development/metadata_test.json b/tests/development/metadata_test.json index 1da85ba814..faa4bc734e 100644 --- a/tests/development/metadata_test.json +++ b/tests/development/metadata_test.json @@ -234,27 +234,6 @@ }, "required": false, "description": "" - }, - "dashEvents": { - "type": { - "name": "enum", - "value": [ - { - "value": "'restyle'", - "computed": false - }, - { - "value": "'relayout'", - "computed": false - }, - { - "value": "'click'", - "computed": false - } - ] - }, - "required": false, - "description": "" } } } diff --git a/tests/development/metadata_test.py b/tests/development/metadata_test.py index 1074ff0e51..1deb97efe6 100644 --- a/tests/development/metadata_test.py +++ b/tests/development/metadata_test.py @@ -22,11 +22,11 @@ class Table(Component): - optionalArrayOf (list; optional) - optionalObjectOf (dict with strings as keys and values of type number; optional) - optionalObjectWithShapeAndNestedDescription (optional): . optionalObjectWithShapeAndNestedDescription has the following type: dict containing keys 'color', 'fontSize', 'figure'. -Those keys have the following types: +Those keys have the following types: - color (string; optional) - fontSize (number; optional) - figure (optional): Figure is a plotly graph object. figure has the following type: dict containing keys 'data', 'layout'. -Those keys have the following types: +Those keys have the following types: - data (list; optional): data is a collection of traces - layout (dict; optional): layout describes the rest of the figure - optionalAny (boolean | number | string | dict | list; optional) @@ -35,16 +35,13 @@ class Table(Component): - data-* (string; optional) - aria-* (string; optional) - in (string; optional) -- id (string; optional) - -Available events: 'restyle', 'relayout', 'click'""" +- id (string; optional)""" @_explicitize_args def __init__(self, children=None, optionalArray=Component.UNDEFINED, optionalBool=Component.UNDEFINED, optionalFunc=Component.UNDEFINED, optionalNumber=Component.UNDEFINED, optionalObject=Component.UNDEFINED, optionalString=Component.UNDEFINED, optionalSymbol=Component.UNDEFINED, optionalNode=Component.UNDEFINED, optionalElement=Component.UNDEFINED, optionalMessage=Component.UNDEFINED, optionalEnum=Component.UNDEFINED, optionalUnion=Component.UNDEFINED, optionalArrayOf=Component.UNDEFINED, optionalObjectOf=Component.UNDEFINED, optionalObjectWithShapeAndNestedDescription=Component.UNDEFINED, optionalAny=Component.UNDEFINED, customProp=Component.UNDEFINED, customArrayProp=Component.UNDEFINED, id=Component.UNDEFINED, **kwargs): self._prop_names = ['children', 'optionalArray', 'optionalBool', 'optionalNumber', 'optionalObject', 'optionalString', 'optionalNode', 'optionalElement', 'optionalEnum', 'optionalUnion', 'optionalArrayOf', 'optionalObjectOf', 'optionalObjectWithShapeAndNestedDescription', 'optionalAny', 'customProp', 'customArrayProp', 'data-*', 'aria-*', 'in', 'id'] self._type = 'Table' self._namespace = 'TableComponents' self._valid_wildcard_attributes = ['data-', 'aria-'] - self.available_events = ['restyle', 'relayout', 'click'] self.available_properties = ['children', 'optionalArray', 'optionalBool', 'optionalNumber', 'optionalObject', 'optionalString', 'optionalNode', 'optionalElement', 'optionalEnum', 'optionalUnion', 'optionalArrayOf', 'optionalObjectOf', 'optionalObjectWithShapeAndNestedDescription', 'optionalAny', 'customProp', 'customArrayProp', 'data-*', 'aria-*', 'in', 'id'] self.available_wildcard_properties = ['data-', 'aria-'] diff --git a/tests/development/test_base_component.py b/tests/development/test_base_component.py index 9e725f5903..1fcfa06f9c 100644 --- a/tests/development/test_base_component.py +++ b/tests/development/test_base_component.py @@ -7,11 +7,9 @@ import unittest import plotly -from dash.development.base_component import ( - Component, - _explicitize_args) +from dash.development.base_component import Component from dash.development._py_components_generation import generate_class_string, generate_class_file, generate_class, \ - create_docstring, parse_events, js_to_py_type + create_docstring, prohibit_events, js_to_py_type Component._prop_names = ('id', 'a', 'children', 'style', ) Component._type = 'TestComponent' @@ -547,17 +545,23 @@ def setUp(self): def tearDown(self): shutil.rmtree('TableComponents') + def assert_no_trailing_spaces(self, s): + for line in s.split('\n'): + self.assertEqual(line, line.rstrip()) + def test_class_string(self): self.assertEqual( self.expected_class_string, self.component_class_string ) + self.assert_no_trailing_spaces(self.component_class_string) def test_class_file(self): self.assertEqual( self.expected_class_string, self.written_class_string ) + self.assert_no_trailing_spaces(self.written_class_string) class TestGenerateClass(unittest.TestCase): @@ -685,10 +689,10 @@ def test_repr_with_wildcards(self): def test_docstring(self): assert_docstring(self.assertEqual, self.ComponentClass.__doc__) - def test_events(self): + def test_no_events(self): self.assertEqual( - self.ComponentClass().available_events, - ['restyle', 'relayout', 'click'] + hasattr(self.ComponentClass(), 'available_events'), + False ) # This one is kind of pointless now @@ -793,11 +797,11 @@ def setUp(self): ['optionalObjectWithShapeAndNestedDescription', '\n'.join([ "dict containing keys 'color', 'fontSize', 'figure'.", - "Those keys have the following types: ", + "Those keys have the following types:", " - color (string; optional)", " - fontSize (number; optional)", " - figure (optional): Figure is a plotly graph object. figure has the following type: dict containing keys 'data', 'layout'.", # noqa: E501 - "Those keys have the following types: ", + "Those keys have the following types:", " - data (list; optional): data is a collection of traces", " - layout (dict; optional): layout describes the rest of the figure" # noqa: E501 @@ -815,18 +819,16 @@ def setUp(self): ['in', 'string'], - ['id', 'string'], - - ['dashEvents', "a value equal to: 'restyle', 'relayout', 'click'"] + ['id', 'string'] ]) def test_docstring(self): docstring = create_docstring( 'Table', self.data['props'], - parse_events(self.data['props']), self.data['description'], ) + prohibit_events(self.data['props']), assert_docstring(self.assertEqual, docstring) def test_docgen_to_python_args(self): @@ -871,7 +873,7 @@ def assert_docstring(assertEqual, docstring): "following type: dict containing keys " "'color', 'fontSize', 'figure'.", - "Those keys have the following types: ", + "Those keys have the following types:", " - color (string; optional)", " - fontSize (number; optional)", @@ -879,7 +881,7 @@ def assert_docstring(assertEqual, docstring): "figure has the following type: dict containing " "keys 'data', 'layout'.", - "Those keys have the following types: ", + "Those keys have the following types:", " - data (list; optional): data is a collection of traces", " - layout (dict; optional): layout describes " @@ -894,8 +896,6 @@ def assert_docstring(assertEqual, docstring): '- aria-* (string; optional)', '- in (string; optional)', '- id (string; optional)', - '', - "Available events: 'restyle', 'relayout', 'click'", ' ' ])[i] ) @@ -931,7 +931,7 @@ def setUp(self): ['optionalSignature(shape)', '\n'.join([ "dict containing keys 'checked', 'children', 'customData', 'disabled', 'label', 'primaryText', 'secondaryText', 'style', 'value'.", - "Those keys have the following types: ", + "Those keys have the following types:", "- checked (boolean; optional)", "- children (a list of or a singular dash component, string or number; optional)", "- customData (bool | number | str | dict | list; required): A test description", @@ -947,9 +947,9 @@ def setUp(self): ['requiredNested', '\n'.join([ "dict containing keys 'customData', 'value'.", - "Those keys have the following types: ", + "Those keys have the following types:", "- customData (required): . customData has the following type: dict containing keys 'checked', 'children', 'customData', 'disabled', 'label', 'primaryText', 'secondaryText', 'style', 'value'.", - " Those keys have the following types: ", + " Those keys have the following types:", " - checked (boolean; optional)", " - children (a list of or a singular dash component, string or number; optional)", " - customData (bool | number | str | dict | list; required)", @@ -968,9 +968,9 @@ def test_docstring(self): docstring = create_docstring( 'Flow_component', self.data['props'], - parse_events(self.data['props']), self.data['description'], ) + prohibit_events(self.data['props']), assert_flow_docstring(self.assertEqual, docstring) def test_docgen_to_python_args(self): @@ -1010,7 +1010,7 @@ def assert_flow_docstring(assertEqual, docstring): "'children', 'customData', 'disabled', 'label', 'primaryText', 'secondaryText', " "'style', 'value'.", - " Those keys have the following types: ", + " Those keys have the following types:", " - checked (boolean; optional)", " - children (a list of or a singular dash component, string or number; optional)", " - customData (bool | number | str | dict | list; required): A test description", @@ -1024,13 +1024,13 @@ def assert_flow_docstring(assertEqual, docstring): "- requiredNested (required): . requiredNested has the following type: dict containing " "keys 'customData', 'value'.", - " Those keys have the following types: ", + " Those keys have the following types:", " - customData (required): . customData has the following type: dict containing " "keys 'checked', 'children', 'customData', 'disabled', 'label', 'primaryText', " "'secondaryText', 'style', 'value'.", - " Those keys have the following types: ", + " Those keys have the following types:", " - checked (boolean; optional)", " - children (a list of or a singular dash component, string or number; optional)", " - customData (bool | number | str | dict | list; required)", @@ -1041,7 +1041,5 @@ def assert_flow_docstring(assertEqual, docstring): " - style (dict; optional)", " - value (bool | number | str | dict | list; required)", " - value (bool | number | str | dict | list; required)", - "", - "Available events: " ])[i] ) diff --git a/tests/test_integration.py b/tests/test_integration.py index e5be2a4298..19bf13bf60 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -11,7 +11,7 @@ import dash -from dash.dependencies import Input, Output, State +from dash.dependencies import Input, Output from dash.exceptions import PreventUpdate from .IntegrationTests import IntegrationTests from .utils import assert_clean_console, invincible, wait_for @@ -105,7 +105,7 @@ def update_text(data): return data self.startServer(app) - output1 = self.wait_for_text_to_equal('#output-1', 'initial value') + self.wait_for_text_to_equal('#output-1', 'initial value') self.percy_snapshot(name='wildcard-callback-1') input1 = self.wait_for_element_by_id('input') @@ -113,7 +113,7 @@ def update_text(data): input1.send_keys('hello world') - output1 = self.wait_for_text_to_equal('#output-1', 'hello world') + self.wait_for_text_to_equal('#output-1', 'hello world') self.percy_snapshot(name='wildcard-callback-2') self.assertEqual( diff --git a/tests/test_react.py b/tests/test_react.py index 28cc3e9dfe..c66d8ebb18 100644 --- a/tests/test_react.py +++ b/tests/test_react.py @@ -7,7 +7,7 @@ import dash_core_components as dcc import dash -from dash.dependencies import Event, Input, Output, State +from dash.dependencies import Input, Output, State from dash import exceptions @@ -73,23 +73,20 @@ def test_dependencies_route(self): self.assertEqual( json.loads(response.data), { 'header': { - 'state': [{'id': 'id1'}], - 'events': [{'id': 'id1'}] + 'state': [{'id': 'id1'}] } } ) self.app.callback( 'header', - state=[{'id': 'id1'}], - events=[{'id': 'id1'}]) + state=[{'id': 'id1'}]) response = self.client.get('/dependencies') self.assertEqual(response.status_code, 200) self.assertEqual( json.loads(response.data), { 'header': { - 'state': [{'id': 'id1'}], - 'events': [{'id': 'id1'}] + 'state': [{'id': 'id1'}] } } ) @@ -103,18 +100,13 @@ def test_dependencies_route(self): # Nested state {'id': 'id1', 'prop': ['style', 'color']} ] - events = [ - {'id': 'id1', 'event': 'click'}, - {'id': 'id1', 'event': 'submit'} - ] - self.app.callback('header', state=state, events=events) + self.app.callback('header', state=state) response = self.client.get('/dependencies') self.assertEqual(response.status_code, 200) self.assertEqual( json.loads(response.data), { 'header': { - 'state': state, - 'events': events + 'state': state } } ) @@ -339,7 +331,6 @@ class TestCallbacks(unittest.TestCase): def test_callback_registry(self): app = dash.Dash('') input = dcc.Input(id='input') - input._events = ['blur', 'change'] app.layout = Div([ input, @@ -364,8 +355,7 @@ def test_callback_registry(self): app.callback( Output('output-3', 'children'), [Input('input', 'value')], - state=[State('input', 'value')], - events=[Event('input', 'blur')], + state=[State('input', 'value')] ) def test_no_layout_exception(self): @@ -416,6 +406,7 @@ def test_exception_prop_not_in_component(self): ) def test_exception_event_not_in_component(self): + # no events anymore, period! app = dash.Dash('') app.layout = Div([ Div(id='button'), @@ -426,27 +417,12 @@ def test_exception_event_not_in_component(self): for id in ['output', 'body']: self.assertRaises( - exceptions.NonExistentEventException, + TypeError, app.callback, Output(id, 'children'), - events=[Event(id, 'style')] - ) - app.callback( - Output(id, 'children'), - events=[Event(id, 'click')] + events=[] ) - self.assertRaises( - exceptions.NonExistentEventException, - app.callback, - Output('output', 'children'), - events=[Event('graph', 'zoom')] - ) - app.callback( - Output('graph-output', 'children'), - events=[Event('graph', 'click')] - ) - def test_exception_component_is_not_right_type(self): app = dash.Dash('') app.layout = Div([ @@ -458,7 +434,6 @@ def test_exception_component_is_not_right_type(self): ['asdf', ['asdf'], [], []], [Output('output', 'children'), Input('input', 'value'), [], []], [Output('output', 'children'), [], State('input', 'value'), []], - [Output('output', 'children'), [], [], Event('input', 'click')], ] for args in test_args: self.assertRaises( @@ -483,13 +458,13 @@ def test_suppress_callback_exception(self): app.callback(Output('id-not-there', 'children'), [Input('input', 'value')]) - def test_missing_input_and_events(self): + def test_missing_inputs(self): app = dash.Dash('') app.layout = Div([ dcc.Input(id='input') ], id='body') self.assertRaises( - exceptions.MissingEventsException, + exceptions.MissingInputsException, app.callback, Output('body', 'children'), [],