From c5ddeadf2d1850009eec4b9b5a703076f03d5aaa Mon Sep 17 00:00:00 2001 From: Jon Mease Date: Tue, 6 Nov 2018 18:14:49 -0500 Subject: [PATCH] Fix incorrect validation error for animate args info array (#1267) * Added failing test cases * Only perform 2D validation if 2D array is allowed --- _plotly_utils/basevalidators.py | 49 +++++++++---------- .../validators/test_infoarray_validator.py | 29 +++++++++++ 2 files changed, 52 insertions(+), 26 deletions(-) diff --git a/_plotly_utils/basevalidators.py b/_plotly_utils/basevalidators.py index 58f769bc4e..df6ecc9da4 100644 --- a/_plotly_utils/basevalidators.py +++ b/_plotly_utils/basevalidators.py @@ -1808,32 +1808,29 @@ def validate_coerce(self, v): is_v_2d = v and is_array(v[0]) - if is_v_2d: - if self.dimensions == 1: - self.raise_invalid_val(orig_v) - else: # self.dimensions is '1-2' or 2 - if is_array(self.items): - # e.g. 2D list as parcoords.dimensions.constraintrange - # check that all items are there for each nested element - for i, row in enumerate(v): - # Check row length - if not is_array(row) or len(row) != len(self.items): - self.raise_invalid_val(orig_v[i], [i]) - - for j, validator in enumerate(self.item_validators): - row[j] = self.validate_element_with_indexed_name( - v[i][j], validator, [i, j]) - else: - # e.g. 2D list as layout.grid.subplots - # check that all elements match individual validator - validator = self.item_validators[0] - for i, row in enumerate(v): - if not is_array(row): - self.raise_invalid_val(orig_v[i], [i]) - - for j, el in enumerate(row): - row[j] = self.validate_element_with_indexed_name( - el, validator, [i, j]) + if is_v_2d and self.dimensions in ('1-2', 2): + if is_array(self.items): + # e.g. 2D list as parcoords.dimensions.constraintrange + # check that all items are there for each nested element + for i, row in enumerate(v): + # Check row length + if not is_array(row) or len(row) != len(self.items): + self.raise_invalid_val(orig_v[i], [i]) + + for j, validator in enumerate(self.item_validators): + row[j] = self.validate_element_with_indexed_name( + v[i][j], validator, [i, j]) + else: + # e.g. 2D list as layout.grid.subplots + # check that all elements match individual validator + validator = self.item_validators[0] + for i, row in enumerate(v): + if not is_array(row): + self.raise_invalid_val(orig_v[i], [i]) + + for j, el in enumerate(row): + row[j] = self.validate_element_with_indexed_name( + el, validator, [i, j]) elif v and self.dimensions == 2: # e.g. 1D list passed as layout.grid.subplots self.raise_invalid_val(orig_v[0], [0]) diff --git a/_plotly_utils/tests/validators/test_infoarray_validator.py b/_plotly_utils/tests/validators/test_infoarray_validator.py index 84bd284c41..5da739fd2f 100644 --- a/_plotly_utils/tests/validators/test_infoarray_validator.py +++ b/_plotly_utils/tests/validators/test_infoarray_validator.py @@ -26,6 +26,14 @@ def validator_number3_free(): {'valType': 'number', 'min': 0, 'max': 1}], free_length=True) +@pytest.fixture() +def validator_any3_free(): + return InfoArrayValidator('prop', 'parent', items=[ + {'valType': 'any'}, + {'valType': 'any'}, + {'valType': 'any'}], free_length=True) + + @pytest.fixture() def validator_number2_2d(): return InfoArrayValidator('prop', 'parent', items=[ @@ -219,6 +227,27 @@ def test_validator_rejection_number3_free_element_value(val, first_invalid_ind, first_invalid_ind=first_invalid_ind)) in str(validation_failure.value) +# Any3 Tests (free_length=True) +# -------------------------------- +# ### Acceptance ### +@pytest.mark.parametrize('val', [ + [1, 0, 'Hello'], + (False, 0.99), + np.array([0.1, 0.99]), + [0], [], + [['a', 'list']], + [['a', 'list'], 0], + [0, ['a', 'list'], 1], +]) +def test_validator_acceptance_any3_free(val, validator_any3_free): + coerce_val = validator_any3_free.validate_coerce(val) + assert coerce_val == list(val) + + # Compute expected + expected = tuple(tuple(el) if isinstance(el, list) else el for el in val) + assert validator_any3_free.present(coerce_val) == expected + + # Number2 2D # ---------- # ### Acceptance ###