Skip to content

Commit 6689cc7

Browse files
committed
Implement Path.__deepcopy__ avoiding infinite recursion
To deep copy an object without calling deepcopy on the object itself, create a new object of the correct class and iterate calling deepcopy on its __dict__. Closes #29157 without relying on private CPython methods. Does not fix the other issue with TransformNode.__copy__.
1 parent 5a10e4d commit 6689cc7

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-4
lines changed

lib/matplotlib/path.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import numpy as np
1717

1818
import matplotlib as mpl
19+
1920
from . import _api, _path
2021
from .cbook import _to_unmasked_float_array, simple_linear_interpolation
2122
from .bezier import BezierSegment
@@ -280,8 +281,17 @@ def __deepcopy__(self, memo=None):
280281
Return a deepcopy of the `Path`. The `Path` will not be
281282
readonly, even if the source `Path` is.
282283
"""
283-
# Deepcopying arrays (vertices, codes) strips the writeable=False flag.
284-
p = copy.deepcopy(super(), memo)
284+
memo = memo or {}
285+
if id(self) in memo:
286+
return memo[id(self)]
287+
288+
cls = type(self)
289+
p = cls.__new__(cls)
290+
memo[id(self)] = p
291+
292+
for k, v in self.__dict__.items():
293+
setattr(p, k, copy.deepcopy(v, memo))
294+
285295
p._readonly = False
286296
return p
287297

lib/matplotlib/tests/test_path.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,15 +355,22 @@ def test_path_deepcopy():
355355
# Should not raise any error
356356
verts = [[0, 0], [1, 1]]
357357
codes = [Path.MOVETO, Path.LINETO]
358-
path1 = Path(verts)
359-
path2 = Path(verts, codes)
358+
path1 = Path(verts, readonly=True)
359+
path2 = Path(verts, codes, readonly=True)
360360
path1_copy = path1.deepcopy()
361361
path2_copy = path2.deepcopy()
362362
assert path1 is not path1_copy
363363
assert path1.vertices is not path1_copy.vertices
364+
assert np.all(path1.vertices == path1_copy.vertices)
365+
assert path1.readonly
366+
assert not path1_copy.readonly
364367
assert path2 is not path2_copy
365368
assert path2.vertices is not path2_copy.vertices
369+
assert np.all(path2.vertices == path2_copy.vertices)
366370
assert path2.codes is not path2_copy.codes
371+
assert all(path2.codes == path2_copy.codes)
372+
assert path2.readonly
373+
assert not path2_copy.readonly
367374

368375

369376
def test_path_shallowcopy():

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy