10BC0 Backport PR #17969 on branch v3.3.x (Honor `'Date': None` in metadata) by meeseeksmachine · Pull Request #18008 · matplotlib/matplotlib · GitHub
[go: up one dir, main page]

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 16 additions & 5 deletions lib/matplotlib/backends/backend_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,8 @@ def _write_metadata(self, metadata):
'Expected str, date, datetime, or iterable '
'of the same, not {!r}.'.format(type(date)))
metadata['Date'] = '/'.join(dates)
else:
elif 'Date' not in metadata:
# Do not add `Date` if the user explicitly set `Date` to `None`
# Get source date from SOURCE_DATE_EPOCH, if set.
# See https://reproducible-builds.org/specs/source-date-epoch/
date = os.getenv("SOURCE_DATE_EPOCH")
Expand All @@ -370,23 +371,30 @@ def _write_metadata(self, metadata):
else:
metadata['Date'] = datetime.datetime.today().isoformat()

mid = writer.start('metadata')
writer.start('rdf:RDF', attrib={
mid = None
def ensure_metadata(mid):
if mid is not None:
return mid
mid = writer.start('metadata')
writer.start('rdf:RDF', attrib={
'xmlns:dc': "http://purl.org/dc/elements/1.1/",
'xmlns:cc': "http://creativecommons.org/ns#",
'xmlns:rdf': "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
})
writer.start('cc:Work')
writer.start('cc:Work')
F440 return mid

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

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

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

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

mid = ensure_metadata(mid)
writer.start('dc:subject')
writer.start('rdf:Bag')
for keyword in keywords:
writer.element('rdf:li', text=keyword)
writer.end('rdf:Bag')
writer.end('dc:subject')

writer.close(mid)
if mid is not None:
writer.close(mid)

if metadata:
raise ValueError('Unknown metadata key(s) passed to SVG writer: ' +
Expand Down
64 changes: 64 additions & 0 deletions lib/matplotlib/tests/test_backend_svg.py
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,70 @@ def test_svg_default_metadata(monkeypatch):
# Type
assert 'StillImage' in buf

# Now make sure all the default metadata can be cleared.
with BytesIO() as fd:
fig.savefig(fd, format='svg', metadata={'Date': None, 'Creator': None,
'Format': None, 'Type': None})
buf = fd.getvalue().decode()

# Creator
assert mpl.__version__ not in buf
# Date
assert '1970-08-16' not in buf
# Format
assert 'image/svg+xml' not in buf
# Type
assert 'StillImage' not in buf


def test_svg_clear_default_metadata(monkeypatch):
# Makes sure that setting a default metadata to `None`
# removes the corresponding tag from the metadata.
monkeypatch.setenv('SOURCE_DATE_EPOCH', '19680801')

metadata_contains = {'creator': mpl.__version__, 'date': '1970-08-16',
'format': 'image/svg+xml', 'type': 'StillImage'}

SVGNS = '{http://www.w3.org/2000/svg}'
RDFNS = '{http://www.w3.org/1999/02/22-rdf-syntax-ns#}'
CCNS = '{http://creativecommons.org/ns#}'
DCNS = '{http://purl.org/dc/elements/1.1/}'

fig, ax = plt.subplots()
for name in metadata_contains:
with BytesIO() as fd:
fig.savefig(fd, format='svg', metadata={name.title(): None})
buf = fd.getvalue().decode()

root = xml.etree.ElementTree.fromstring(buf)
work, = root.findall(f'./{SVGNS}metadata/{RDFNS}RDF/{CCNS}Work')
for key in metadata_contains:
data = work.findall(f'./{DCNS}{key}')
if key == name:
# The one we cleared is not there
assert not data
continue
# Everything else should be there
data, = data
xmlstr = xml.etree.ElementTree.tostring(data, encoding="unicode")
assert metadata_contains[key] in xmlstr


def test_svg_clear_all_metadata():
# Makes sure that setting all default metadata to `None`
# removes the metadata tag from the output.

fig, ax = plt.subplots()
with BytesIO() as fd:
fig.savefig(fd, format='svg', metadata={'Date': None, 'Creator': None,
'Format': None, 'Type': None})
buf = fd.getvalue().decode()

SVGNS = '{http://www.w3.org/2000/svg}'

root = xml.etree.ElementTree.fromstring(buf)
assert not root.findall(f'./{SVGNS}metadata')


def test_svg_metadata():
single_value = ['Coverage', 'Identifier', 'Language', 'Relation', 'Source',
Expand Down
0