Skip to content

Commit

Permalink
Fix update method on empty and uninitialized array property (#1092)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
jonmmease authored Aug 5, 2018
1 parent 7ab0c90 commit 1c75712
Show file tree
Hide file tree
Showing 43 changed files with 253 additions and 108 deletions.
21 changes: 13 additions & 8 deletions _plotly_utils/basevalidators.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
3 changes: 2 additions & 1 deletion _plotly_utils/tests/validators/test_basetraces_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ def validator():
'bar': 'Bar',
'box': 'Box'},
plotly_name='prop',
parent_name='parent')
parent_name='parent',
set_uid=True)


# Tests
Expand Down
2 changes: 1 addition & 1 deletion _plotly_utils/tests/validators/test_infoarray_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
28 changes: 28 additions & 0 deletions _plotly_utils/tests/validators/test_literal_validator.py
Original file line number Diff line number Diff line change
@@ -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)
7 changes: 4 additions & 3 deletions codegen/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"""
Expand Down
2 changes: 2 additions & 0 deletions codegen/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
27 changes: 19 additions & 8 deletions plotly/basedatatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_area.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_bar.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_candlestick.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_carpet.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_choropleth.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_cone.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_contour.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion plotly/graph_objs/_contourcarpet.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_heatmap.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_heatmapgl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_histogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_histogram2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion plotly/graph_objs/_histogram2dcontour.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_mesh3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_ohlc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_parcoords.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_pie.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_pointcloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_sankey.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_scatter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_scatter3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion plotly/graph_objs/_scattercarpet.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_scattergeo.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion plotly/graph_objs/_scattergl.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion plotly/graph_objs/_scattermapbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 1c75712

Please sign in to comment.