From 4d01858904ef0cc262512388bb1830bead5e8f15 Mon Sep 17 00:00:00 2001 From: Jan Schulz Date: Mon, 28 Oct 2013 21:18:29 +0100 Subject: [PATCH] Make it possible to add mpl.rcParams to itself or deepcopy Before it was not possible to set all rcParams to mpl.rcParams or use copy.deepcopy on mpl.rcParams. There were two problems: 1. validate_bool_maybe_none(None) was raising ValueError -> fixed by accepting this value 2. svg.embed_char_paths was deprecated by svg.fonttype but both have different valid values (bool vs strings). -> fixed by adding a "value translation" lambda to deprecatedmap which translates the boolean values to the string values of svg.fonttype. Also changed all validators, which accept None to check strings without case ("none" vs "None"). Test for this: mpl.tests.test_rcparams.test_Bug_2543() Closes: #2543 --- lib/matplotlib/__init__.py | 34 +++++++++++++---------- lib/matplotlib/rcsetup.py | 9 +++--- lib/matplotlib/tests/test_rcparams.py | 40 +++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 19 deletions(-) diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 930f1ed3b26d..d336064f6319 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -762,14 +762,14 @@ def matplotlib_fname(): _deprecated_map = { - 'text.fontstyle': 'font.style', - 'text.fontangle': 'font.style', - 'text.fontvariant': 'font.variant', - 'text.fontweight': 'font.weight', - 'text.fontsize': 'font.size', - 'tick.size' : 'tick.major.size', - 'svg.embed_char_paths' : 'svg.fonttype', - 'savefig.extension' : 'savefig.format' + 'text.fontstyle': ('font.style',lambda x: x), + 'text.fontangle': ('font.style',lambda x: x), + 'text.fontvariant': ('font.variant',lambda x: x), + 'text.fontweight': ('font.weight',lambda x: x), + 'text.fontsize': ('font.size',lambda x: x), + 'tick.size' : ('tick.major.size',lambda x: x), + 'svg.embed_char_paths' : ('svg.fonttype',lambda x: "path" if x else "none"), + 'savefig.extension' : ('savefig.format',lambda x: x), } _deprecated_ignore_map = { @@ -793,14 +793,18 @@ class RcParams(dict): def __setitem__(self, key, val): try: if key in _deprecated_map: - alt = _deprecated_map[key] - warnings.warn(self.msg_depr % (key, alt)) - key = alt + alt_key, alt_val = _deprecated_map[key] + warnings.warn(self.msg_depr % (key, alt_key)) + key = alt_key + val = alt_val(val) elif key in _deprecated_ignore_map: alt = _deprecated_ignore_map[key] warnings.warn(self.msg_depr_ignore % (key, alt)) return - cval = self.validate[key](val) + try: + cval = self.validate[key](val) + except ValueError as ve: + raise ValueError("Key %s: %s" % (key, str(ve))) dict.__setitem__(self, key, cval) except KeyError: raise KeyError('%s is not a valid rc parameter.\ @@ -808,9 +812,9 @@ def __setitem__(self, key, val): def __getitem__(self, key): if key in _deprecated_map: - alt = _deprecated_map[key] - warnings.warn(self.msg_depr % (key, alt)) - key = alt + alt_key, alt_val = _deprecated_map[key] + warnings.warn(self.msg_depr % (key, alt_key)) + key = alt_key elif key in _deprecated_ignore_map: alt = _deprecated_ignore_map[key] warnings.warn(self.msg_depr_ignore % (key, alt)) diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index 60d6e3c12e13..96b56f62e07a 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -88,7 +88,7 @@ def validate_bool_maybe_none(b): 'Convert b to a boolean or raise' if isinstance(b, six.string_types): b = b.lower() - if b == 'none': + if b is None or b == 'none': return None if b in ('t', 'y', 'yes', 'on', 'true', '1', 1, True): return True @@ -336,7 +336,6 @@ def update_savefig_format(value): def validate_ps_distiller(s): if isinstance(s, six.string_types): s = s.lower() - if s in ('none', None): return None elif s in ('false', False): @@ -395,7 +394,7 @@ def deprecate_svg_embed_char_paths(value): warnings.warn("svg.embed_char_paths is deprecated. Use " "svg.fonttype instead.") -validate_svg_fonttype = ValidateInStrings('fonttype', +validate_svg_fonttype = ValidateInStrings('svg.fonttype', ['none', 'path', 'svgfont']) @@ -430,7 +429,9 @@ def validate_bbox(s): raise ValueError("bbox should be 'tight' or 'standard'") def validate_sketch(s): - if s == 'None' or s is None: + if isinstance(s, six.string_types): + s = s.lower() + if s == 'none' or s is None: return None if isinstance(s, six.string_types): result = tuple([float(v.strip()) for v in s.split(',')]) diff --git a/lib/matplotlib/tests/test_rcparams.py b/lib/matplotlib/tests/test_rcparams.py index dac2248b45ca..9d6d0613db76 100644 --- a/lib/matplotlib/tests/test_rcparams.py +++ b/lib/matplotlib/tests/test_rcparams.py @@ -4,9 +4,12 @@ import six import os +import sys import matplotlib as mpl from matplotlib.tests import assert_str_equal +from nose.tools import assert_true, assert_raises +import nose mpl.rc('text', usetex=False) @@ -92,6 +95,43 @@ def test_RcParams_class(): assert ['font.cursive', 'font.size'] == sorted(rc.find_all('i[vz]').keys()) assert ['font.family'] == list(six.iterkeys(rc.find_all('family'))) +def test_Bug_2543(): + # Test that it possible to add all values to itself / deepcopy + # This was not possible because validate_bool_maybe_none did not + # accept None as an argument. + # https://github.com/matplotlib/matplotlib/issues/2543 + with mpl.rc_context(): + _copy = mpl.rcParams.copy() + for key in six.iterkeys(_copy): + mpl.rcParams[key] = _copy[key] + mpl.rcParams['text.dvipnghack'] = None + with mpl.rc_context(): + from copy import deepcopy + _deep_copy = deepcopy(mpl.rcParams) + from matplotlib.rcsetup import validate_bool_maybe_none, validate_bool + # real test is that this does not raise + assert_true(validate_bool_maybe_none(None) is None) + assert_true(validate_bool_maybe_none("none") is None) + _fonttype = mpl.rcParams['svg.fonttype'] + assert_true(_fonttype == mpl.rcParams['svg.embed_char_paths']) + with mpl.rc_context(): + mpl.rcParams['svg.embed_char_paths'] = False + assert_true(mpl.rcParams['svg.fonttype'] == "none") + +def test_Bug_2543_newer_python(): + # only split from above because of the usage of assert_raises + # as a context manager, which only works in 2.7 and above + if sys.version_info[:2] < (2, 7): + raise nose.SkipTest("assert_raises as context manager not supported with Python < 2.7") + from matplotlib.rcsetup import validate_bool_maybe_none, validate_bool + with assert_raises(ValueError): + validate_bool_maybe_none("blah") + with assert_raises(ValueError): + validate_bool(None) + with assert_raises(ValueError): + with mpl.rc_context(): + mpl.rcParams['svg.fonttype'] = True + if __name__ == '__main__': import nose nose.runmodule(argv=['-s', '--with-doctest'], exit=False)