From 5f60446f7c684b967cd423f553617f361348b1a2 Mon Sep 17 00:00:00 2001 From: Tobias Megies Date: Mon, 23 Sep 2013 20:34:29 +0200 Subject: [PATCH 1/3] add option to delete empty PdfPages when closed - PdfPages objects can be told at initialization to delete the pdf file when closed, if no page was actually plotted - keep the default to not delete empty pdf files so current behavior is not changed - also some basic tests for it --- lib/matplotlib/backends/backend_pdf.py | 9 ++++-- lib/matplotlib/tests/test_backend_pdf.py | 35 ++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 861b2a082b5d..452f3539444d 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -2263,15 +2263,18 @@ class PdfPages(object): avoid confusion when using savefig and forgetting the format argument.) """ - __slots__ = ('_file',) + __slots__ = ('_file', 'keep_empty') - def __init__(self, filename): + def __init__(self, filename, keep_empty=True): """ Create a new PdfPages object that will be written to the file named *filename*. The file is opened at once and any older file with the same name is overwritten. + If keep_empty is set to False then empty pdf files will be deleted when + closed. """ self._file = PdfFile(filename) + self.keep_empty = keep_empty def __enter__(self): return self @@ -2285,6 +2288,8 @@ def close(self): PDF file. """ self._file.close() + if self.get_pagecount() == 0 and self.keep_empty is False: + os.remove(self._file.fh.name) self._file = None def infodict(self): diff --git a/lib/matplotlib/tests/test_backend_pdf.py b/lib/matplotlib/tests/test_backend_pdf.py index 9e666e4a2062..c3e41926fcd1 100644 --- a/lib/matplotlib/tests/test_backend_pdf.py +++ b/lib/matplotlib/tests/test_backend_pdf.py @@ -50,3 +50,38 @@ def test_multipage_pagecount(): assert pdf.get_pagecount() == 1 pdf.savefig() assert pdf.get_pagecount() == 2 + + +@cleanup +def test_multipage_keep_empty(): + from matplotlib.backends.backend_pdf import PdfPages + from tempfile import NamedTemporaryFile + ### test empty pdf files + # test that an empty pdf is left behind with keep_empty=True (default) + with NamedTemporaryFile(delete=False) as tmp: + with PdfPages(tmp) as pdf: + filename = pdf._file.fh.name + assert os.path.exists(filename) + os.remove(filename) + # test if an empty pdf is deleting itself afterwards with keep_empty=False + with NamedTemporaryFile(delete=False) as tmp: + with PdfPages(tmp, keep_empty=False) as pdf: + filename = pdf._file.fh.name + assert not os.path.exists(filename) + ### test pdf files with content + fig = plt.figure() + ax = fig.add_subplot(111) + ax.plot([1, 2, 3]) + # test that a non-empty pdf is left behind regardless of keep_empty-setting + with NamedTemporaryFile(delete=False) as tmp: + with PdfPages(tmp) as pdf: + filename = pdf._file.fh.name + pdf.savefig() + assert os.path.exists(filename) + os.remove(filename) + with NamedTemporaryFile(delete=False) as tmp: + with PdfPages(tmp, keep_empty=False) as pdf: + filename = pdf._file.fh.name + pdf.savefig() + assert os.path.exists(filename) + os.remove(filename) From dffaf4e7fd67f23d2643f671d9daccf2fc0dd459 Mon Sep 17 00:00:00 2001 From: Tobias Megies Date: Tue, 24 Sep 2013 11:41:31 +0200 Subject: [PATCH 2/3] clearer comments in test --- lib/matplotlib/tests/test_backend_pdf.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/tests/test_backend_pdf.py b/lib/matplotlib/tests/test_backend_pdf.py index c3e41926fcd1..4dc0b4701159 100644 --- a/lib/matplotlib/tests/test_backend_pdf.py +++ b/lib/matplotlib/tests/test_backend_pdf.py @@ -68,17 +68,18 @@ def test_multipage_keep_empty(): with PdfPages(tmp, keep_empty=False) as pdf: filename = pdf._file.fh.name assert not os.path.exists(filename) - ### test pdf files with content + ### test pdf files with content, they should never be deleted fig = plt.figure() ax = fig.add_subplot(111) ax.plot([1, 2, 3]) - # test that a non-empty pdf is left behind regardless of keep_empty-setting + # test that a non-empty pdf is left behind with keep_empty=True (default) with NamedTemporaryFile(delete=False) as tmp: with PdfPages(tmp) as pdf: filename = pdf._file.fh.name pdf.savefig() assert os.path.exists(filename) os.remove(filename) + # test that a non-empty pdf is left behind with keep_empty=False with NamedTemporaryFile(delete=False) as tmp: with PdfPages(tmp, keep_empty=False) as pdf: filename = pdf._file.fh.name From cb805ad89fcb685bdb6e110b4c6bb22da123435d Mon Sep 17 00:00:00 2001 From: Tobias Megies Date: Tue, 24 Sep 2013 12:19:33 +0200 Subject: [PATCH 3/3] refactor docstrings of PdfPages --- lib/matplotlib/backends/backend_pdf.py | 65 +++++++++++++++++--------- 1 file changed, 43 insertions(+), 22 deletions(-) diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index 452f3539444d..50d47f8497a0 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -2249,29 +2249,41 @@ class PdfPages(object): """ A multi-page PDF file. - Use like this:: - - # Initialize: - with PdfPages('foo.pdf') as pdf: - - # As many times as you like, create a figure fig and save it: - # When no figure is specified the current figure is saved - pdf.savefig(fig) - pdf.savefig() - - (In reality PdfPages is a thin wrapper around PdfFile, in order to - avoid confusion when using savefig and forgetting the format - argument.) + Examples + -------- + + >>> import matplotlib.pyplot as plt + >>> # Initialize: + >>> with PdfPages('foo.pdf') as pdf: + ... # As many times as you like, create a figure fig and save it: + ... fig = plt.figure() + ... pdf.savefig(fig) + ... # When no figure is specified the current figure is saved + ... pdf.savefig() + + Notes + ----- + + In reality :class:`PdfPages` is a thin wrapper around :class:`PdfFile`, in + order to avoid confusion when using :func:`~matplotlib.pyplot.savefig` and + forgetting the format argument. """ __slots__ = ('_file', 'keep_empty') def __init__(self, filename, keep_empty=True): """ - Create a new PdfPages object that will be written to the file - named *filename*. The file is opened at once and any older - file with the same name is overwritten. - If keep_empty is set to False then empty pdf files will be deleted when - closed. + Create a new PdfPages object. + + Parameters + ---------- + + filename: str + Plots using :meth:`PdfPages.savefig` will be written to a file at + this location. The file is opened at once and any older file with + the same name is overwritten. + keep_empty: bool, optional + If set to False, then empty pdf files will be deleted automatically + when closed. """ self._file = PdfFile(filename) self.keep_empty = keep_empty @@ -2302,10 +2314,19 @@ def infodict(self): def savefig(self, figure=None, **kwargs): """ - Save the Figure instance *figure* to this file as a new page. - If *figure* is a number, the figure instance is looked up by - number, and if *figure* is None, the active figure is saved. - Any other keyword arguments are passed to Figure.savefig. + Saves a :class:`~matplotlib.figure.Figure` to this file as a new page. + + Any other keyword arguments are passed to + :meth:`~matplotlib.figure.Figure.savefig`. + + Parameters + ---------- + + figure: :class:`~matplotlib.figure.Figure` or int, optional + Specifies what figure is saved to file. If not specified, the + active figure is saved. If a :class:`~matplotlib.figure.Figure` + instance is provided, this figure is saved. If an int is specified, + the figure instance to save is looked up by number. """ if isinstance(figure, Figure): figure.savefig(self, format='pdf', **kwargs)