Skip to content

Fix string validation on unicode strings in Python 2.7 #1380

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions _plotly_utils/basevalidators.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,17 @@ def __init__(self,
self.array_ok = array_ok
self.values = values

@staticmethod
def to_str_or_unicode_or_none(v):
"""
Convert a value to a string if it's not None, a string,
or a unicode (on Python 2).
"""
if v is None or isinstance(v, string_types):
return v
else:
return str(v)

def description(self):
desc = ("""\
The '{plotly_name}' property is a string and must be specified as:"""
Expand Down Expand Up @@ -938,10 +949,8 @@ def validate_coerce(self, v):

elif is_simple_array(v):
if not self.strict:
# Convert all elements other than None to strings
# Leave None as is, Plotly.js will decide how to handle
# these null values.
v = [str(e) if e is not None else None for e in v]
v = [StringValidator.to_str_or_unicode_or_none(e)
for e in v]

# Check no_blank
if self.no_blank:
Expand All @@ -962,12 +971,14 @@ def validate_coerce(self, v):
if not isinstance(v, string_types):
self.raise_invalid_val(v)
else:
if not isinstance(v, string_types + (int, float)):
if isinstance(v, string_types):
pass
elif isinstance(v, (int, float)):
# Convert value to a string
v = str(v)
else:
self.raise_invalid_val(v)

# Convert value to a string
v = str(v)

if self.no_blank and len(v) == 0:
self.raise_invalid_val(v)

Expand Down
19 changes: 11 additions & 8 deletions _plotly_utils/tests/validators/test_string_validator.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import pytest
from six import string_types

from _plotly_utils.basevalidators import StringValidator
import numpy as np

Expand Down Expand Up @@ -50,9 +52,10 @@ def validator_no_blanks_aok():
# ### Acceptance ###
@pytest.mark.parametrize('val',
['bar', 234, np.nan,
'HELLO!!!', 'world!@#$%^&*()', ''])
'HELLO!!!', 'world!@#$%^&*()', '', u'\u03BC'])
def test_acceptance(val, validator):
assert validator.validate_coerce(val) == str(val)
expected = str(val) if not isinstance(val, string_types) else val
assert validator.validate_coerce(val) == expected


# ### Rejection by value ###
Expand Down Expand Up @@ -85,7 +88,7 @@ def test_rejection_values(val, validator_values):

# ### No blanks ###
@pytest.mark.parametrize('val',
['bar', 'HELLO!!!', 'world!@#$%^&*()'])
['bar', 'HELLO!!!', 'world!@#$%^&*()', u'\u03BC'])
def test_acceptance_no_blanks(val, validator_no_blanks):
assert validator_no_blanks.validate_coerce(val) == val

Expand All @@ -103,7 +106,7 @@ def test_rejection_no_blanks(val, validator_no_blanks):
# ------
# ### Acceptance ###
@pytest.mark.parametrize('val',
['bar', 'HELLO!!!', 'world!@#$%^&*()', ''])
['bar', 'HELLO!!!', 'world!@#$%^&*()', '', u'\u03BC'])
def test_acceptance_strict(val, validator_strict):
assert validator_strict.validate_coerce(val) == val

Expand All @@ -122,17 +125,17 @@ def test_rejection_strict(val, validator_strict):
# --------
# ### Acceptance ###
@pytest.mark.parametrize('val',
['foo', 'BAR', '', 'baz'])
['foo', 'BAR', '', 'baz', u'\u03BC'])
def test_acceptance_aok_scalars(val, validator_aok):
assert validator_aok.validate_coerce(val) == val


@pytest.mark.parametrize('val',
['foo',
['foo'],
np.array(['BAR', ''], dtype='object'),
np.array(['BAR', '', u'\u03BC'], dtype='object'),
['baz', 'baz', 'baz'],
['foo', None, 'bar']])
['foo', None, 'bar', u'\u03BC']])
def test_acceptance_aok_list(val, validator_aok):
coerce_val = validator_aok.validate_coerce(val)
if isinstance(val, np.ndarray):
Expand Down Expand Up @@ -173,7 +176,7 @@ def test_rejection_aok_values(val, validator_aok_values):
['123',
['bar', 'HELLO!!!'],
np.array(['bar', 'HELLO!!!'], dtype='object'),
['world!@#$%^&*()']])
['world!@#$%^&*()', u'\u03BC']])
def test_acceptance_no_blanks_aok(val, validator_no_blanks_aok):
coerce_val = validator_no_blanks_aok.validate_coerce(val)
if isinstance(val, np.ndarray):
Expand Down