import json import re from collections.abc import MutableMapping import inkex from lxml import etree from .utils.settings import DEFAULT_METADATA, global_settings def strip_namespace(tag): """Remove xml namespace from a tag name. >>> {http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd}namedview <<< namedview """ match = re.match(r'^\{[^}]+\}(.+)$', tag) if match: return match.group(1) else: return tag class InkStitchMetadata(MutableMapping): """Helper class to get and set inkstitch-specific metadata attributes. Operates on a document and acts like a dict. Setting an item adds or updates a metadata element in the document. Getting an item retrieves a metadata element's text contents or None if an element by that name doesn't exist. """ def __init__(self, document): super().__init__() self.document = document self.metadata = document.metadata for setting in DEFAULT_METADATA: if self[setting] is None: self[setting] = global_settings[f'default_{setting}'] # Because this class inherints from MutableMapping, all we have to do is # implement these five methods and we get a full dict-like interface. def __setitem__(self, name, value): item = self._find_item(name) item.text = json.dumps(value) def _find_item(self, name, create=True): tag = inkex.addNS(name, "inkstitch") item = self.metadata.find(tag) if item is None and create: item = etree.SubElement(self.metadata, tag) return item def __getitem__(self, name): item = self._find_item(name) try: return json.loads(item.text) except (ValueError, TypeError): return None def __delitem__(self, name): item = self._find_item(name, create=False) if item is not None: self.metadata.remove(item) def __iter__(self): for child in self.metadata: if child.prefix == "inkstitch": yield strip_namespace(child.tag) def __len__(self): i = 0 for i, item in enumerate(self): pass return i + 1 def __json__(self): return dict(self)