diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index 050e8901f98c..33c7d09a42c2 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -914,24 +914,40 @@ def _validate_linestyle(ls): A validator for all possible line styles, the named ones *and* the on-off ink sequences. """ - # Named line style, like u'--' or u'solid' - if isinstance(ls, six.text_type): - return _validate_named_linestyle(ls) - - # On-off ink (in points) sequence *of even length*. + # Look first for a valid named line style, like '--' or 'solid' + if isinstance(ls, six.string_types): + try: + return _validate_named_linestyle(ls) + except (UnicodeDecodeError, KeyError): + # On Python 2, string-like *ls*, like for example + # 'solid'.encode('utf-16'), may raise a unicode error. + raise ValueError("the linestyle string {!r} is not a valid " + "string.".format(ls)) + + if isinstance(ls, (bytes, bytearray)): + # On Python 2, a string-like *ls* should already have lead to a + # successful return or to raising an exception. On Python 3, we have + # to manually raise an exception in the case of a byte-like *ls*. + # Otherwise, if *ls* is of even-length, it will be passed to the + # instance of validate_nseq_float, which will return an absurd on-off + # ink sequence... + raise ValueError("linestyle {!r} neither looks like an on-off ink " + "sequence nor a valid string.".format(ls)) + + # Look for an on-off ink sequence (in points) *of even length*. # Offset is set to None. try: if len(ls) % 2 != 0: - # Expecting a sequence of even length - raise ValueError + raise ValueError("the linestyle sequence {!r} is not of even " + "length.".format(ls)) + return (None, validate_nseq_float()(ls)) - except (ValueError, TypeError): - # TypeError can be raised by wrong types passed to float() - # (called inside the instance of validate_nseq_float). - pass - raise ValueError("linestyle must be a string or " + - "an even-length sequence of floats.") + except (ValueError, TypeError): + # TypeError can be raised inside the instance of validate_nseq_float, + # by wrong types passed to float(), like NoneType. + raise ValueError("linestyle {!r} is not a valid on-off ink " + "sequence.".format(ls)) # a map from key -> value, converter diff --git a/lib/matplotlib/tests/test_rcparams.py b/lib/matplotlib/tests/test_rcparams.py index 4e689f6b9c47..e84a90ee34cf 100644 --- a/lib/matplotlib/tests/test_rcparams.py +++ b/lib/matplotlib/tests/test_rcparams.py @@ -333,29 +333,45 @@ def generate_validator_testcases(valid): ), 'fail': (('aardvark', ValueError), ) - }, - {'validator': _validate_linestyle, # NB: case-insensitive - 'success': (('-', '-'), ('solid', 'solid'), - ('--', '--'), ('dashed', 'dashed'), - ('-.', '-.'), ('dashdot', 'dashdot'), - (':', ':'), ('dotted', 'dotted'), - ('', ''), (' ', ' '), - ('None', 'none'), ('none', 'none'), - ('DoTtEd', 'dotted'), - (['1.23', '4.56'], (None, [1.23, 4.56])), - ([1.23, 456], (None, [1.23, 456.0])), - ([1, 2, 3, 4], (None, [1.0, 2.0, 3.0, 4.0])), - ), - 'fail': (('aardvark', ValueError), # not a valid string - ((None, [1, 2]), ValueError), # (offset, dashes) is not OK - ((0, [1, 2]), ValueError), # idem - ((-1, [1, 2]), ValueError), # idem - ([1, 2, 3], ValueError), # not a sequence of even length - (1.23, ValueError) # not a sequence - ) } ) + # The behavior of _validate_linestyle depends on the version of Python. + # ASCII-compliant bytes arguments should pass on Python 2 because of the + # automatic conversion between bytes and strings. Python 3 does not + # perform such a conversion, so the same cases should raise an exception. + # + # Common cases: + ls_test = {'validator': _validate_linestyle, + 'success': (('-', '-'), ('solid', 'solid'), + ('--', '--'), ('dashed', 'dashed'), + ('-.', '-.'), ('dashdot', 'dashdot'), + (':', ':'), ('dotted', 'dotted'), + ('', ''), (' ', ' '), + ('None', 'none'), ('none', 'none'), + ('DoTtEd', 'dotted'), # case-insensitive + (['1.23', '4.56'], (None, [1.23, 4.56])), + ([1.23, 456], (None, [1.23, 456.0])), + ([1, 2, 3, 4], (None, [1.0, 2.0, 3.0, 4.0])), + ), + 'fail': (('aardvark', ValueError), # not a valid string + ('dotted'.encode('utf-16'), ValueError), # even on PY2 + ((None, [1, 2]), ValueError), # (offset, dashes) != OK + ((0, [1, 2]), ValueError), # idem + ((-1, [1, 2]), ValueError), # idem + ([1, 2, 3], ValueError), # sequence with odd length + (1.23, ValueError), # not a sequence + ) + } + # Add some cases of bytes arguments that Python 2 can convert silently: + ls_bytes_args = (b'dotted', 'dotted'.encode('ascii')) + if six.PY3: + ls_test['fail'] += tuple((arg, ValueError) for arg in ls_bytes_args) + else: + ls_test['success'] += tuple((arg, 'dotted') for arg in ls_bytes_args) + # Update the validation test sequence. + validation_tests += (ls_test,) + for validator_dict in validation_tests: validator = validator_dict['validator'] if valid:
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: