From 1c757121a6e04df0f468e505787fbcc718663333 Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Sun, 5 Aug 2018 05:45:47 -0400 Subject: [PATCH] Fix update method on empty and uninitialized array property (#1092) * Fix for GH1072. Empty array properties are replaced during update * Don't error when a literal property is set to it's correct value. This avoids errors when performing updates like figure.update(data=[go.Scatter(...), ...]) * Fix two failing validator tests --- _plotly_utils/basevalidators.py | 21 ++- .../validators/test_basetraces_validator.py | 3 +- .../validators/test_infoarray_validator.py | 2 +- .../validators/test_literal_validator.py | 28 +++ codegen/datatypes.py | 7 +- codegen/utils.py | 2 + plotly/basedatatypes.py | 27 ++- plotly/graph_objs/_area.py | 2 +- plotly/graph_objs/_bar.py | 2 +- plotly/graph_objs/_box.py | 2 +- plotly/graph_objs/_candlestick.py | 2 +- plotly/graph_objs/_carpet.py | 2 +- plotly/graph_objs/_choropleth.py | 2 +- plotly/graph_objs/_cone.py | 2 +- plotly/graph_objs/_contour.py | 2 +- plotly/graph_objs/_contourcarpet.py | 4 +- plotly/graph_objs/_heatmap.py | 2 +- plotly/graph_objs/_heatmapgl.py | 2 +- plotly/graph_objs/_histogram.py | 2 +- plotly/graph_objs/_histogram2d.py | 2 +- plotly/graph_objs/_histogram2dcontour.py | 4 +- plotly/graph_objs/_mesh3d.py | 2 +- plotly/graph_objs/_ohlc.py | 2 +- plotly/graph_objs/_parcoords.py | 2 +- plotly/graph_objs/_pie.py | 2 +- plotly/graph_objs/_pointcloud.py | 2 +- plotly/graph_objs/_sankey.py | 2 +- plotly/graph_objs/_scatter.py | 2 +- plotly/graph_objs/_scatter3d.py | 2 +- plotly/graph_objs/_scattercarpet.py | 4 +- plotly/graph_objs/_scattergeo.py | 2 +- plotly/graph_objs/_scattergl.py | 2 +- plotly/graph_objs/_scattermapbox.py | 4 +- plotly/graph_objs/_scatterpolar.py | 2 +- plotly/graph_objs/_scatterpolargl.py | 4 +- plotly/graph_objs/_scatterternary.py | 4 +- plotly/graph_objs/_splom.py | 2 +- plotly/graph_objs/_streamtube.py | 2 +- plotly/graph_objs/_surface.py | 2 +- plotly/graph_objs/_table.py | 2 +- plotly/graph_objs/_violin.py | 2 +- .../test_graph_objs/test_figure_properties.py | 22 +++ .../test_core/test_graph_objs/test_update.py | 169 ++++++++++++------ 43 files changed, 253 insertions(+), 108 deletions(-) create mode 100644 _plotly_utils/tests/validators/test_literal_validator.py diff --git a/_plotly_utils/basevalidators.py b/_plotly_utils/basevalidators.py index d094e27aae..5c17caf02d 100644 --- a/_plotly_utils/basevalidators.py +++ b/_plotly_utils/basevalidators.py @@ -1658,16 +1658,21 @@ class LiteralValidator(BaseValidator): """ Validator for readonly literal values """ - def __init__(self, plotly_name, parent_name, **kwargs): - super(LiteralValidator, self).__init__(plotly_name=plotly_name, - parent_name=parent_name, - **kwargs) + def __init__(self, plotly_name, parent_name, val, **kwargs): + super(LiteralValidator, self).__init__( + plotly_name=plotly_name, + parent_name=parent_name, + **kwargs) + self.val = val def validate_coerce(self, v): - raise ValueError("""\ -The '{plotly_name}' property of {parent_name} is read-only""".format( - plotly_name=self.plotly_name, parent_name=self.parent_name - )) + if v != self.val: + raise ValueError("""\ + The '{plotly_name}' property of {parent_name} is read-only""".format( + plotly_name=self.plotly_name, parent_name=self.parent_name + )) + else: + return v class ImageUriValidator(BaseValidator): diff --git a/_plotly_utils/tests/validators/test_basetraces_validator.py b/_plotly_utils/tests/validators/test_basetraces_validator.py index 40c62e6f01..a3e3927413 100644 --- a/_plotly_utils/tests/validators/test_basetraces_validator.py +++ b/_plotly_utils/tests/validators/test_basetraces_validator.py @@ -10,7 +10,8 @@ def validator(): 'bar': 'Bar', 'box': 'Box'}, plotly_name='prop', - parent_name='parent') + parent_name='parent', + set_uid=True) # Tests diff --git a/_plotly_utils/tests/validators/test_infoarray_validator.py b/_plotly_utils/tests/validators/test_infoarray_validator.py index b7deed75ef..c7f7d8d18b 100644 --- a/_plotly_utils/tests/validators/test_infoarray_validator.py +++ b/_plotly_utils/tests/validators/test_infoarray_validator.py @@ -30,7 +30,7 @@ def validator_number3_free(): # ---------- # ### Acceptance ### @pytest.mark.parametrize('val', [ - [1, 'A'], ('hello', 'world!'), [1, ()], [-1, 1] + [1, 'A'], ('hello', 'world!'), [1, set()], [-1, 1] ]) def test_validator_acceptance_any2(val, validator_any2: InfoArrayValidator): coerce_val = validator_any2.validate_coerce(val) diff --git a/_plotly_utils/tests/validators/test_literal_validator.py b/_plotly_utils/tests/validators/test_literal_validator.py new file mode 100644 index 0000000000..e624569298 --- /dev/null +++ b/_plotly_utils/tests/validators/test_literal_validator.py @@ -0,0 +1,28 @@ +import pytest +from _plotly_utils.basevalidators import LiteralValidator +import numpy as np + + +# Fixtures +# -------- +@pytest.fixture() +def validator(): + return LiteralValidator('prop', 'parent', 'scatter') + + +# Tests +# ----- +# ### Acceptance ### +@pytest.mark.parametrize('val', ['scatter']) +def test_acceptance(val, validator): + assert validator.validate_coerce(val) is val + + +# ### Test rejection ### +@pytest.mark.parametrize('val', + ['hello', (), [], [1, 2, 3], set(), '34']) +def test_rejection(val, validator): + with pytest.raises(ValueError) as validation_failure: + validator.validate_coerce(val) + + assert 'read-only' in str(validation_failure.value) diff --git a/codegen/datatypes.py b/codegen/datatypes.py index d44504c95f..483043c5ca 100644 --- a/codegen/datatypes.py +++ b/codegen/datatypes.py @@ -254,11 +254,12 @@ def __init__(self""") for literal_node in literal_nodes: lit_name = literal_node.name_property lit_parent = literal_node.parent_path_str - lit_val = literal_node.node_data + lit_val = repr(literal_node.node_data) buffer.write(f""" - self._props['{lit_name}'] = '{lit_val}' + self._props['{lit_name}'] = {lit_val} self._validators['{lit_name}'] =\ -LiteralValidator(plotly_name='{lit_name}', parent_name='{lit_parent}')""") +LiteralValidator(plotly_name='{lit_name}',\ + parent_name='{lit_parent}', val={lit_val})""") buffer.write(f""" diff --git a/codegen/utils.py b/codegen/utils.py index 2ade3566fa..e7cd3912fa 100644 --- a/codegen/utils.py +++ b/codegen/utils.py @@ -423,6 +423,8 @@ def get_validator_params(self): if colorscale_node_list: colorscale_path = colorscale_node_list[0].path_str params['colorscale_path'] = repr(colorscale_path) + elif self.datatype == 'literal': + params['val'] = self.node_data return params diff --git a/plotly/basedatatypes.py b/plotly/basedatatypes.py index 65700aa357..16921089d5 100644 --- a/plotly/basedatatypes.py +++ b/plotly/basedatatypes.py @@ -378,7 +378,16 @@ def update(self, dict1=None, **kwargs): for d in [dict1, kwargs]: if d: for k, v in d.items(): - BaseFigure._perform_update(self[k], v) + if self[k] == (): + # existing data or frames property is empty + # In this case we accept the v as is. + if k == 'data': + self.add_traces(v) + else: + # Accept v + self[k] = v + else: + BaseFigure._perform_update(self[k], v) return self @@ -1059,11 +1068,6 @@ def add_traces(self, data, rows=None, cols=None): ... rows=[1, 2], cols=[1, 1]) """ - if self._in_batch_mode: - self._batch_layout_edits.clear() - self._batch_trace_edits.clear() - raise ValueError('Traces may not be added in a batch context') - # Validate traces data = self._data_validator.validate_coerce(data) @@ -2133,8 +2137,15 @@ def _perform_update(plotly_obj, update_obj): BaseFigure._perform_update( plotly_obj[key], val) elif isinstance(validator, CompoundArrayValidator): - BaseFigure._perform_update( - plotly_obj[key], val) + if plotly_obj[key]: + # plotly_obj has an existing non-empty array for key + # In this case we merge val into the existing elements + BaseFigure._perform_update( + plotly_obj[key], val) + else: + # plotly_obj is an empty or uninitialized list for key + # In this case we accept val as is + plotly_obj[key] = val else: # Assign non-compound value plotly_obj[key] = val diff --git a/plotly/graph_objs/_area.py b/plotly/graph_objs/_area.py index 20a24329d2..98dd3f08e1 100644 --- a/plotly/graph_objs/_area.py +++ b/plotly/graph_objs/_area.py @@ -785,7 +785,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'area' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='area' + plotly_name='type', parent_name='area', val='area' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_bar.py b/plotly/graph_objs/_bar.py index ee3c10e9eb..a0967870e7 100644 --- a/plotly/graph_objs/_bar.py +++ b/plotly/graph_objs/_bar.py @@ -2172,7 +2172,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'bar' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='bar' + plotly_name='type', parent_name='bar', val='bar' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_box.py b/plotly/graph_objs/_box.py index ca0ee00e36..be2a827da3 100644 --- a/plotly/graph_objs/_box.py +++ b/plotly/graph_objs/_box.py @@ -1574,7 +1574,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'box' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='box' + plotly_name='type', parent_name='box', val='box' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_candlestick.py b/plotly/graph_objs/_candlestick.py index c86390eca3..074c58c3f1 100644 --- a/plotly/graph_objs/_candlestick.py +++ b/plotly/graph_objs/_candlestick.py @@ -1234,7 +1234,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'candlestick' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='candlestick' + plotly_name='type', parent_name='candlestick', val='candlestick' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_carpet.py b/plotly/graph_objs/_carpet.py index d9c47cabe6..509e09d50e 100644 --- a/plotly/graph_objs/_carpet.py +++ b/plotly/graph_objs/_carpet.py @@ -1712,7 +1712,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'carpet' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='carpet' + plotly_name='type', parent_name='carpet', val='carpet' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_choropleth.py b/plotly/graph_objs/_choropleth.py index db69088c2b..104b805918 100644 --- a/plotly/graph_objs/_choropleth.py +++ b/plotly/graph_objs/_choropleth.py @@ -1478,7 +1478,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'choropleth' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='choropleth' + plotly_name='type', parent_name='choropleth', val='choropleth' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_cone.py b/plotly/graph_objs/_cone.py index e152866470..00df2f5019 100644 --- a/plotly/graph_objs/_cone.py +++ b/plotly/graph_objs/_cone.py @@ -1798,7 +1798,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'cone' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='cone' + plotly_name='type', parent_name='cone', val='cone' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_contour.py b/plotly/graph_objs/_contour.py index f200f90049..2c8544c278 100644 --- a/plotly/graph_objs/_contour.py +++ b/plotly/graph_objs/_contour.py @@ -2080,7 +2080,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'contour' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='contour' + plotly_name='type', parent_name='contour', val='contour' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_contourcarpet.py b/plotly/graph_objs/_contourcarpet.py index 0fa245cd25..51ff71bfb2 100644 --- a/plotly/graph_objs/_contourcarpet.py +++ b/plotly/graph_objs/_contourcarpet.py @@ -1979,7 +1979,9 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'contourcarpet' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='contourcarpet' + plotly_name='type', + parent_name='contourcarpet', + val='contourcarpet' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_heatmap.py b/plotly/graph_objs/_heatmap.py index 6a66930cbe..b6ea7f5b48 100644 --- a/plotly/graph_objs/_heatmap.py +++ b/plotly/graph_objs/_heatmap.py @@ -1877,7 +1877,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'heatmap' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='heatmap' + plotly_name='type', parent_name='heatmap', val='heatmap' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_heatmapgl.py b/plotly/graph_objs/_heatmapgl.py index c0a3e55e7b..3b51598f32 100644 --- a/plotly/graph_objs/_heatmapgl.py +++ b/plotly/graph_objs/_heatmapgl.py @@ -1646,7 +1646,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'heatmapgl' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='heatmapgl' + plotly_name='type', parent_name='heatmapgl', val='heatmapgl' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_histogram.py b/plotly/graph_objs/_histogram.py index d2c6f36cbf..f21dbcdd99 100644 --- a/plotly/graph_objs/_histogram.py +++ b/plotly/graph_objs/_histogram.py @@ -1754,7 +1754,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'histogram' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='histogram' + plotly_name='type', parent_name='histogram', val='histogram' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_histogram2d.py b/plotly/graph_objs/_histogram2d.py index 8bca104068..5004df4536 100644 --- a/plotly/graph_objs/_histogram2d.py +++ b/plotly/graph_objs/_histogram2d.py @@ -1941,7 +1941,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'histogram2d' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='histogram2d' + plotly_name='type', parent_name='histogram2d', val='histogram2d' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_histogram2dcontour.py b/plotly/graph_objs/_histogram2dcontour.py index aafb61ed86..ea397565b8 100644 --- a/plotly/graph_objs/_histogram2dcontour.py +++ b/plotly/graph_objs/_histogram2dcontour.py @@ -2090,7 +2090,9 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'histogram2dcontour' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='histogram2dcontour' + plotly_name='type', + parent_name='histogram2dcontour', + val='histogram2dcontour' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_mesh3d.py b/plotly/graph_objs/_mesh3d.py index 24d93ac8dd..73dc4f77a8 100644 --- a/plotly/graph_objs/_mesh3d.py +++ b/plotly/graph_objs/_mesh3d.py @@ -2268,7 +2268,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'mesh3d' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='mesh3d' + plotly_name='type', parent_name='mesh3d', val='mesh3d' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_ohlc.py b/plotly/graph_objs/_ohlc.py index 4a8c756c22..fcd103fcf9 100644 --- a/plotly/graph_objs/_ohlc.py +++ b/plotly/graph_objs/_ohlc.py @@ -1225,7 +1225,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'ohlc' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='ohlc' + plotly_name='type', parent_name='ohlc', val='ohlc' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_parcoords.py b/plotly/graph_objs/_parcoords.py index f56c3322f3..c65c237da4 100644 --- a/plotly/graph_objs/_parcoords.py +++ b/plotly/graph_objs/_parcoords.py @@ -1026,7 +1026,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'parcoords' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='parcoords' + plotly_name='type', parent_name='parcoords', val='parcoords' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_pie.py b/plotly/graph_objs/_pie.py index b485b9f32e..916b02a0e5 100644 --- a/plotly/graph_objs/_pie.py +++ b/plotly/graph_objs/_pie.py @@ -1505,7 +1505,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'pie' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='pie' + plotly_name='type', parent_name='pie', val='pie' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_pointcloud.py b/plotly/graph_objs/_pointcloud.py index 1da7e6198d..d0ec82bd57 100644 --- a/plotly/graph_objs/_pointcloud.py +++ b/plotly/graph_objs/_pointcloud.py @@ -1207,7 +1207,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'pointcloud' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='pointcloud' + plotly_name='type', parent_name='pointcloud', val='pointcloud' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_sankey.py b/plotly/graph_objs/_sankey.py index abecf27a65..930e08c98a 100644 --- a/plotly/graph_objs/_sankey.py +++ b/plotly/graph_objs/_sankey.py @@ -981,7 +981,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'sankey' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='sankey' + plotly_name='type', parent_name='sankey', val='sankey' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_scatter.py b/plotly/graph_objs/_scatter.py index 13a9bd9c16..e5e4900bfb 100644 --- a/plotly/graph_objs/_scatter.py +++ b/plotly/graph_objs/_scatter.py @@ -2145,7 +2145,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'scatter' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='scatter' + plotly_name='type', parent_name='scatter', val='scatter' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_scatter3d.py b/plotly/graph_objs/_scatter3d.py index ef0f967624..63b9347b4f 100644 --- a/plotly/graph_objs/_scatter3d.py +++ b/plotly/graph_objs/_scatter3d.py @@ -1925,7 +1925,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'scatter3d' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='scatter3d' + plotly_name='type', parent_name='scatter3d', val='scatter3d' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_scattercarpet.py b/plotly/graph_objs/_scattercarpet.py index 43ee2f9768..efc2a6e0db 100644 --- a/plotly/graph_objs/_scattercarpet.py +++ b/plotly/graph_objs/_scattercarpet.py @@ -1580,7 +1580,9 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'scattercarpet' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='scattercarpet' + plotly_name='type', + parent_name='scattercarpet', + val='scattercarpet' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_scattergeo.py b/plotly/graph_objs/_scattergeo.py index ce81aaa316..d0f8a658ae 100644 --- a/plotly/graph_objs/_scattergeo.py +++ b/plotly/graph_objs/_scattergeo.py @@ -1589,7 +1589,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'scattergeo' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='scattergeo' + plotly_name='type', parent_name='scattergeo', val='scattergeo' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_scattergl.py b/plotly/graph_objs/_scattergl.py index f918157dfe..f3613b7503 100644 --- a/plotly/graph_objs/_scattergl.py +++ b/plotly/graph_objs/_scattergl.py @@ -1942,7 +1942,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'scattergl' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='scattergl' + plotly_name='type', parent_name='scattergl', val='scattergl' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_scattermapbox.py b/plotly/graph_objs/_scattermapbox.py index cfb6ecad4e..8740dd579e 100644 --- a/plotly/graph_objs/_scattermapbox.py +++ b/plotly/graph_objs/_scattermapbox.py @@ -1430,7 +1430,9 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'scattermapbox' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='scattermapbox' + plotly_name='type', + parent_name='scattermapbox', + val='scattermapbox' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_scatterpolar.py b/plotly/graph_objs/_scatterpolar.py index 39158c7c87..593ea4f839 100644 --- a/plotly/graph_objs/_scatterpolar.py +++ b/plotly/graph_objs/_scatterpolar.py @@ -1638,7 +1638,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'scatterpolar' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='scatterpolar' + plotly_name='type', parent_name='scatterpolar', val='scatterpolar' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_scatterpolargl.py b/plotly/graph_objs/_scatterpolargl.py index 4c0f2b30d0..c610e2aefc 100644 --- a/plotly/graph_objs/_scatterpolargl.py +++ b/plotly/graph_objs/_scatterpolargl.py @@ -1394,7 +1394,9 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'scatterpolargl' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='scatterpolargl' + plotly_name='type', + parent_name='scatterpolargl', + val='scatterpolargl' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_scatterternary.py b/plotly/graph_objs/_scatterternary.py index 2b82d8d0d7..0d13d31c1d 100644 --- a/plotly/graph_objs/_scatterternary.py +++ b/plotly/graph_objs/_scatterternary.py @@ -1736,7 +1736,9 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'scatterternary' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='scatterternary' + plotly_name='type', + parent_name='scatterternary', + val='scatterternary' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_splom.py b/plotly/graph_objs/_splom.py index 14a56c9214..5f99140019 100644 --- a/plotly/graph_objs/_splom.py +++ b/plotly/graph_objs/_splom.py @@ -1139,7 +1139,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'splom' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='splom' + plotly_name='type', parent_name='splom', val='splom' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_streamtube.py b/plotly/graph_objs/_streamtube.py index 0fbd59c5b3..9ff232fbcf 100644 --- a/plotly/graph_objs/_streamtube.py +++ b/plotly/graph_objs/_streamtube.py @@ -1753,7 +1753,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'streamtube' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='streamtube' + plotly_name='type', parent_name='streamtube', val='streamtube' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_surface.py b/plotly/graph_objs/_surface.py index 7f4c999fea..33d3a05949 100644 --- a/plotly/graph_objs/_surface.py +++ b/plotly/graph_objs/_surface.py @@ -1729,7 +1729,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'surface' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='surface' + plotly_name='type', parent_name='surface', val='surface' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_table.py b/plotly/graph_objs/_table.py index 94aac263fc..346979334d 100644 --- a/plotly/graph_objs/_table.py +++ b/plotly/graph_objs/_table.py @@ -949,7 +949,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'table' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='table' + plotly_name='type', parent_name='table', val='table' ) # Process unknown kwargs diff --git a/plotly/graph_objs/_violin.py b/plotly/graph_objs/_violin.py index 144e873ebd..24222a52a5 100644 --- a/plotly/graph_objs/_violin.py +++ b/plotly/graph_objs/_violin.py @@ -1709,7 +1709,7 @@ def __init__( from _plotly_utils.basevalidators import LiteralValidator self._props['type'] = 'violin' self._validators['type'] = LiteralValidator( - plotly_name='type', parent_name='violin' + plotly_name='type', parent_name='violin', val='violin' ) # Process unknown kwargs diff --git a/plotly/tests/test_core/test_graph_objs/test_figure_properties.py b/plotly/tests/test_core/test_graph_objs/test_figure_properties.py index 69551b7c8e..49c0f9820c 100644 --- a/plotly/tests/test_core/test_graph_objs/test_figure_properties.py +++ b/plotly/tests/test_core/test_graph_objs/test_figure_properties.py @@ -121,6 +121,28 @@ def test_update_data(self): self.figure.update({'data': {0: {'marker': {'color': 'yellow'}}}}) self.assertEqual(self.figure.data[0].marker.color, 'yellow') + def test_update_data_empty(self): + # Create figure with empty data (no traces) + figure = go.Figure(layout={'width': 1000}) + + # Update data with new traces + figure.update(data=[go.Scatter(y=[2, 1, 3]), go.Bar(y=[1, 2, 3])]) + + # Build expected dict + expected = { + 'data': [{'y': [2, 1, 3], 'type': 'scatter'}, + {'y': [1, 2, 3], 'type': 'bar'}], + 'layout': {'width': 1000} + } + + # Compute expected figure dict (pop uids for comparison) + result = figure.to_dict() + del result['data'][0]['uid'] + del result['data'][1]['uid'] + + # Perform comparison + self.assertEqual(result, expected) + def test_update_frames(self): # Check initial frame axis title self.assertEqual(self.figure.frames[0].layout.yaxis.title, 'f1') diff --git a/plotly/tests/test_core/test_graph_objs/test_update.py b/plotly/tests/test_core/test_graph_objs/test_update.py index 9f181d32b9..69c71dd03f 100644 --- a/plotly/tests/test_core/test_graph_objs/test_update.py +++ b/plotly/tests/test_core/test_graph_objs/test_update.py @@ -1,60 +1,123 @@ from __future__ import absolute_import from unittest import skip +import plotly.graph_objs as go from plotly.graph_objs import Data, Figure, Layout, Line, Scatter, scatter, XAxis from plotly.tests.utils import strip_dict_params +from unittest import TestCase -def test_update_dict(): - title = 'this' - fig = Figure() - fig.update(layout=Layout(title=title)) - assert fig == Figure(layout=Layout(title=title)) - fig['layout'].update(xaxis=XAxis()) - assert fig == Figure(layout=Layout(title=title, xaxis=XAxis())) - - -def test_update_list(): - trace1 = Scatter(x=[1, 2, 3], y=[2, 1, 2]) - trace2 = Scatter(x=[1, 2, 3], y=[3, 2, 1]) - fig = Figure([trace1, trace2]) - update = dict(x=[2, 3, 4], y=[1, 2, 3]) - fig.data[0].update(update) - fig.data[1].update(update) - - d1, d2 = strip_dict_params(fig.data[0], Scatter(x=[2, 3, 4], y=[1, 2, 3])) - assert d1 == d2 - d1, d2 = strip_dict_params(fig.data[1], Scatter(x=[2, 3, 4], y=[1, 2, 3])) - assert d1 == d2 - - -def test_update_dict_empty(): - trace1 = Scatter(x=[1, 2, 3], y=[2, 1, 2]) - trace2 = Scatter(x=[1, 2, 3], y=[3, 2, 1]) - fig = Figure([trace1, trace2]) - fig.update({}) - d1, d2 = strip_dict_params(fig.data[0], Scatter(x=[1, 2, 3], y=[2, 1, 2])) - assert d1 == d2 - d1, d2 = strip_dict_params(fig.data[1], Scatter(x=[1, 2, 3], y=[3, 2, 1])) - assert d1 == d2 - - -def test_update_list_empty(): - trace1 = Scatter(x=[1, 2, 3], y=[2, 1, 2]) - trace2 = Scatter(x=[1, 2, 3], y=[3, 2, 1]) - fig = Figure([trace1, trace2]) - fig.update([]) - d1, d2 = strip_dict_params(fig.data[0], Scatter(x=[1, 2, 3], y=[2, 1, 2])) - assert d1 == d2 - d1, d2 = strip_dict_params(fig.data[1], Scatter(x=[1, 2, 3], y=[3, 2, 1])) - assert d1 == d2 - - -@skip('See https://github.com/plotly/python-api/issues/291') -def test_update_list_make_copies_false(): - trace1 = Scatter(x=[1, 2, 3], y=[2, 1, 2]) - trace2 = Scatter(x=[1, 2, 3], y=[3, 2, 1]) - data = Data([trace1, trace2]) - update = dict(x=[2, 3, 4], y=[1, 2, 3], line=Line()) - data.update(update, make_copies=False) - assert data[0]['line'] is data[1]['line'] + +class TestUpdateMethod(TestCase): + def setUp(self): + print('Setup!') + + def test_update_dict(self): + title = 'this' + fig = Figure() + fig.update(layout=Layout(title=title)) + assert fig == Figure(layout=Layout(title=title)) + fig['layout'].update(xaxis=XAxis()) + assert fig == Figure(layout=Layout(title=title, xaxis=XAxis())) + + + def test_update_list(self): + trace1 = Scatter(x=[1, 2, 3], y=[2, 1, 2]) + trace2 = Scatter(x=[1, 2, 3], y=[3, 2, 1]) + fig = Figure([trace1, trace2]) + update = dict(x=[2, 3, 4], y=[1, 2, 3]) + fig.data[0].update(update) + fig.data[1].update(update) + + d1, d2 = strip_dict_params(fig.data[0], Scatter(x=[2, 3, 4], y=[1, 2, 3])) + assert d1 == d2 + d1, d2 = strip_dict_params(fig.data[1], Scatter(x=[2, 3, 4], y=[1, 2, 3])) + assert d1 == d2 + + + def test_update_dict_empty(self): + trace1 = Scatter(x=[1, 2, 3], y=[2, 1, 2]) + trace2 = Scatter(x=[1, 2, 3], y=[3, 2, 1]) + fig = Figure([trace1, trace2]) + fig.update({}) + d1, d2 = strip_dict_params(fig.data[0], Scatter(x=[1, 2, 3], y=[2, 1, 2])) + assert d1 == d2 + d1, d2 = strip_dict_params(fig.data[1], Scatter(x=[1, 2, 3], y=[3, 2, 1])) + assert d1 == d2 + + + def test_update_list_empty(self): + trace1 = Scatter(x=[1, 2, 3], y=[2, 1, 2]) + trace2 = Scatter(x=[1, 2, 3], y=[3, 2, 1]) + fig = Figure([trace1, trace2]) + fig.update([]) + d1, d2 = strip_dict_params(fig.data[0], Scatter(x=[1, 2, 3], y=[2, 1, 2])) + assert d1 == d2 + d1, d2 = strip_dict_params(fig.data[1], Scatter(x=[1, 2, 3], y=[3, 2, 1])) + assert d1 == d2 + + + @skip('See https://github.com/plotly/python-api/issues/291') + def test_update_list_make_copies_false(self): + trace1 = Scatter(x=[1, 2, 3], y=[2, 1, 2]) + trace2 = Scatter(x=[1, 2, 3], y=[3, 2, 1]) + data = Data([trace1, trace2]) + update = dict(x=[2, 3, 4], y=[1, 2, 3], line=Line()) + data.update(update, make_copies=False) + assert data[0]['line'] is data[1]['line'] + + def test_update_uninitialized_list_with_list(self): + """ + If the original list is undefined, the updated list should be + accepted in full. + + See GH1072 + """ + layout = go.Layout() + layout.update(annotations=[ + go.layout.Annotation(text='one'), + go.layout.Annotation(text='two'), + ]) + + expected = {'annotations': [{'text': 'one'}, {'text': 'two'}]} + + self.assertEqual(len(layout.annotations), 2) + self.assertEqual(layout.to_plotly_json(), expected) + + def test_update_initialized_empty_list_with_list(self): + """ + If the original list is empty, treat is just as if it's undefined. + This is a change in behavior from version 2 + (where the input list would just be completly ignored), because + in version 3 the difference between an uninitialized and empty list + is not obvious to the user. + """ + layout = go.Layout(annotations=[]) + layout.update(annotations=[ + go.layout.Annotation(text='one'), + go.layout.Annotation(text='two'), + ]) + + expected = {'annotations': [{'text': 'one'}, {'text': 'two'}]} + + self.assertEqual(len(layout.annotations), 2) + self.assertEqual(layout.to_plotly_json(), expected) + + def test_update_initialized_nonempty_list_with_dict(self): + """ + If the original list is defined, a dict from + index numbers to property dicts may be used to update select + elements of the existing list + """ + layout = go.Layout(annotations=[ + go.layout.Annotation(text='one'), + go.layout.Annotation(text='two'), + ]) + + layout.update(annotations={1: go.layout.Annotation(width=30)}) + + expected = {'annotations': [{'text': 'one'}, + {'text': 'two', 'width': 30}]} + + self.assertEqual(len(layout.annotations), 2) + self.assertEqual(layout.to_plotly_json(), expected)