Skip to content

Commit cf4a117

Browse files
committed
Add tests for PDF metadata saving using pikepdf.
1 parent aa0fa1a commit cf4a117

File tree

3 files changed

+131
-2
lines changed

3 files changed

+131
-2
lines changed

lib/matplotlib/tests/test_backend_pdf.py

+74
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import datetime
12
import io
23
import os
34
from pathlib import Path
@@ -7,6 +8,7 @@
78
import numpy as np
89
import pytest
910

11+
import matplotlib as mpl
1012
from matplotlib import dviread, pyplot as plt, checkdep_usetex, rcParams
1113
from matplotlib.backends.backend_pdf import PdfPages
1214
from matplotlib.testing.compare import compare_images
@@ -125,6 +127,78 @@ def test_composite_image():
125127
assert len(pdf._file._images) == 2
126128

127129

130+
def test_savefig_metadata(monkeypatch):
131+
pikepdf = pytest.importorskip('pikepdf')
132+
monkeypatch.setenv('SOURCE_DATE_EPOCH', '0')
133+
134+
fig, ax = plt.subplots()
135+
ax.plot(range(5))
136+
137+
md = {
138+
'Author': 'me',
139+
'Title': 'Multipage PDF',
140+
'Subject': 'Test page',
141+
'Keywords': 'test,pdf,multipage',
142+
'ModDate': datetime.datetime(
143+
1968, 8, 1, tzinfo=datetime.timezone(datetime.timedelta(0))),
144+
'Trapped': 'True'
145+
}
146+
buf = io.BytesIO()
147+
fig.savefig(buf, metadata=md, format='pdf')
148+
149+
with pikepdf.Pdf.open(buf) as pdf:
150+
info = {k: str(v) for k, v in pdf.docinfo.items()}
151+
152+
assert info == {
153+
'/Author': 'me',
154+
'/CreationDate': 'D:19700101000000Z',
155+
'/Creator': f'Matplotlib v{mpl.__version__}, https://matplotlib.org',
156+
'/Keywords': 'test,pdf,multipage',
157+
'/ModDate': 'D:19680801000000Z',
158+
'/Producer': f'Matplotlib pdf backend v{mpl.__version__}',
159+
'/Subject': 'Test page',
160+
'/Title': 'Multipage PDF',
161+
'/Trapped': '/True',
162+
}
163+
164+
165+
def test_multipage_metadata(monkeypatch):
166+
pikepdf = pytest.importorskip('pikepdf')
167+
monkeypatch.setenv('SOURCE_DATE_EPOCH', '0')
168+
169+
fig, ax = plt.subplots()
170+
ax.plot(range(5))
171+
172+
md = {
173+
'Author': 'me',
174+
'Title': 'Multipage PDF',
175+
'Subject': 'Test page',
176+
'Keywords': 'test,pdf,multipage',
177+
'ModDate': datetime.datetime(
178+
1968, 8, 1, tzinfo=datetime.timezone(datetime.timedelta(0))),
179+
'Trapped': 'True'
180+
}
181+
buf = io.BytesIO()
182+
with PdfPages(buf, metadata=md) as pdf:
183+
pdf.savefig(fig)
184+
pdf.savefig(fig)
185+
186+
with pikepdf.Pdf.open(buf) as pdf:
187+
info = {k: str(v) for k, v in pdf.docinfo.items()}
188+
189+
assert info == {
190+
'/Author': 'me',
191+
'/CreationDate': 'D:19700101000000Z',
192+
'/Creator': f'Matplotlib v{mpl.__version__}, https://matplotlib.org',
193+
'/Keywords': 'test,pdf,multipage',
194+
'/ModDate': 'D:19680801000000Z',
195+
'/Producer': f'Matplotlib pdf backend v{mpl.__version__}',
196+
'/Subject': 'Test page',
197+
'/Title': 'Multipage PDF',
198+
'/Trapped': '/True',
199+
}
200+
201+
128202
def test_pdfpages_fspath():
129203
with PdfPages(Path(os.devnull)) as pdf:
130204
pdf.savefig(plt.figure())

lib/matplotlib/tests/test_backend_pgf.py

+56-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from datetime import datetime
1+
import datetime
22
from io import BytesIO
33
import os
44
from pathlib import Path
@@ -243,7 +243,8 @@ def test_pdf_pages(system):
243243
'Title': 'Multipage PDF with pgf',
244244
'Subject': 'Test page',
245245
'Keywords': 'test,pdf,multipage',
246-
'ModDate': datetime(1968, 8, 1),
246+
'ModDate': datetime.datetime(
247+
1968, 8, 1, tzinfo=datetime.timezone(datetime.timedelta(0))),
247248
'Trapped': 'Unknown'
248249
}
249250

@@ -255,6 +256,59 @@ def test_pdf_pages(system):
255256
assert pdf.get_pagecount() == 3
256257

257258

259+
@pytest.mark.style('default')
260+
@pytest.mark.backend('pgf')
261+
@pytest.mark.parametrize('system', [
262+
pytest.param('lualatex', marks=[needs_lualatex]),
263+
pytest.param('pdflatex', marks=[needs_pdflatex]),
264+
pytest.param('xelatex', marks=[needs_xelatex]),
265+
])
266+
def test_pdf_pages_metadata_check(monkeypatch, system):
267+
# Basically the same as test_pdf_pages, but we keep it separate to leave
268+
# pikepdf as an optional dependency.
269+
pikepdf = pytest.importorskip('pikepdf')
270+
monkeypatch.setenv('SOURCE_DATE_EPOCH', '0')
271+
272+
mpl.rcParams.update({'pgf.texsystem': system})
273+
274+
fig, ax = plt.subplots()
275+
ax.plot(range(5))
276+
277+
md = {
278+
'Author': 'me',
279+
'Title': 'Multipage PDF with pgf',
280+
'Subject': 'Test page',
281+
'Keywords': 'test,pdf,multipage',
282+
'ModDate': datetime.datetime(
283+
1968, 8, 1, tzinfo=datetime.timezone(datetime.timedelta(0))),
284+
'Trapped': 'True'
285+
}
286+
path = os.path.join(result_dir, f'pdfpages_meta_check_{system}.pdf')
287+
with PdfPages(path, metadata=md) as pdf:
288+
pdf.savefig(fig)
289+
290+
with pikepdf.Pdf.open(path) as pdf:
291+
info = {k: str(v) for k, v in pdf.docinfo.items()}
292+
293+
# Not set by us, so don't bother checking.
294+
if '/PTEX.FullBanner' in info:
295+
del info['/PTEX.FullBanner']
296+
if '/PTEX.Fullbanner' in info:
297+
del info['/PTEX.Fullbanner']
298+
299+
assert info == {
300+
'/Author': 'me',
301+
'/CreationDate': 'D:19700101000000Z',
302+
'/Creator': f'Matplotlib v{mpl.__version__}, https://matplotlib.org',
303+
'/Keywords': 'test,pdf,multipage',
304+
'/ModDate': 'D:19680801000000Z',
305+
'/Producer': f'Matplotlib pgf backend v{mpl.__version__}',
306+
'/Subject': 'Test page',
307+
'/Title': 'Multipage PDF with pgf',
308+
'/Trapped': '/True',
309+
}
310+
311+
258312
@needs_xelatex
259313
def test_tex_restart_after_error():
260314
fig = plt.figure()

requirements/testing/travis_extra.txt

+1
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ ipykernel
44
nbconvert[execute]
55
nbformat!=5.0.0,!=5.0.1
66
pandas!=0.25.0
7+
pikepdf
78
pytz

0 commit comments

Comments
 (0)