diff --git a/lib/matplotlib/backends/backend_pdf.py b/lib/matplotlib/backends/backend_pdf.py index c73f0e867101..31aab0e4074c 100644 --- a/lib/matplotlib/backends/backend_pdf.py +++ b/lib/matplotlib/backends/backend_pdf.py @@ -552,9 +552,10 @@ def newTextnote(self, text, positionRect=[-100, -100, 0, 0]): self.writeObject(annotObject, theNote) self.pageAnnotations.append(annotObject) - def close(self): + def finalize(self): + "Write out the various deferred objects and the pdf end matter." + self.endStream() - # Write out the various deferred objects self.writeFonts() self.writeObject(self.alphaStateObject, dict([(val[0], val[1]) @@ -582,12 +583,16 @@ def close(self): # Finalize the file self.writeXref() self.writeTrailer() + + def close(self): + "Flush all buffers and free all resources." + + self.endStream() if self.passed_in_file_object: self.fh.flush() - elif self.original_file_like is not None: - self.original_file_like.write(self.fh.getvalue()) - self.fh.close() else: + if self.original_file_like is not None: + self.original_file_like.write(self.fh.getvalue()) self.fh.close() def write(self, data): @@ -1871,6 +1876,12 @@ def draw_tex(self, gc, x, y, s, prop, angle, ismath='TeX!', mtext=None): pdfname = self.file.fontName(dvifont.texname) if dvifont.texname not in self.file.dviFontInfo: psfont = self.tex_font_mapping(dvifont.texname) + if psfont.filename is None: + self.file.broken = True + raise ValueError( + ("No usable font file found for %s (%s). " + "The font may lack a Type-1 version.") + % (psfont.psname, dvifont.texname)) self.file.dviFontInfo[dvifont.texname] = Bunch( fontfile=psfont.filename, basefont=psfont.psname, @@ -2438,6 +2449,7 @@ def close(self): Finalize this object, making the underlying file a complete PDF file. """ + self._file.finalize() self._file.close() if (self.get_pagecount() == 0 and not self.keep_empty and not self._file.passed_in_file_object): @@ -2534,6 +2546,7 @@ def print_pdf(self, filename, **kwargs): bbox_inches_restore=_bbox_inches_restore) self.figure.draw(renderer) renderer.finalize() + file.finalize() finally: if isinstance(filename, PdfPages): # finish off this page file.endStream() diff --git a/lib/matplotlib/tests/test_backend_pdf.py b/lib/matplotlib/tests/test_backend_pdf.py index a52a95464491..e8f2b4e5743c 100644 --- a/lib/matplotlib/tests/test_backend_pdf.py +++ b/lib/matplotlib/tests/test_backend_pdf.py @@ -7,13 +7,21 @@ import io import os +import tempfile + +try: + from unittest.mock import patch +except ImportError: + from mock import patch +from nose.tools import raises import numpy as np -from matplotlib import cm, rcParams +from matplotlib import checkdep_tex, cm, rcParams from matplotlib.backends.backend_pdf import PdfPages from matplotlib import pyplot as plt from matplotlib.testing.decorators import (image_comparison, knownfailureif, cleanup) +from matplotlib import dviread if 'TRAVIS' not in os.environ: @image_comparison(baseline_images=['pdf_use14corefonts'], @@ -29,6 +37,10 @@ def test_use14corefonts(): and containing some French characters and the euro symbol: "Merci pépé pour les 10 €"''' +needs_tex = knownfailureif( + not checkdep_tex(), + "This test needs a TeX installation") + @cleanup def test_type42(): @@ -132,3 +144,19 @@ def test_grayscale_alpha(): ax.imshow(dd, interpolation='none', cmap='gray_r') ax.set_xticks([]) ax.set_yticks([]) + + +@cleanup +@needs_tex +@raises(ValueError) +@patch('matplotlib.dviread.PsfontsMap.__getitem__') +def test_missing_psfont(mock): + """An error is raised if a TeX font lacks a Type-1 equivalent""" + psfont = dviread.PsFont(texname='texfont', psname='Some Font', + effects=None, encoding=None, filename=None) + mock.configure_mock(return_value=psfont) + rcParams['text.usetex'] = True + fig, ax = plt.subplots() + ax.text(0.5, 0.5, 'hello') + with tempfile.TemporaryFile() as tmpfile: + fig.savefig(tmpfile, format='pdf') diff --git a/lib/matplotlib/tests/test_backend_svg.py b/lib/matplotlib/tests/test_backend_svg.py index fcbdefb9102f..6bae4f0d626c 100644 --- a/lib/matplotlib/tests/test_backend_svg.py +++ b/lib/matplotlib/tests/test_backend_svg.py @@ -5,12 +5,22 @@ import numpy as np from io import BytesIO +import os +import tempfile import xml.parsers.expat +try: + from unittest.mock import patch +except ImportError: + from mock import patch +from nose.tools import raises + import matplotlib.pyplot as plt from matplotlib.testing.decorators import cleanup from matplotlib.testing.decorators import image_comparison, knownfailureif import matplotlib +from matplotlib import dviread + needs_tex = knownfailureif( not matplotlib.checkdep_tex(), @@ -183,6 +193,23 @@ def test_determinism_tex(): _test_determinism('determinism_tex.svg', usetex=True) +@cleanup +@needs_tex +@raises(ValueError) +@patch('matplotlib.dviread.PsfontsMap.__getitem__') +def test_missing_psfont(mock): + """An error is raised if a TeX font lacks a Type-1 equivalent""" + from matplotlib import rc + psfont = dviread.PsFont(texname='texfont', psname='Some Font', + effects=None, encoding=None, filename=None) + mock.configure_mock(return_value=psfont) + rc('text', usetex=True) + fig, ax = plt.subplots() + ax.text(0.5, 0.5, 'hello') + with tempfile.NamedTemporaryFile(suffix='.svg') as tmpfile: + fig.savefig(tmpfile.name) + + if __name__ == '__main__': import nose nose.runmodule(argv=['-s', '--with-doctest'], exit=False) diff --git a/lib/matplotlib/textpath.py b/lib/matplotlib/textpath.py index bd0db3bc0bbe..17f59c09a7fb 100644 --- a/lib/matplotlib/textpath.py +++ b/lib/matplotlib/textpath.py @@ -335,6 +335,12 @@ def get_glyphs_tex(self, prop, s, glyph_map=None, font_bunch = self.tex_font_map[dvifont.texname] if font_and_encoding is None: + if font_bunch.filename is None: + raise ValueError( + ("No usable font file found for %s (%s). " + "The font may lack a Type-1 version.") + % (font_bunch.psname, dvifont.texname)) + font = get_font(font_bunch.filename) for charmap_name, charmap_code in [("ADOBE_CUSTOM",