From 191452dd3ec97f13138157bc8786d0f60126130f Mon Sep 17 00:00:00 2001 From: Jakub Klus Date: Sat, 24 Jul 2021 11:22:49 +0200 Subject: [PATCH 1/2] Improved implementation of Path.copy and deepcopy The original Path.copy raised RecursionError, new implementation mimicks deepcopy, creating shared members. Path tests were updated to utilize member functions copy and deepcopy instead of builtin copy functional protocol. --- lib/matplotlib/path.py | 9 +++++++-- lib/matplotlib/tests/test_path.py | 25 ++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/lib/matplotlib/path.py b/lib/matplotlib/path.py index bfc3250df647..17df7c19026e 100644 --- a/lib/matplotlib/path.py +++ b/lib/matplotlib/path.py @@ -264,8 +264,13 @@ def __copy__(self): Return a shallow copy of the `Path`, which will share the vertices and codes with the source `Path`. """ - import copy - return copy.copy(self) + try: + codes = self.codes + except AttributeError: + codes = None + return self.__class__( + self.vertices, codes, + _interpolation_steps=self._interpolation_steps) copy = __copy__ diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index ed818257bb17..69aa7c5bec21 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -1,4 +1,3 @@ -import copy import re import numpy as np @@ -333,8 +332,28 @@ def test_path_deepcopy(): codes = [Path.MOVETO, Path.LINETO] path1 = Path(verts) path2 = Path(verts, codes) - copy.deepcopy(path1) - copy.deepcopy(path2) + path1_copy = path1.deepcopy() + path2_copy = path2.deepcopy() + assert(path1 is not path1_copy) + assert(path1.vertices is not path1_copy.vertices) + assert(path2 is not path2_copy) + assert(path2.vertices is not path2_copy.vertices) + assert(path2.codes is not path2_copy.codes) + + +def test_path_shallowcopy(): + # Should not raise any error + verts = [[0, 0], [1, 1]] + codes = [Path.MOVETO, Path.LINETO] + path1 = Path(verts) + path2 = Path(verts, codes) + path1_copy = path1.copy() + path2_copy = path2.copy() + assert(path1 is not path1_copy) + assert(path1.vertices is path1_copy.vertices) + assert(path2 is not path2_copy) + assert(path2.vertices is path2_copy.vertices) + assert(path2.codes is path2_copy.codes) @pytest.mark.parametrize('phi', np.concatenate([ From dda3a9aaeafd6f3bb0499ba5dd7c24aba2699e1a Mon Sep 17 00:00:00 2001 From: Jakub Klus Date: Sat, 24 Jul 2021 17:54:45 +0200 Subject: [PATCH 2/2] Use builtin copy for shallow copy --- lib/matplotlib/path.py | 13 +++---------- lib/matplotlib/tests/test_path.py | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/lib/matplotlib/path.py b/lib/matplotlib/path.py index 17df7c19026e..45826439b91f 100644 --- a/lib/matplotlib/path.py +++ b/lib/matplotlib/path.py @@ -9,6 +9,7 @@ visualisation. """ +import copy from functools import lru_cache from weakref import WeakValueDictionary @@ -259,20 +260,12 @@ def readonly(self): """ return self._readonly - def __copy__(self): + def copy(self): """ Return a shallow copy of the `Path`, which will share the vertices and codes with the source `Path`. """ - try: - codes = self.codes - except AttributeError: - codes = None - return self.__class__( - self.vertices, codes, - _interpolation_steps=self._interpolation_steps) - - copy = __copy__ + return copy.copy(self) def __deepcopy__(self, memo=None): """ diff --git a/lib/matplotlib/tests/test_path.py b/lib/matplotlib/tests/test_path.py index 69aa7c5bec21..be8e9d2b6ced 100644 --- a/lib/matplotlib/tests/test_path.py +++ b/lib/matplotlib/tests/test_path.py @@ -334,11 +334,11 @@ def test_path_deepcopy(): path2 = Path(verts, codes) path1_copy = path1.deepcopy() path2_copy = path2.deepcopy() - assert(path1 is not path1_copy) - assert(path1.vertices is not path1_copy.vertices) - assert(path2 is not path2_copy) - assert(path2.vertices is not path2_copy.vertices) - assert(path2.codes is not path2_copy.codes) + assert path1 is not path1_copy + assert path1.vertices is not path1_copy.vertices + assert path2 is not path2_copy + assert path2.vertices is not path2_copy.vertices + assert path2.codes is not path2_copy.codes def test_path_shallowcopy(): @@ -349,11 +349,11 @@ def test_path_shallowcopy(): path2 = Path(verts, codes) path1_copy = path1.copy() path2_copy = path2.copy() - assert(path1 is not path1_copy) - assert(path1.vertices is path1_copy.vertices) - assert(path2 is not path2_copy) - assert(path2.vertices is path2_copy.vertices) - assert(path2.codes is path2_copy.codes) + assert path1 is not path1_copy + assert path1.vertices is path1_copy.vertices + assert path2 is not path2_copy + assert path2.vertices is path2_copy.vertices + assert path2.codes is path2_copy.codes @pytest.mark.parametrize('phi', np.concatenate([