FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Warn on invalid savefig keyword arguments by QuLogic · Pull Request #17223 · matplotlib/matplotlib · GitHub

Repository navigation

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

Filter by extension

Filter by extension .py  (9) All 1 file type selected
Viewed files
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Unified
Split
Hide whitespace
Diff view
Unified
Split
Hide whitespace
67 changes: 67 additions & 0 deletions lib/matplotlib/backend_bases.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,14 @@
from enum import Enum, IntEnum
import functools
import importlib
import inspect
import io
import logging
import os
import re
import sys
import time
import traceback
from weakref import WeakKeyDictionary

import numpy as np
Expand Down Expand Up @@ -1567,6 +1570,70 @@ def _is_non_interactive_terminal_ipython(ip):
and getattr(ip.parent, 'interact', None) is False)


def _check_savefig_extra_args(func=None, extra_kwargs=()):
"""
Decorator for the final print_* methods that accept keyword arguments.

If any unused keyword arguments are left, this decorator will warn about
them, and as part of the warning, will attempt to specify the function that
the user actually called, instead of the backend-specific method. If unable
to determine which function the user called, it will specify `.savefig`.

For compatibility across backends, this does not warn about keyword
arguments added by `FigureCanvasBase.print_figure` for use in a subset of
backends, because the user would not have added them directly.
"""

if func is None:
return functools.partial(_check_savefig_extra_args,
extra_kwargs=extra_kwargs)

old_sig = inspect.signature(func)

@functools.wraps(func)
def wrapper(*args, **kwargs):
name = 'savefig' # Reasonable default guess.
public_api = re.compile(r'^savefig|print_[A-Za-z0-9]+$')
seen_print_figure = False
for frame, line in traceback.walk_stack(None):
if frame is None:
# when called in embedded context may hit frame is None.
break
if re.match(r'\A(matplotlib|mpl_toolkits)(\Z|\.(?!tests\.))',
# Work around sphinx-gallery not setting __name__.
frame.f_globals.get('__name__', '')):
if public_api.match(frame.f_code.co_name):
name = frame.f_code.co_name
if name == 'print_figure':
seen_print_figure = True
else:
break

accepted_kwargs = {*old_sig.parameters, *extra_kwargs}
if seen_print_figure:
for kw in ['dpi', 'facecolor', 'edgecolor', 'orientation',
'bbox_inches_restore']:
# Ignore keyword arguments that are passed in by print_figure
# for the use of other renderers.
if kw not in accepted_kwargs:
kwargs.pop(kw, None)

for arg in list(kwargs):
if arg in accepted_kwargs:
continue
cbook.warn_deprecated(
'3.3', name=name,
message='%(name)s() got unexpected keyword argument "'
+ arg + '" which is no longer supported as of '
'%(since)s and will become an error '
'%(removal)s')
kwargs.pop(arg)

return func(*args, **kwargs)

return wrapper


class FigureCanvasBase:
"""
The canvas the figure renders into.
Expand Down
18 changes: 11 additions & 7 deletions lib/matplotlib/backends/backend_agg.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
from matplotlib import cbook
from matplotlib import colors as mcolors
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
_Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
RendererBase)
from matplotlib.font_manager import findfont, get_font
from matplotlib.ft2font import (LOAD_FORCE_AUTOHINT, LOAD_NO_HINTING,
LOAD_DEFAULT, LOAD_NO_AUTOHINT)
Expand Down Expand Up @@ -447,17 +448,18 @@ def buffer_rgba(self):
"""
return self.renderer.buffer_rgba()

def print_raw(self, filename_or_obj, *args, **kwargs):
@_check_savefig_extra_args
def print_raw(self, filename_or_obj, *args):
FigureCanvasAgg.draw(self)
renderer = self.get_renderer()
with cbook.open_file_cm(filename_or_obj, "wb") as fh:
fh.write(renderer.buffer_rgba())

print_rgba = print_raw

