Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5f24501

Browse files
authored
Merge pull request #18008 from meeseeksmachine/auto-backport-of-pr-17969-on-v3.3.x
Backport PR #17969 on branch v3.3.x (Honor `'Date': None` in metadata)
2 parents 5c8392b + 5010de1 commit 5f24501

File tree

2 files changed

+80
-5
lines changed

2 files changed

+80
-5
lines changed

lib/matplotlib/backends/backend_svg.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,8 @@ def _write_metadata(self, metadata):
360360
'Expected str, date, datetime, or iterable '
361361
'of the same, not {!r}.'.format(type(date)))
362362
metadata['Date'] = '/'.join(dates)
363-
else:
363+
elif 'Date' not in metadata:
364+
# Do not add `Date` if the user explicitly set `Date` to `None`
364365
# Get source date from SOURCE_DATE_EPOCH, if set.
365366
# See https://reproducible-builds.org/specs/source-date-epoch/
366367
date = os.getenv("SOURCE_DATE_EPOCH")
@@ -370,23 +371,30 @@ def _write_metadata(self, metadata):
370371
else:
371372
metadata['Date'] = datetime.datetime.today().isoformat()
372373

373-
mid = writer.start('metadata')
374-
writer.start('rdf:RDF', attrib={
374+
mid = None
375+
def ensure_metadata(mid):
376+
if mid is not None:
377+
return mid
378+
mid = writer.start('metadata')
379+
writer.start('rdf:RDF', attrib={
375380
'xmlns:dc': "http://purl.org/dc/elements/1.1/",
376381
'xmlns:cc': "http://creativecommons.org/ns#",
377382
'xmlns:rdf': "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
378383
})
379-
writer.start('cc:Work')
384+
writer.start('cc:Work')
385+
return mid
380386

381387
uri = metadata.pop('Type', None)
382388
if uri is not None:
389+
mid = ensure_metadata(mid)
383390
writer.element('dc:type', attrib={'rdf:resource': uri})
384391

385392
# Single value only.
386393
for key in ['title', 'coverage', 'date', 'description', 'format',
387394
'identifier', 'language', 'relation', 'source']:
388395
info = metadata.pop(key.title(), None)
389396
if info is not None:
397+
mid = ensure_metadata(mid)
390398
writer.element(f'dc:{key}', text=info)
391399

392400
# Multiple Agent values.
@@ -398,6 +406,7 @@ def _write_metadata(self, metadata):
398406
if isinstance(agents, str):
399407
agents = [agents]
400408

409+
mid = ensure_metadata(mid)
401410
writer.start(f'dc:{key}')
402411
for agent in agents:
403412
writer.start('cc:Agent')
@@ -411,14 +420,16 @@ def _write_metadata(self, metadata):
411420
if isinstance(keywords, str):
412421
keywords = [keywords]
413422

423+
mid = ensure_metadata(mid)
414424
writer.start('dc:subject')
415425
writer.start('rdf:Bag')
416426
for keyword in keywords:
417427
writer.element('rdf:li', text=keyword)
418428
writer.end('rdf:Bag')
419429
writer.end('dc:subject')
420430

421-
writer.close(mid)
431+
if mid is not None:
432+
writer.close(mid)
422433

423434
if metadata:
424435
raise ValueError('Unknown metadata key(s) passed to SVG writer: ' +

lib/matplotlib/tests/test_backend_svg.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,70 @@ def test_svg_default_metadata(monkeypatch):
276276
# Type
277277
assert 'StillImage' in buf
278278

279+
# Now make sure all the default metadata can be cleared.
280+
with BytesIO() as fd:
281+
fig.savefig(fd, format='svg', metadata={'Date': None, 'Creator': None,
282+
'Format': None, 'Type': None})
283+
buf = fd.getvalue().decode()
284+
285+
# Creator
286+
assert mpl.__version__ not in buf
287+
# Date
288+
assert '1970-08-16' not in buf
289+
# Format
290+
assert 'image/svg+xml' not in buf
291+
# Type
292+
assert 'StillImage' not in buf
293+
294+
295+
def test_svg_clear_default_metadata(monkeypatch):
296+
# Makes sure that setting a default metadata to `None`
297+
# removes the corresponding tag from the metadata.
298+
monkeypatch.setenv('SOURCE_DATE_EPOCH', '19680801')
299+
300+
metadata_contains = {'creator': mpl.__version__, 'date': '1970-08-16',
301+
'format': 'image/svg+xml', 'type': 'StillImage'}
302+
303+
SVGNS = '{http://www.w3.org/2000/svg}'
304+
RDFNS = '{http://www.w3.org/1999/02/22-rdf-syntax-ns#}'
305+
CCNS = '{http://creativecommons.org/ns#}'
306+
DCNS = '{http://purl.org/dc/elements/1.1/}'
307+
308+
fig, ax = plt.subplots()
309+
for name in metadata_contains:
310+
with BytesIO() as fd:
311+
fig.savefig(fd, format='svg', metadata={name.title(): None})
312+
buf = fd.getvalue().decode()
313+
314+
root = xml.etree.ElementTree.fromstring(buf)
315+
work, = root.findall(f'./{SVGNS}metadata/{RDFNS}RDF/{CCNS}Work')
316+
for key in metadata_contains:
317+
data = work.findall(f'./{DCNS}{key}')
318+
if key == name:
319+
# The one we cleared is not there
320+
assert not data
321+
continue
322+
# Everything else should be there
323+
data, = data
324+
xmlstr = xml.etree.ElementTree.tostring(data, encoding="unicode")
325+
assert metadata_contains[key] in xmlstr
326+
327+
328+
def test_svg_clear_all_metadata():
329+
# Makes sure that setting all default metadata to `None`
330+
# removes the metadata tag from the output.
331+
332+
fig, ax = plt.subplots()
333+
with BytesIO() as fd:
334+
fig.savefig(fd, format='svg', metadata={'Date': None, 'Creator': None,
335+
'Format': None, 'Type': None})
336+
buf = fd.getvalue().decode()
337+
338+
SVGNS = '{http://www.w3.org/2000/svg}'
339+
340+
root = xml.etree.ElementTree.fromstring(buf)
341+
assert not root.findall(f'./{SVGNS}metadata')
342+
279343

280344
def test_svg_metadata():
281345
single_value = ['Coverage', 'Identifier', 'Language', 'Relation', 'Source',

0 commit comments

Comments
 (0)