Skip to content

ENH: Use rcParams savefig.directory on macosx backend #22180

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 2 commits into from
May 18, 2022
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
7 changes: 7 additions & 0 deletions lib/matplotlib/backends/backend_macosx.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os

import matplotlib as mpl
from matplotlib import cbook
from matplotlib._pylab_helpers import Gcf
Expand Down Expand Up @@ -118,10 +120,15 @@ def remove_rubberband(self):
self.canvas.remove_rubberband()

def save_figure(self, *args):
directory = os.path.expanduser(mpl.rcParams['savefig.directory'])
Copy link
Member

Choose a reason for hiding this comment

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

Is it possible to add a smoke test for this in the tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately I think this is another PR that would be quite hard to add a test for because it is using the GUI :( I did a global search and didn't see any of the other backends testing this either...

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 take that back, I just pushed up a test to hijack the GUI function and return a well-defined string instead. I think that should get codecov for the Python branches at least... Still not testing the Objective-C updates, but better than nothing?

filename = _macosx.choose_save_file('Save the figure',
directory,
self.canvas.get_default_filename())
if filename is None: # Cancel
return
# Save dir for next time, unless empty str (which means use cwd).
if mpl.rcParams['savefig.directory']:
mpl.rcParams['savefig.directory'] = os.path.dirname(filename)
self.canvas.figure.savefig(filename)

def prepare_configure_subplots(self):
Expand Down
34 changes: 30 additions & 4 deletions lib/matplotlib/tests/test_backend_macosx.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import os

import pytest

import matplotlib as mpl
import matplotlib.pyplot as plt


pytest.importorskip("matplotlib.backends.backend_macosx",
reason="These are mac only tests")
try:
from matplotlib.backends import _macosx
except ImportError:
pytest.skip("These are mac only tests", allow_module_level=True)


@pytest.mark.backend('macosx')
Expand All @@ -18,3 +21,26 @@ def test_cached_renderer():
fig = plt.figure(2)
fig.draw_without_rendering()
assert fig._cachedRenderer is not None


@pytest.mark.backend('macosx')
def test_savefig_rcparam(monkeypatch, tmp_path):

def new_choose_save_file(title, directory, filename):
# Replacement function instead of opening a GUI window
# Make a new directory for testing the update of the rcParams
assert directory == str(tmp_path)
os.makedirs(f"{directory}/test")
return f"{directory}/test/{filename}"

monkeypatch.setattr(_macosx, "choose_save_file", new_choose_save_file)
fig = plt.figure()
with mpl.rc_context({"savefig.directory": tmp_path}):
fig.canvas.toolbar.save_figure()
# Check the saved location got created
save_file = f"{tmp_path}/test/{fig.canvas.get_default_filename()}"
assert os.path.exists(save_file)

# Check the savefig.directory rcParam got updated because
# we added a subdirectory "test"
assert mpl.rcParams["savefig.directory"] == f"{tmp_path}/test"
25 changes: 8 additions & 17 deletions src/_macosx.m
Original file line number Diff line number Diff line change
Expand Up @@ -980,33 +980,24 @@ -(void)save_figure:(id)sender { gil_call_method(toolbar, "save_figure"); }
{
int result;
const char* title;
const char* directory;
const char* default_filename;
if (!PyArg_ParseTuple(args, "ss", &title, &default_filename)) {
if (!PyArg_ParseTuple(args, "sss", &title, &directory, &default_filename)) {
return NULL;
}
NSSavePanel* panel = [NSSavePanel savePanel];
[panel setTitle: [NSString stringWithCString: title
encoding: NSASCIIStringEncoding]];
NSString* ns_default_filename =
[[NSString alloc]
initWithCString: default_filename
encoding: NSUTF8StringEncoding];
[panel setNameFieldStringValue: ns_default_filename];
[panel setTitle: [NSString stringWithUTF8String: title]];
[panel setDirectoryURL: [NSURL fileURLWithPath: [NSString stringWithUTF8String: directory]
isDirectory: YES]];
[panel setNameFieldStringValue: [NSString stringWithUTF8String: default_filename]];
result = [panel runModal];
[ns_default_filename release];
if (result == NSModalResponseOK) {
NSURL* url = [panel URL];
NSString* filename = [url path];
NSString *filename = [[panel URL] path];
if (!filename) {
PyErr_SetString(PyExc_RuntimeError, "Failed to obtain filename");
return 0;
}
unsigned int n = [filename length];
unichar* buffer = malloc(n*sizeof(unichar));
[filename getCharacters: buffer];
PyObject* string = PyUnicode_FromKindAndData(PyUnicode_2BYTE_KIND, buffer, n);
free(buffer);
return string;
return PyUnicode_FromString([filename UTF8String]);
}
Py_RETURN_NONE;
}
Expand Down