Skip to content

Commit 3c77c28

Browse files
authored
Merge pull request #8165 from afvincent/fix_issue_8145_ls_validation
[MRG+2] FIX: Remove type checking for strings in '_validate_linestyle'
2 parents 8407ffc + ed04d93 commit 3c77c28

File tree

2 files changed

+65
-33
lines changed

2 files changed

+65
-33
lines changed

lib/matplotlib/rcsetup.py

+29-13
Original file line numberDiff line numberDiff line change
@@ -919,24 +919,40 @@ def _validate_linestyle(ls):
919919
A validator for all possible line styles, the named ones *and*
920920
the on-off ink sequences.
921921
"""
922-
# Named line style, like u'--' or u'solid'
923-
if isinstance(ls, six.text_type):
924-
return _validate_named_linestyle(ls)
925-
926-
# On-off ink (in points) sequence *of even length*.
922+
# Look first for a valid named line style, like '--' or 'solid'
923+
if isinstance(ls, six.string_types):
924+
try:
925+
return _validate_named_linestyle(ls)
926+
except (UnicodeDecodeError, KeyError):
927+
# On Python 2, string-like *ls*, like for example
928+
# 'solid'.encode('utf-16'), may raise a unicode error.
929+
raise ValueError("the linestyle string {!r} is not a valid "
930+
"string.".format(ls))
931+
932+
if isinstance(ls, (bytes, bytearray)):
933+
# On Python 2, a string-like *ls* should already have lead to a
934+
# successful return or to raising an exception. On Python 3, we have
935+
# to manually raise an exception in the case of a byte-like *ls*.
936+
# Otherwise, if *ls* is of even-length, it will be passed to the
937+
# instance of validate_nseq_float, which will return an absurd on-off
938+
# ink sequence...
939+
raise ValueError("linestyle {!r} neither looks like an on-off ink "
940+
"sequence nor a valid string.".format(ls))
941+
942+
# Look for an on-off ink sequence (in points) *of even length*.
927943
# Offset is set to None.
928944
try:
929945
if len(ls) % 2 != 0:
930-
# Expecting a sequence of even length
931-
raise ValueError
946+
raise ValueError("the linestyle sequence {!r} is not of even "
947+
"length.".format(ls))
948+
932949
return (None, validate_nseq_float()(ls))
933-
except (ValueError, TypeError):
934-
# TypeError can be raised by wrong types passed to float()
935-
# (called inside the instance of validate_nseq_float).
936-
pass
937950

938-
raise ValueError("linestyle must be a string or " +
939-
"an even-length sequence of floats.")
951+
except (ValueError, TypeError):
952+
# TypeError can be raised inside the instance of validate_nseq_float,
953+
# by wrong types passed to float(), like NoneType.
954+
raise ValueError("linestyle {!r} is not a valid on-off ink "
955+
"sequence.".format(ls))
940956

941957

942958
# a map from key -> value, converter

lib/matplotlib/tests/test_rcparams.py

+36-20
Original file line numberDiff line numberDiff line change
@@ -333,29 +333,45 @@ def generate_validator_testcases(valid):
333333
),
334334
'fail': (('aardvark', ValueError),
335335
)
336-
},
337-
{'validator': _validate_linestyle, # NB: case-insensitive
338-
'success': (('-', '-'), ('solid', 'solid'),
339-
('--', '--'), ('dashed', 'dashed'),
340-
('-.', '-.'), ('dashdot', 'dashdot'),
341-
(':', ':'), ('dotted', 'dotted'),
342-
('', ''), (' ', ' '),
343-
('None', 'none'), ('none', 'none'),
344-
('DoTtEd', 'dotted'),
345-
(['1.23', '4.56'], (None, [1.23, 4.56])),
346-
([1.23, 456], (None, [1.23, 456.0])),
347-
([1, 2, 3, 4], (None, [1.0, 2.0, 3.0, 4.0])),
348-
),
349-
'fail': (('aardvark', ValueError), # not a valid string
350-
((None, [1, 2]), ValueError), # (offset, dashes) is not OK
351-
((0, [1, 2]), ValueError), # idem
352-
((-1, [1, 2]), ValueError), # idem
353-
([1, 2, 3], ValueError), # not a sequence of even length
354-
(1.23, ValueError) # not a sequence
355-
)
356336
}
357337
)
358338

339+
# The behavior of _validate_linestyle depends on the version of Python.
340+
# ASCII-compliant bytes arguments should pass on Python 2 because of the
341+
# automatic conversion between bytes and strings. Python 3 does not
342+
# perform such a conversion, so the same cases should raise an exception.
343+
#
344+
# Common cases:
345+
ls_test = {'validator': _validate_linestyle,
346+
'success': (('-', '-'), ('solid', 'solid'),
347+
('--', '--'), ('dashed', 'dashed'),
348+
('-.', '-.'), ('dashdot', 'dashdot'),
349+
(':', ':'), ('dotted', 'dotted'),
350+
('', ''), (' ', ' '),
351+
('None', 'none'), ('none', 'none'),
352+
('DoTtEd', 'dotted'), # case-insensitive
353+
(['1.23', '4.56'], (None, [1.23, 4.56])),
354+
([1.23, 456], (None, [1.23, 456.0])),
355+
([1, 2, 3, 4], (None, [1.0, 2.0, 3.0, 4.0])),
356+
),
357+
'fail': (('aardvark', ValueError), # not a valid string
358+
('dotted'.encode('utf-16'), ValueError), # even on PY2
359+
((None, [1, 2]), ValueError), # (offset, dashes) != OK
360+
((0, [1, 2]), ValueError), # idem
361+
((-1, [1, 2]), ValueError), # idem
362+
([1, 2, 3], ValueError), # sequence with odd length
363+
(1.23, ValueError), # not a sequence
364+
)
365+
}
366+
# Add some cases of bytes arguments that Python 2 can convert silently:
367+
ls_bytes_args = (b'dotted', 'dotted'.encode('ascii'))
368+
if six.PY3:
369+
ls_test['fail'] += tuple((arg, ValueError) for arg in ls_bytes_args)
370+
else:
371+
ls_test['success'] += tuple((arg, 'dotted') for arg in ls_bytes_args)
372+
# Update the validation test sequence.
373+
validation_tests += (ls_test,)
374+
359375
for validator_dict in validation_tests:
360376
validator = validator_dict['validator']
361377
if valid:

0 commit comments

Comments
 (0)