def __init__(self, filename=None, transform=None): if filename is None: self.root = etree.ElementTree() else: tree = etree.parse(filename) self.root = tree.getroot() self.transform = transform
def dump( value, fp, sort_keys=True, skipkeys=False, use_builtin_types=None, pretty_print=True, ): if not hasattr(fp, "write"): raise AttributeError("'%s' object has no attribute 'write'" % type(fp).__name__) root = etree.Element("plist", version="1.0") el = totree( value, sort_keys=sort_keys, skipkeys=skipkeys, use_builtin_types=use_builtin_types, pretty_print=pretty_print, ) root.append(el) tree = etree.ElementTree(root) # we write the doctype ourselves instead of using the 'doctype' argument # of 'write' method, becuse lxml will force adding a '\n' even when # pretty_print is False. if pretty_print: header = b"\n".join((XML_DECLARATION, PLIST_DOCTYPE, b"")) else: header = XML_DECLARATION + PLIST_DOCTYPE fp.write(header) tree.write(fp, encoding="utf-8", pretty_print=pretty_print, xml_declaration=False)
def dump( value: PlistEncodable, fp: IO[bytes], sort_keys: bool = True, skipkeys: bool = False, use_builtin_types: Optional[bool] = None, pretty_print: bool = True, ) -> None: """Write a Python object to a plist file. Args: value: An object to write. fp: A file opened for writing. sort_keys (bool): Whether keys of dictionaries should be sorted. skipkeys (bool): Whether to silently skip non-string dictionary keys. use_builtin_types (bool): If true, byte strings will be encoded in Base-64 and wrapped in a ``data`` tag; if false, they will be either stored as ASCII strings or an exception raised if they cannot be represented. Defaults pretty_print (bool): Whether to indent the output. indent_level (int): Level of indentation when serializing. Raises: ``TypeError`` if non-string dictionary keys are serialized and ``skipkeys`` is false. ``ValueError`` if non-representable binary data is present and `use_builtin_types` is false. """ if not hasattr(fp, "write"): raise AttributeError("'%s' object has no attribute 'write'" % type(fp).__name__) root = etree.Element("plist", version="1.0") el = totree( value, sort_keys=sort_keys, skipkeys=skipkeys, use_builtin_types=use_builtin_types, pretty_print=pretty_print, ) root.append(el) tree = etree.ElementTree(root) # we write the doctype ourselves instead of using the 'doctype' argument # of 'write' method, becuse lxml will force adding a '\n' even when # pretty_print is False. if pretty_print: header = b"\n".join((XML_DECLARATION, PLIST_DOCTYPE, b"")) else: header = XML_DECLARATION + PLIST_DOCTYPE fp.write(header) tree.write( # type: ignore fp, encoding="utf-8", pretty_print=pretty_print, xml_declaration=False, )
def getGlyphXML(glyphDir, glyphFileName): glyphPath = os.path.join(glyphDir, glyphFileName) # default etRoot = ET.ElementTree() glifXML = etRoot.parse(glyphPath) outlineXML = glifXML.find("outline") try: widthXML = glifXML.find("advance") if widthXML is not None: width = round(ast.literal_eval(widthXML.get("width", '0')), 9) else: width = 0 except UFOParseError as e: print(f"Error. skipping glyph '{glyphFileName}' because " f"of parse error: {str(e)}") return None, None, None return width, glifXML, outlineXML
def buildGlyphHashValue(self, width, outlineXML, glyphName, useDefaultGlyphDir, level=0): """ glyphData must be the official <outline> XML from a GLIF. We skip contours with only one point. """ dataList = ["w%s" % norm_float(round(width, 9))] if level > 10: raise UFOParseError( "In parsing component, exceeded 10 levels of reference. " "'%s'. " % (glyphName)) # <outline> tag is optional per spec., e.g. space glyph # does not necessarily have it. if outlineXML is not None: for childContour in outlineXML: if childContour.tag == "contour": if len(childContour) < 2: continue for child in childContour: if child.tag == "point": ptType = child.get("type") pointType = '' if ptType is None else ptType[0] x = self._rd_val(child.get("x")) y = self._rd_val(child.get("y")) dataList.append("%s%s%s" % (pointType, x, y)) elif childContour.tag == "component": # append the component hash. compGlyphName = childContour.get("base") if compGlyphName is None: raise UFOParseError( "'%s' is missing the 'base' attribute in a " "component." % glyphName) dataList.append("%s%s" % ("base:", compGlyphName)) if useDefaultGlyphDir: try: componentPath = self.getGlyphDefaultPath( compGlyphName) except KeyError: raise UFOParseError( "'%s' component glyph is missing from " "contents.plist." % (compGlyphName)) else: # If we are not necessarily using the default layer # for the main glyph, then a missing component may not # have been processed, and may just be in the default # layer. We need to look for component glyphs in the # src list first, then in the defualt layer. try: componentPath = self.getGlyphSrcPath(compGlyphName) if not os.path.exists(componentPath): componentPath = self.getGlyphDefaultPath( compGlyphName) except KeyError: try: componentPath = self.getGlyphDefaultPath( compGlyphName) except KeyError: raise UFOParseError( "'%s' component glyph is missing from " "contents.plist." % (compGlyphName)) if not os.path.exists(componentPath): raise UFOParseError( "'%s' component file is missing: '%s'." % (compGlyphName, componentPath)) etRoot = ET.ElementTree() # Collect transform values for trans_key, flbk_val in COMP_TRANSFORM.items(): value = childContour.get(trans_key, flbk_val) dataList.append(self._rd_val(value)) componentXML = etRoot.parse(componentPath) componentOutlineXML = componentXML.find("outline") _, componentDataList = self.buildGlyphHashValue( width, componentOutlineXML, glyphName, useDefaultGlyphDir, level + 1) dataList.extend(componentDataList) data = "".join(dataList) if len(data) >= 128: data = hashlib.sha512(data.encode("ascii")).hexdigest() return data, dataList