Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix problem with (deep)copy of TextPath #20921

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions lib/matplotlib/tests/test_textpath.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from copy import copy, deepcopy

from numpy.testing import assert_array_equal
from matplotlib.textpath import TextPath


def test_set_size():
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this get a docstring, even if very cursory? I can't really tell what it is supposed to be testing...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added a simple docstring. I have revisited the test and I think that it tests the required functionality.

"""Set size with zero offset should scale vertices and retain codes."""
path = TextPath((0, 0), ".")
_size = path.get_size()
verts = path.vertices.copy()
codes = path.codes.copy()
path.set_size(20)
assert_array_equal(verts/_size*path.get_size(), path.vertices)
assert_array_equal(codes, path.codes)


def test_deepcopy():
path = TextPath((0, 0), ".")
path_copy = deepcopy(path)
assert isinstance(path_copy, TextPath)
assert path is not path_copy
assert path.vertices is not path_copy.vertices
assert path.codes is not path_copy.codes
path = TextPath((0, 0), ".")
path_copy = path.deepcopy({})
assert isinstance(path_copy, TextPath)
assert path is not path_copy
assert path.vertices is not path_copy.vertices
assert path.codes is not path_copy.codes


def test_copy():
path = TextPath((0, 0), ".")
path_copy = copy(path)
assert path is not path_copy
assert path.vertices is path_copy.vertices
assert path.codes is path_copy.codes
path = TextPath((0, 0), ".")
path_copy = path.copy()
assert path is not path_copy
assert path.vertices is path_copy.vertices
assert path.codes is path_copy.codes
21 changes: 21 additions & 0 deletions lib/matplotlib/textpath.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from copy import deepcopy
from collections import OrderedDict
import functools
import logging
Expand Down Expand Up @@ -429,3 +430,23 @@ def _revalidate_path(self):
self._cached_vertices = tr.transform(self._vertices)
self._cached_vertices.flags.writeable = False
self._invalid = False

def __deepcopy__(self, memo):
"""Update path and create deep copy."""
self._revalidate_path()
cls = self.__class__
new_instance = cls.__new__(cls)
memo[id(self)] = new_instance
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need to fill in the memo yourself, copy.deepcopy already does that for you: https://github.com/python/cpython/blob/7c2a040a10654d67ff543a55858ba2d7a9f7eea8/Lib/copy.py#L175-L176

for k, v in self.__dict__.items():
setattr(new_instance, k, deepcopy(v, memo))
return new_instance

deepcopy = __deepcopy__
Copy link
Contributor

@anntzer anntzer Oct 5, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need this as a public method? I'd say copy.deepcopy(textpath) is good enough (and in fact, per https://github.com/matplotlib/matplotlib/pull/20921/files#r721988323, it does a bit more)?


def __copy__(self):
"""Update path and create shallow copy."""
self._revalidate_path()
cls = self.__class__
new_instance = cls.__new__(cls)
new_instance.__dict__.update(self.__dict__)
return new_instance