@_check_savefig_extra_args
def print_png(self, filename_or_obj, *args,
metadata=None, pil_kwargs=None,
**kwargs):
metadata=None, pil_kwargs=None):
"""
Write the figure to a PNG file.

Expand Down Expand Up @@ -519,6 +521,8 @@ def print_to_buffer(self):
# print_figure(), and the latter ensures that `self.figure.dpi` already
# matches the dpi kwarg (if any).

@_check_savefig_extra_args(
extra_kwargs=["quality", "optimize", "progressive"])
@cbook._delete_parameter("3.2", "dryrun")
@cbook._delete_parameter("3.3", "quality",
alternative="pil_kwargs={'quality': ...}")
Expand Down Expand Up @@ -572,7 +576,7 @@ def print_jpg(self, filename_or_obj, *args, dryrun=False, pil_kwargs=None,
pil_kwargs = {}
for k in ["quality", "optimize", "progressive"]:
if k in kwargs:
pil_kwargs.setdefault(k, kwargs[k])
pil_kwargs.setdefault(k, kwargs.pop(k))
if "quality" not in pil_kwargs:
quality = pil_kwargs["quality"] = \
dict.__getitem__(mpl.rcParams, "savefig.jpeg_quality")
Expand All @@ -590,9 +594,9 @@ def print_jpg(self, filename_or_obj, *args, dryrun=False, pil_kwargs=None,

print_jpeg = print_jpg

@_check_savefig_extra_args
@cbook._delete_parameter("3.2", "dryrun")
def print_tif(self, filename_or_obj, *args, dryrun=False, pil_kwargs=None,
**kwargs):
def print_tif(self, filename_or_obj, *, dryrun=False, pil_kwargs=None):
FigureCanvasAgg.draw(self)
if dryrun:
return
Expand Down
13 changes: 8 additions & 5 deletions lib/matplotlib/backends/backend_cairo.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@

from .. import cbook, font_manager
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
RendererBase)
_Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
GraphicsContextBase, RendererBase)
from matplotlib.font_manager import ttfFontProperty
from matplotlib.mathtext import MathTextParser
from matplotlib.path import Path
Expand Down Expand Up @@ -444,10 +444,12 @@ def restore_region(self, region):
surface.mark_dirty_rectangle(
slx.start, sly.start, slx.stop - slx.start, sly.stop - sly.start)

def print_png(self, fobj, *args, **kwargs):
@_check_savefig_extra_args
def print_png(self, fobj):
self._get_printed_image_surface().write_to_png(fobj)

def print_rgba(self, fobj, *args, **kwargs):
@_check_savefig_extra_args
def print_rgba(self, fobj):
width, height = self.get_width_height()
buf = self._get_printed_image_surface().get_data()
fobj.write(cbook._premultiplied_argb32_to_unmultiplied_rgba8888(
Expand Down Expand Up @@ -476,7 +478,8 @@ def print_svg(self, fobj, *args, **kwargs):
def print_svgz(self, fobj, *args, **kwargs):
return self._save(fobj, 'svgz', *args, **kwargs)

def _save(self, fo, fmt, *, orientation='portrait', **kwargs):
@_check_savefig_extra_args
def _save(self, fo, fmt, *, orientation='portrait'):
# save PDF/PS/SVG

dpi = 72
Expand Down
9 changes: 5 additions & 4 deletions lib/matplotlib/backends/backend_pdf.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
from matplotlib import _text_layout, cbook
from matplotlib._pylab_helpers import Gcf
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
RendererBase)
_Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
GraphicsContextBase, RendererBase)
from matplotlib.backends.backend_mixed import MixedModeRenderer
from matplotlib.figure import Figure
from matplotlib.font_manager import findfont, is_opentype_cff_font, get_font
Expand Down Expand Up @@ -2573,10 +2573,11 @@ class FigureCanvasPdf(FigureCanvasBase):
def get_default_filetype(self):
return 'pdf'

@_check_savefig_extra_args
def print_pdf(self, filename, *,
dpi=72, # dpi to use for images
bbox_inches_restore=None, metadata=None,
**kwargs):
bbox_inches_restore=None, metadata=None):

self.figure.set_dpi(72) # there are 72 pdf points to an inch
width, height = self.figure.get_size_inches()
if isinstance(filename, PdfPages):
Expand Down
10 changes: 6 additions & 4 deletions lib/matplotlib/backends/backend_pgf.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
import matplotlib as mpl
from matplotlib import cbook, font_manager as fm
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
RendererBase)
_Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
GraphicsContextBase, RendererBase)
from matplotlib.backends.backend_mixed import MixedModeRenderer
from matplotlib.backends.backend_pdf import (
_create_pdf_info_dict, _datetime_to_pdf)
Expand Down Expand Up @@ -802,9 +802,11 @@ class FigureCanvasPgf(FigureCanvasBase):
def get_default_filetype(self):
return 'pdf'

@_check_savefig_extra_args
@cbook._delete_parameter("3.2", "dryrun")
def _print_pgf_to_fh(self, fh, *args,
dryrun=False, bbox_inches_restore=None, **kwargs):
def _print_pgf_to_fh(self, fh, *,
dryrun=False, bbox_inches_restore=None):

if dryrun:
renderer = RendererPgf(self.figure, None, dummy=True)
self.figure.draw(renderer)
Expand Down
10 changes: 6 additions & 4 deletions lib/matplotlib/backends/backend_ps.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@
from matplotlib import cbook, _path
from matplotlib import _text_layout
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
RendererBase)
_Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
GraphicsContextBase, RendererBase)
from matplotlib.cbook import is_writable_file_like, file_requires_unicode
from matplotlib.font_manager import is_opentype_cff_font, get_font
from matplotlib.ft2font import LOAD_NO_HINTING
Expand Down Expand Up @@ -808,11 +808,12 @@ def _print_ps(
printer(outfile, format, dpi=dpi, dsc_comments=dsc_comments,
orientation=orientation, papertype=papertype, **kwargs)

@_check_savefig_extra_args
@cbook._delete_parameter("3.2", "dryrun")
def _print_figure(
self, outfile, format, *,
dpi, dsc_comments, orientation, papertype,
dryrun=False, bbox_inches_restore=None, **kwargs):
dryrun=False, bbox_inches_restore=None):
"""
Render the figure to a filesystem path or a file-like object.

