From e7e6c8cea7dd174751be335f89369aeb3c1f40f0 Mon Sep 17 00:00:00 2001 From: Antony Lee Date: Fri, 14 Feb 2020 11:18:56 +0100 Subject: [PATCH] Factor out common parts of `__str__` for Transform subclasses. --- lib/matplotlib/projections/polar.py | 54 +++-------- lib/matplotlib/tests/test_transforms.py | 65 ++++++++++++++ lib/matplotlib/transforms.py | 113 +++++++++--------------- 3 files changed, 116 insertions(+), 116 deletions(-) diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py index 84212d4b726c..354482aafede 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -32,15 +32,10 @@ def __init__(self, axis=None, use_rmin=True, self._use_rmin = use_rmin self._apply_theta_transforms = _apply_theta_transforms - def __str__(self): - return ("{}(\n" - "{},\n" - " use_rmin={},\n" - " _apply_theta_transforms={})" - .format(type(self).__name__, - mtransforms._indent_str(self._axis), - self._use_rmin, - self._apply_theta_transforms)) + __str__ = mtransforms._make_str_method( + "_axis", + use_rmin="_use_rmin", + _apply_theta_transforms="_apply_theta_transforms") def transform_non_affine(self, tr): # docstring inherited @@ -86,13 +81,7 @@ def __init__(self, scale_transform, limits): self.set_children(scale_transform, limits) self._mtx = None - def __str__(self): - return ("{}(\n" - "{},\n" - "{})" - .format(type(self).__name__, - mtransforms._indent_str(self._scale_transform), - mtransforms._indent_str(self._limits))) + __str__ = mtransforms._make_str_method("_scale_transform", "_limits") def get_matrix(self): # docstring inherited @@ -124,15 +113,10 @@ def __init__(self, axis=None, use_rmin=True, self._use_rmin = use_rmin self._apply_theta_transforms = _apply_theta_transforms - def __str__(self): - return ("{}(\n" - "{},\n" - " use_rmin={},\n" - " _apply_theta_transforms={})" - .format(type(self).__name__, - mtransforms._indent_str(self._axis), - self._use_rmin, - self._apply_theta_transforms)) + __str__ = mtransforms._make_str_method( + "_axis", + use_rmin="_use_rmin", + _apply_theta_transforms="_apply_theta_transforms") def transform_non_affine(self, xy): # docstring inherited @@ -454,15 +438,7 @@ def __init__(self, axes, pad, mode): self.mode = mode self.pad = pad - def __str__(self): - return ("{}(\n" - "{},\n" - "{},\n" - "{})" - .format(type(self).__name__, - mtransforms._indent_str(self.axes), - mtransforms._indent_str(self.pad), - mtransforms._indent_str(repr(self.mode)))) + __str__ = mtransforms._make_str_method("axes", "pad", "mode") def get_matrix(self): if self._invalid: @@ -714,15 +690,7 @@ def __init__(self, center, viewLim, originLim, **kwargs): self._originLim = originLim self.set_children(viewLim, originLim) - def __str__(self): - return ("{}(\n" - "{},\n" - "{},\n" - "{})" - .format(type(self).__name__, - mtransforms._indent_str(self._center), - mtransforms._indent_str(self._viewLim), - mtransforms._indent_str(self._originLim))) + __str__ = mtransforms._make_str_method("_center", "_viewLim", "_originLim") def get_points(self): # docstring inherited diff --git a/lib/matplotlib/tests/test_transforms.py b/lib/matplotlib/tests/test_transforms.py index 909231506b2a..de56e427f119 100644 --- a/lib/matplotlib/tests/test_transforms.py +++ b/lib/matplotlib/tests/test_transforms.py @@ -492,6 +492,71 @@ def test_bbox_as_strings(): assert eval(format(getattr(b, k), fmt)) == v +def test_str_transform(): + # The str here should not be considered as "absolutely stable", and may be + # reformatted later; this is just a smoketest for __str__. + assert str(plt.subplot(projection="polar").transData) == """\ +CompositeGenericTransform( + CompositeGenericTransform( + CompositeGenericTransform( + TransformWrapper( + BlendedAffine2D( + IdentityTransform(), + IdentityTransform())), + CompositeAffine2D( + Affine2D( + [[1. 0. 0.] + [0. 1. 0.] + [0. 0. 1.]]), + Affine2D( + [[1. 0. 0.] + [0. 1. 0.] + [0. 0. 1.]]))), + PolarTransform( + PolarAxesSubplot(0.125,0.1;0.775x0.8), + use_rmin=True, + _apply_theta_transforms=False)), + CompositeGenericTransform( + CompositeGenericTransform( + PolarAffine( + TransformWrapper( + BlendedAffine2D( + IdentityTransform(), + IdentityTransform())), + LockableBbox( + Bbox(x0=0.0, y0=0.0, x1=6.283185307179586, y1=1.0), + [[-- --] + [-- --]])), + BboxTransformFrom( + _WedgeBbox( + (0.5, 0.5), + TransformedBbox( + Bbox(x0=0.0, y0=0.0, x1=6.283185307179586, y1=1.0), + CompositeAffine2D( + Affine2D( + [[1. 0. 0.] + [0. 1. 0.] + [0. 0. 1.]]), + Affine2D( + [[1. 0. 0.] + [0. 1. 0.] + [0. 0. 1.]]))), + LockableBbox( + Bbox(x0=0.0, y0=0.0, x1=6.283185307179586, y1=1.0), + [[-- --] + [-- --]])))), + BboxTransformTo( + TransformedBbox( + Bbox(x0=0.125, y0=0.09999999999999998, x1=0.9, y1=0.9), + BboxTransformTo( + TransformedBbox( + Bbox(x0=0.0, y0=0.0, x1=8.0, y1=6.0), + Affine2D( + [[80. 0. 0.] + [ 0. 80. 0.] + [ 0. 0. 1.]])))))))""" + + def test_transform_single_point(): t = mtransforms.Affine2D() r = t.transform_affine((1, 1)) diff --git a/lib/matplotlib/transforms.py b/lib/matplotlib/transforms.py index 3292340bf99d..6b773d85a7d9 100644 --- a/lib/matplotlib/transforms.py +++ b/lib/matplotlib/transforms.py @@ -33,7 +33,8 @@ # `np.minimum` instead of the builtin `min`, and likewise for `max`. This is # done so that `nan`s are propagated, instead of being silently dropped. -import re +import functools +import textwrap import weakref import numpy as np @@ -47,8 +48,32 @@ DEBUG = False -def _indent_str(obj): # textwrap.indent(str(obj), 4) on Py3. - return re.sub("(^|\n)", r"\1 ", str(obj)) +def _make_str_method(*args, **kwargs): + """ + Generate a ``__str__`` method for a `.Transform` subclass. + + After :: + + class T: + __str__ = _make_str_method("attr", key="other") + + ``str(T(...))`` will be + + .. code-block:: text + + {type(T).__name__}( + {self.attr}, + key={self.other}) + """ + indent = functools.partial(textwrap.indent, prefix=" " * 4) + def strrepr(x): return repr(x) if isinstance(x, str) else str(x) + return lambda self: ( + type(self).__name__ + "(" + + ",".join([*(indent("\n" + strrepr(getattr(self, arg))) + for arg in args), + *(indent("\n" + k + "=" + strrepr(getattr(self, arg))) + for k, arg in kwargs.items())]) + + ")") class TransformNode: @@ -1001,13 +1026,7 @@ def __init__(self, bbox, transform, **kwargs): self.set_children(bbox, transform) self._points = None - def __str__(self): - return ("{}(\n" - "{},\n" - "{})" - .format(type(self).__name__, - _indent_str(self._bbox), - _indent_str(self._transform))) + __str__ = _make_str_method("_bbox", "_transform") def get_points(self): # docstring inherited @@ -1086,13 +1105,7 @@ def __init__(self, bbox, x0=None, y0=None, x1=None, y1=None, **kwargs): mask = [val is None for val in fp] self._locked_points = np.ma.array(fp, float, mask=mask).reshape((2, 2)) - def __str__(self): - return ("{}(\n" - "{},\n" - "{})" - .format(type(self).__name__, - _indent_str(self._bbox), - _indent_str(self._locked_points))) + __str__ = _make_str_method("_bbox", "_locked_points") def get_points(self): # docstring inherited @@ -1625,11 +1638,7 @@ def _init(self, child): def __eq__(self, other): return self._child.__eq__(other) - def __str__(self): - return ("{}(\n" - "{})" - .format(type(self).__name__, - _indent_str(self._child))) + __str__ = _make_str_method("_child") def frozen(self): # docstring inherited @@ -1831,11 +1840,7 @@ def __init__(self, matrix=None, **kwargs): self._mtx = matrix self._invalid = 0 - def __str__(self): - return ("{}(\n" - "{})" - .format(type(self).__name__, - _indent_str(self._mtx))) + __str__ = _make_str_method("_mtx") @staticmethod def from_values(a, b, c, d, e, f): @@ -2032,9 +2037,7 @@ def frozen(self): # docstring inherited return self - def __str__(self): - return ("{}()" - .format(type(self).__name__)) + __str__ = _make_str_method() def get_matrix(self): # docstring inherited @@ -2088,13 +2091,7 @@ def contains_branch_seperately(self, transform): return (self._x.contains_branch(transform), self._y.contains_branch(transform)) - def __str__(self): - return ("{}(\n" - "{},\n" - "{})" - .format(type(self).__name__, - _indent_str(self._x), - _indent_str(self._y))) + __str__ = _make_str_method("_x", "_y") class BlendedGenericTransform(_BlendedMixin, Transform): @@ -2333,13 +2330,7 @@ def _iter_break_from_left_to_right(self): has_inverse = property( lambda self: self._a.has_inverse and self._b.has_inverse) - def __str__(self): - return ("{}(\n" - "{},\n" - "{})" - .format(type(self).__name__, - _indent_str(self._a), - _indent_str(self._b))) + __str__ = _make_str_method("_a", "_b") def transform_affine(self, points): # docstring inherited @@ -2419,13 +2410,7 @@ def _iter_break_from_left_to_right(self): for left, right in self._b._iter_break_from_left_to_right(): yield self._a + left, right - def __str__(self): - return ("{}(\n" - "{},\n" - "{})" - .format(type(self).__name__, - _indent_str(self._a), - _indent_str(self._b))) + __str__ = _make_str_method("_a", "_b") def get_matrix(self): # docstring inherited @@ -2486,13 +2471,7 @@ def __init__(self, boxin, boxout, **kwargs): self._mtx = None self._inverted = None - def __str__(self): - return ("{}(\n" - "{},\n" - "{})" - .format(type(self).__name__, - _indent_str(self._boxin), - _indent_str(self._boxout))) + __str__ = _make_str_method("_boxin", "_boxout") def get_matrix(self): # docstring inherited @@ -2534,11 +2513,7 @@ def __init__(self, boxout, **kwargs): self._mtx = None self._inverted = None - def __str__(self): - return ("{}(\n" - "{})" - .format(type(self).__name__, - _indent_str(self._boxout))) + __str__ = _make_str_method("_boxout") def get_matrix(self): # docstring inherited @@ -2592,11 +2567,7 @@ def __init__(self, boxin, **kwargs): self._mtx = None self._inverted = None - def __str__(self): - return ("{}(\n" - "{})" - .format(type(self).__name__, - _indent_str(self._boxin))) + __str__ = _make_str_method("_boxin") def get_matrix(self): # docstring inherited @@ -2628,11 +2599,7 @@ def __init__(self, xt, yt, scale_trans, **kwargs): self._mtx = None self._inverted = None - def __str__(self): - return ("{}(\n" - "{})" - .format(type(self).__name__, - _indent_str(self._t))) + __str__ = _make_str_method("_t") def get_matrix(self): # docstring inherited