10000 Backport PR #23462: Fix AttributeError for pickle load of Figure class by tacaswell · Pull Request #23515 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

Skip to content

Backport PR #23462: Fix AttributeError for pickle load of Figure class #23515

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

Merged
Merged
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
3 changes: 2 additions & 1 deletion lib/matplotlib/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -2919,7 +2919,8 @@ def __setstate__(self, state):
import matplotlib._pylab_helpers as pylab_helpers
allnums = plt.get_fignums()
num = max(allnums) + 1 if allnums else 1
mgr = plt._backend_mod.new_figure_manager_given_figure(num, self)
backend = plt._get_backend_mod()
mgr = backend.new_figure_manager_given_figure(num, self)
pylab_helpers.Gcf._set_new_active_manager(mgr)
plt.draw_if_interactive()

Expand Down
101 changes: 101 additions & 0 deletions lib/matplotlib/tests/test_pickle.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
from io import BytesIO
import ast
import pickle

import numpy as np
import pytest

from matplotlib import cm
from matplotlib.testing.decorators import image_comparison
import matplotlib as mpl
from matplotlib.testing import subprocess_run_helper
from matplotlib.testing.decorators import check_figures_equal
from matplotlib.dates import rrulewrapper
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms
Expand Down Expand Up @@ -110,6 +114,103 @@ def test_complete():
assert fig.get_label() == 'Figure with a label?'


def _pickle_load_subprocess():
import os
import pickle

path = os.environ['PICKLE_FILE_PATH']

with open(path, 'rb') as blob:
fig = pickle.load(blob)

print(str(pickle.dumps(fig)))


def _generate_complete_test_figure(fig_ref):
fig_ref.set_size_inches((10, 6))
plt.figure(fig_ref)

plt.suptitle('Can you fit any more in a figure?')

# make some arbitrary data
x, y = np.arange(8), np.arange(10)
data = u = v = np.linspace(0, 10, 80).reshape(10, 8)
v = np.sin(v * -0.6)

# Ensure lists also pickle correctly.
plt.subplot(3, 3, 1)
plt.plot(list(range(10)))

plt.subplot(3, 3, 2)
plt.contourf(data, hatches=['//', 'ooo'])
plt.colorbar()

plt.subplot(3, 3, 3)
plt.pcolormesh(data)

plt.subplot(3, 3, 4)
plt.imshow(data)

plt.subplot(3, 3, 5)
plt.pcolor(data)

ax = plt.subplot(3, 3, 6)
ax.set_xlim(0, 7)
ax.set_ylim(0, 9)
plt.streamplot(x, y, u, v)

ax = plt.subplot(3, 3, 7)
ax.set_xlim(0, 7)
ax.set_ylim(0, 9)
plt.quiver(x, y, u, v)

plt.subplot(3, 3, 8)
plt.scatter(x, x ** 2, label='$x^2$')
plt.legend(loc='upper left')

plt.subplot(3, 3, 9)
plt.errorbar(x, x * -0.5, xerr=0.2, yerr=0.4)


@mpl.style.context("default")
@check_figures_equal(extensions=['png'])
def test_pickle_load_from_subprocess(fig_test, fig_ref, tmp_path):
_generate_complete_test_figure(fig_ref)

fp = tmp_path / 'sinus.pickle'
assert not fp.exists()

with fp.open('wb') as file:
pickle.dump(fig_ref, file, pickle.HIGHEST_PROTOCOL)
assert fp.exists()

proc = subprocess_run_helper(
_pickle_load_subprocess,
timeout=60,
PICKLE_FILE_PATH=str(fp),
)

loaded_fig = pickle.loads(ast.literal_eval(proc.stdout))

loaded_fig.canvas.draw()

fig_test.set_size_inches(loaded_fig.get_size_inches())
fig_test.figimage(loaded_fig.canvas.renderer.buffer_rgba())

plt.close(loaded_fig)


def test_gcf():
fig = plt.figure("a label")
buf = BytesIO()
pickle.dump(fig, buf, pickle.HIGHEST_PROTOCOL)
plt.close("all")
assert plt._pylab_helpers.Gcf.figs == {} # No figures must be left.
fig = pickle.loads(buf.getbuffer())
assert plt._pylab_helpers.Gcf.figs != {} # A manager is there again.
assert fig.get_label() == "a label"


def test_no_pyplot():
# tests pickle-ability of a figure not created with pyplot
from matplotlib.backends.backend_pdf import FigureCanvasPdf
Expand Down
0