Expand Down Expand Up @@ -985,11 +986,12 @@ def print_figure_impl(fh):
with open(outfile, 'w', encoding='latin-1') as fh:
print_figure_impl(fh)

@_check_savefig_extra_args
@cbook._delete_parameter("3.2", "dryrun")
def _print_figure_tex(
self, outfile, format, *,
dpi, dsc_comments, orientation, papertype,
dryrun=False, bbox_inches_restore=None, **kwargs):
dryrun=False, bbox_inches_restore=None):
"""
If :rc:`text.usetex` is True, a temporary pair of tex/eps files
are created to allow tex to manage the text layout via the PSFrags
Expand Down
6 changes: 4 additions & 2 deletions lib/matplotlib/backends/backend_svg.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
import matplotlib as mpl
from matplotlib import cbook
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, RendererBase)
_Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
RendererBase)
from matplotlib.backends.backend_mixed import MixedModeRenderer
from matplotlib.colors import rgb2hex
from matplotlib.dates import UTC
Expand Down Expand Up @@ -1328,8 +1329,9 @@ def print_svgz(self, filename, *args, **kwargs):
gzip.GzipFile(mode='w', fileobj=fh) as gzipwriter:
return self.print_svg(gzipwriter)

@_check_savefig_extra_args
def _print_svg(self, filename, fh, *, dpi=72, bbox_inches_restore=None,
metadata=None, **kwargs):
metadata=None):
self.figure.set_dpi(72.0)
width, height = self.figure.get_size_inches()
w, h = width * 72, height * 72
Expand Down
17 changes: 9 additions & 8 deletions lib/matplotlib/backends/backend_wx.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@

import matplotlib as mpl
from matplotlib.backend_bases import (
_Backend, FigureCanvasBase, FigureManagerBase, GraphicsContextBase,
MouseButton, NavigationToolbar2, RendererBase, StatusbarBase, TimerBase,
ToolContainerBase, cursors)
_Backend, _check_savefig_extra_args, FigureCanvasBase, FigureManagerBase,
GraphicsContextBase, MouseButton, NavigationToolbar2, RendererBase,
StatusbarBase, TimerBase, ToolContainerBase, cursors)

from matplotlib import cbook, backend_tools
from matplotlib._pylab_helpers import Gcf
Expand Down Expand Up @@ -861,7 +861,8 @@ def print_tiff(self, filename, *args, **kwargs):
def print_xpm(self, filename, *args, **kwargs):
return self._print_image(filename, wx.BITMAP_TYPE_XPM, *args, **kwargs)

def _print_image(self, filename, filetype, *args, **kwargs):
@_check_savefig_extra_args
def _print_image(self, filename, filetype, *, quality=None):
origBitmap = self.bitmap

self.bitmap = wx.Bitmap(math.ceil(self.figure.bbox.width),
Expand All @@ -878,11 +879,11 @@ def _print_image(self, filename, filetype, *args, **kwargs):
# are saving a JPEG, convert the wx.Bitmap to a wx.Image,
# and set the quality.
if filetype == wx.BITMAP_TYPE_JPEG:
jpeg_quality = kwargs.get(
'quality',
dict.__getitem__(mpl.rcParams, 'savefig.jpeg_quality'))
if quality is None:
quality = dict.__getitem__(mpl.rcParams,
'savefig.jpeg_quality')
image = self.bitmap.ConvertToImage()
image.SetOption(wx.IMAGE_OPTION_QUALITY, str(jpeg_quality))
image.SetOption(wx.IMAGE_OPTION_QUALITY, str(quality))

# Now that we have rendered into the bitmap, save it to the appropriate
# file type and clean up.
Expand Down
9 changes: 9 additions & 0 deletions lib/matplotlib/tests/test_figure.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from datetime import datetime
import io
from pathlib import Path
import platform
from types import SimpleNamespace
Expand Down Expand Up @@ -424,6 +425,14 @@ def test_savefig():
fig.savefig("fname1.png", "fname2.png")


def test_savefig_warns():
fig = plt.figure()
msg = r'savefig\(\) got unexpected keyword argument "non_existent_kwarg"'
for format in ['png', 'pdf', 'svg', 'tif', 'jpg']:
with pytest.warns(cbook.MatplotlibDeprecationWarning, match=msg):
fig.savefig(io.BytesIO(), format=format, non_existent_kwarg=True)


def test_savefig_backend():
fig = plt.figure()
# Intentionally use an invalid module name.
Expand Down

Back | FazBrowse Home | New Git URL