Skip to content

Commit af5a9ef

Browse files
committed
Better handling for nested lists in validation
e.g. list that contains a pandas series.
1 parent c0a4098 commit af5a9ef

File tree

1 file changed

+25
-13
lines changed

1 file changed

+25
-13
lines changed

_plotly_utils/basevalidators.py

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ def fullmatch(regex, string, flags=0):
4141

4242
# Utility functions
4343
# -----------------
44+
def to_scalar_or_list(v):
45+
if isinstance(v, (list, tuple)):
46+
return [to_scalar_or_list(e) for e in v]
47+
elif np and isinstance(v, np.ndarray):
48+
return [to_scalar_or_list(e) for e in v]
49+
elif pd and isinstance(v, (pd.Series, pd.Index)):
50+
return [to_scalar_or_list(e) for e in v]
51+
else:
52+
return v
53+
54+
4455
def copy_to_readonly_numpy_array(v, dtype=None, force_numeric=False):
4556
"""
4657
Convert an array-like value into a read-only numpy array
@@ -73,7 +84,8 @@ def copy_to_readonly_numpy_array(v, dtype=None, force_numeric=False):
7384
numeric_kinds = ['u', 'i', 'f']
7485

7586
if not isinstance(v, np.ndarray):
76-
new_v = np.array(v, order='C', dtype=dtype)
87+
v_list = [to_scalar_or_list(e) for e in v]
88+
new_v = np.array(v_list, order='C', dtype=dtype)
7789
elif v.dtype.kind in numeric_kinds:
7890
new_v = np.ascontiguousarray(v.astype(dtype))
7991
else:
@@ -113,7 +125,7 @@ def is_homogeneous_array(v):
113125
Return whether a value is considered to be a homogeneous array
114126
"""
115127
return ((np and isinstance(v, np.ndarray)) or
116-
(pd and isinstance(v, pd.Series)))
128+
(pd and isinstance(v, (pd.Series, pd.Index))))
117129

118130

119131
def is_simple_array(v):
@@ -296,7 +308,7 @@ def validate_coerce(self, v):
296308
elif is_homogeneous_array(v):
297309
v = copy_to_readonly_numpy_array(v)
298310
elif is_simple_array(v):
299-
v = list(v)
311+
v = to_scalar_or_list(v)
300312
else:
301313
self.raise_invalid_val(v)
302314
return v
@@ -469,7 +481,7 @@ def validate_coerce(self, v):
469481
if is_homogeneous_array(v):
470482
v = copy_to_readonly_numpy_array(v)
471483
else:
472-
v = list(v)
484+
v = to_scalar_or_list(v)
473485
else:
474486
v = self.perform_replacemenet(v)
475487
if not self.in_values(v):
@@ -616,7 +628,7 @@ def validate_coerce(self, v):
616628
if invalid_els:
617629
self.raise_invalid_elements(invalid_els[:10])
618630

619-
v = list(v)
631+
v = to_scalar_or_list(v)
620632
else:
621633
# Check numeric
622634
if not isinstance(v, numbers.Number):
@@ -734,7 +746,7 @@ def validate_coerce(self, v):
734746
if invalid_els:
735747
self.raise_invalid_elements(invalid_els[:10])
736748

737-
v = list(v)
749+
v = to_scalar_or_list(v)
738750
else:
739751
# Check int
740752
if not isinstance(v, int):
@@ -858,7 +870,7 @@ def validate_coerce(self, v):
858870
if invalid_els:
859871
self.raise_invalid_elements(invalid_els)
860872

861-
v = list(v)
873+
v = to_scalar_or_list(v)
862874

863875
else:
864876
if self.strict:
@@ -1145,7 +1157,7 @@ def validate_coerce(self, v):
11451157
if invalid_els:
11461158
self.raise_invalid_elements(invalid_els)
11471159

1148-
v = list(v)
1160+
v = to_scalar_or_list(v)
11491161
else:
11501162
self.raise_invalid_val(v)
11511163
return v
@@ -1461,7 +1473,7 @@ def validate_coerce(self, v):
14611473
if is_homogeneous_array(v):
14621474
v = copy_to_readonly_numpy_array(validated_v, dtype='unicode')
14631475
else:
1464-
v = list(v)
1476+
v = to_scalar_or_list(v)
14651477
else:
14661478

14671479
validated_v = self.vc_scalar(v)
@@ -1511,7 +1523,7 @@ def validate_coerce(self, v):
15111523
elif self.array_ok and is_homogeneous_array(v):
15121524
v = copy_to_readonly_numpy_array(v, dtype='object')
15131525
elif self.array_ok and is_simple_array(v):
1514-
v = list(v)
1526+
v = to_scalar_or_list(v)
15151527
return v
15161528

15171529

@@ -1595,7 +1607,7 @@ def validate_coerce(self, v):
15951607
self.raise_invalid_val(v)
15961608
else:
15971609
# We have an array of the correct length
1598-
v = list(v)
1610+
v = to_scalar_or_list(v)
15991611
for i, (el, validator) in enumerate(zip(v, self.item_validators)):
16001612
# Validate coerce elements
16011613
v[i] = validator.validate_coerce(el)
@@ -1816,7 +1828,7 @@ def validate_coerce(self, v):
18161828
if invalid_els:
18171829
self.raise_invalid_elements(invalid_els)
18181830

1819-
v = list(res)
1831+
v = to_scalar_or_list(res)
18201832
else:
18211833
self.raise_invalid_val(v)
18221834

@@ -1915,7 +1927,7 @@ def validate_coerce(self, v):
19151927
if invalid_els:
19161928
self.raise_invalid_elements(invalid_els)
19171929

1918-
v = list(res)
1930+
v = to_scalar_or_list(res)
19191931

19201932
# Set new UIDs
19211933
for trace in v:

0 commit comments

Comments
 (0)