Consistent whitespace across source files according to PEP 8

(mostly automated by using autopep8, fixes #69)
This commit is contained in:
Eduard Braun 2016-09-15 00:35:13 +02:00
parent 943319b710
commit 0f1974c1e2
8 changed files with 4787 additions and 4276 deletions

View file

@ -1,19 +1,19 @@
############################################################################### ###############################################################################
## #
## Copyright (C) 2010 Jeff Schiller, 2010 Louis Simard, 2013-2015 Tavendo GmbH # Copyright (C) 2010 Jeff Schiller, 2010 Louis Simard, 2013-2015 Tavendo GmbH
## #
## Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
## You may obtain a copy of the License at # You may obtain a copy of the License at
## #
## http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
## #
## Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS, # distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
## limitations under the License. # limitations under the License.
## #
############################################################################### ###############################################################################
__version__ = u'0.35' __version__ = u'0.35'

View file

@ -400,6 +400,7 @@ default_properties = { # excluded all properties with 'auto' as default
'viewport-fill-opacity': '1', 'viewport-fill-opacity': '1',
} }
def isSameSign(a, b): return (a <= 0 and b <= 0) or (a >= 0 and b >= 0) def isSameSign(a, b): return (a <= 0 and b <= 0) or (a >= 0 and b >= 0)
scinumber = re.compile(r"[-+]?(\d*\.?)?\d+[eE][-+]?\d+") scinumber = re.compile(r"[-+]?(\d*\.?)?\d+[eE][-+]?\d+")
@ -407,6 +408,7 @@ number = re.compile(r"[-+]?(\d*\.?)?\d+")
sciExponent = re.compile(r"[eE]([-+]?\d+)") sciExponent = re.compile(r"[eE]([-+]?\d+)")
unit = re.compile("(em|ex|px|pt|pc|cm|mm|in|%){1,1}$") unit = re.compile("(em|ex|px|pt|pc|cm|mm|in|%){1,1}$")
class Unit(object): class Unit(object):
# Integer constants for units. # Integer constants for units.
INVALID = -1 INVALID = -1
@ -451,7 +453,8 @@ class Unit(object):
# @staticmethod # @staticmethod
def get(unitstr): def get(unitstr):
if unitstr is None: return Unit.NONE if unitstr is None:
return Unit.NONE
try: try:
return Unit.s2u[unitstr] return Unit.s2u[unitstr]
except KeyError: except KeyError:
@ -467,7 +470,9 @@ class Unit(object):
get = staticmethod(get) get = staticmethod(get)
str = staticmethod(str) str = staticmethod(str)
class SVGLength(object): class SVGLength(object):
def __init__(self, str): def __init__(self, str):
try: # simple unitless and no scientific notation try: # simple unitless and no scientific notation
self.value = float(str) self.value = float(str)
@ -509,6 +514,7 @@ class SVGLength(object):
self.value = 0 self.value = 0
self.units = Unit.INVALID self.units = Unit.INVALID
def findElementsWithId(node, elems=None): def findElementsWithId(node, elems=None):
""" """
Returns all elements with id attributes Returns all elements with id attributes
@ -529,6 +535,7 @@ def findElementsWithId(node, elems=None):
referencingProps = ['fill', 'stroke', 'filter', 'clip-path', 'mask', 'marker-start', referencingProps = ['fill', 'stroke', 'filter', 'clip-path', 'mask', 'marker-start',
'marker-end', 'marker-mid'] 'marker-end', 'marker-mid']
def findReferencedElements(node, ids=None): def findReferencedElements(node, ids=None):
""" """
Returns the number of times an ID is referenced as well as all elements Returns the number of times an ID is referenced as well as all elements
@ -589,6 +596,7 @@ def findReferencedElements(node, ids=None):
findReferencedElements(child, ids) findReferencedElements(child, ids)
return ids return ids
def findReferencingProperty(node, prop, val, ids): def findReferencingProperty(node, prop, val, ids):
global referencingProps global referencingProps
if prop in referencingProps and val != '': if prop in referencingProps and val != '':
@ -629,6 +637,7 @@ numBytesSavedInTransforms = 0
numPointsRemovedFromPolygon = 0 numPointsRemovedFromPolygon = 0
numCommentBytes = 0 numCommentBytes = 0
def removeUnusedDefs(doc, defElem, elemsToRemove=None): def removeUnusedDefs(doc, defElem, elemsToRemove=None):
if elemsToRemove is None: if elemsToRemove is None:
elemsToRemove = [] elemsToRemove = []
@ -639,7 +648,7 @@ def removeUnusedDefs(doc, defElem, elemsToRemove=None):
keepTags = ['font', 'style', 'metadata', 'script', 'title', 'desc'] keepTags = ['font', 'style', 'metadata', 'script', 'title', 'desc']
for elem in defElem.childNodes: for elem in defElem.childNodes:
# only look at it if an element and not referenced anywhere else # only look at it if an element and not referenced anywhere else
if elem.nodeType == 1 and (elem.getAttribute('id') == '' or \ if elem.nodeType == 1 and (elem.getAttribute('id') == '' or
(not elem.getAttribute('id') in referencedIDs)): (not elem.getAttribute('id') in referencedIDs)):
# we only inspect the children of a group in a defs if the group # we only inspect the children of a group in a defs if the group
@ -651,6 +660,7 @@ def removeUnusedDefs(doc, defElem, elemsToRemove=None):
elemsToRemove.append(elem) elemsToRemove.append(elem)
return elemsToRemove return elemsToRemove
def removeUnreferencedElements(doc, keepDefs): def removeUnreferencedElements(doc, keepDefs):
""" """
Removes all unreferenced elements except for <svg>, <font>, <metadata>, <title>, and <desc>. Removes all unreferenced elements except for <svg>, <font>, <metadata>, <title>, and <desc>.
@ -687,6 +697,7 @@ def removeUnreferencedElements(doc, keepDefs):
num += 1 num += 1
return num return num
def shortenIDs(doc, prefix, unprotectedElements=None): def shortenIDs(doc, prefix, unprotectedElements=None):
""" """
Shortens ID names used in the document. ID names referenced the most often are assigned the Shortens ID names used in the document. ID names referenced the most often are assigned the
@ -731,6 +742,7 @@ def shortenIDs(doc, prefix, unprotectedElements=None):
return num return num
def intToID(idnum, prefix): def intToID(idnum, prefix):
""" """
Returns the ID name for the given ID number, spreadsheet-style, i.e. from a to z, Returns the ID name for the given ID number, spreadsheet-style, i.e. from a to z,
@ -745,6 +757,7 @@ def intToID(idnum, prefix):
return prefix + rid return prefix + rid
def renameID(doc, idFrom, idTo, identifiedElements, referencedIDs): def renameID(doc, idFrom, idTo, identifiedElements, referencedIDs):
""" """
Changes the ID name from idFrom to idTo, on the declaring element Changes the ID name from idFrom to idTo, on the declaring element
@ -822,6 +835,7 @@ def renameID(doc, idFrom, idTo, identifiedElements, referencedIDs):
return num return num
def unprotected_ids(doc, options): def unprotected_ids(doc, options):
u"""Returns a list of unprotected IDs within the document doc.""" u"""Returns a list of unprotected IDs within the document doc."""
identifiedElements = findElementsWithId(doc.documentElement) identifiedElements = findElementsWithId(doc.documentElement)
@ -847,6 +861,7 @@ def unprotected_ids(doc, options):
del identifiedElements[id] del identifiedElements[id]
return identifiedElements return identifiedElements
def removeUnreferencedIDs(referencedIDs, identifiedElements): def removeUnreferencedIDs(referencedIDs, identifiedElements):
""" """
Removes the unreferenced ID attributes. Removes the unreferenced ID attributes.
@ -855,7 +870,7 @@ def removeUnreferencedIDs(referencedIDs, identifiedElements):
""" """
global numIDsRemoved global numIDsRemoved
keepTags = ['font'] keepTags = ['font']
num = 0; num = 0
for id in list(identifiedElements.keys()): for id in list(identifiedElements.keys()):
node = identifiedElements[id] node = identifiedElements[id]
if (id in referencedIDs) == False and not node.nodeName in keepTags: if (id in referencedIDs) == False and not node.nodeName in keepTags:
@ -864,6 +879,7 @@ def removeUnreferencedIDs(referencedIDs, identifiedElements):
num += 1 num += 1
return num return num
def removeNamespacedAttributes(node, namespaces): def removeNamespacedAttributes(node, namespaces):
global numAttrsRemoved global numAttrsRemoved
num = 0 num = 0
@ -885,6 +901,7 @@ def removeNamespacedAttributes(node, namespaces):
num += removeNamespacedAttributes(child, namespaces) num += removeNamespacedAttributes(child, namespaces)
return num return num
def removeNamespacedElements(node, namespaces): def removeNamespacedElements(node, namespaces):
global numElemsRemoved global numElemsRemoved
num = 0 num = 0
@ -905,6 +922,7 @@ def removeNamespacedElements(node, namespaces):
num += removeNamespacedElements(child, namespaces) num += removeNamespacedElements(child, namespaces)
return num return num
def removeDescriptiveElements(doc, options): def removeDescriptiveElements(doc, options):
elementTypes = [] elementTypes = []
if options.remove_descriptive_elements: if options.remove_descriptive_elements:
@ -932,6 +950,7 @@ def removeDescriptiveElements(doc, options):
return num return num
def removeNestedGroups(node): def removeNestedGroups(node):
""" """
This walks further and further down the tree, removing groups This walks further and further down the tree, removing groups
@ -968,6 +987,7 @@ def removeNestedGroups(node):
num += removeNestedGroups(child) num += removeNestedGroups(child)
return num return num
def moveCommonAttributesToParentGroup(elem, referencedElements): def moveCommonAttributesToParentGroup(elem, referencedElements):
""" """
This recursively calls this function on all children of the passed in element This recursively calls this function on all children of the passed in element
@ -992,7 +1012,8 @@ def moveCommonAttributesToParentGroup(elem, referencedElements):
return num return num
# only process the children if there are more than one element # only process the children if there are more than one element
if len(childElements) <= 1: return num if len(childElements) <= 1:
return num
commonAttrs = {} commonAttrs = {}
# add all inheritable properties of the first child element # add all inheritable properties of the first child element
@ -1049,6 +1070,7 @@ def moveCommonAttributesToParentGroup(elem, referencedElements):
num += (len(childElements) - 1) * len(commonAttrs) num += (len(childElements) - 1) * len(commonAttrs)
return num return num
def createGroupsForCommonAttributes(elem): def createGroupsForCommonAttributes(elem):
""" """
Creates <g> elements to contain runs of 3 or more Creates <g> elements to contain runs of 3 or more
@ -1114,17 +1136,21 @@ def createGroupsForCommonAttributes(elem):
while runStart > 0: while runStart > 0:
nextNode = elem.childNodes.item(runStart - 1) nextNode = elem.childNodes.item(runStart - 1)
if nextNode.nodeType == 1: if nextNode.nodeType == 1:
if nextNode.getAttribute(curAttr) != value: break if nextNode.getAttribute(curAttr) != value:
break
else: else:
runElements += 1 runElements += 1
runStart -= 1 runStart -= 1
else: runStart -= 1 else:
runStart -= 1
if runElements >= 3: if runElements >= 3:
# Include whitespace/comment/etc. nodes in the run. # Include whitespace/comment/etc. nodes in the run.
while runEnd < elem.childNodes.length - 1: while runEnd < elem.childNodes.length - 1:
if elem.childNodes.item(runEnd + 1).nodeType == 1: break if elem.childNodes.item(runEnd + 1).nodeType == 1:
else: runEnd += 1 break
else:
runEnd += 1
runLength = runEnd - runStart + 1 runLength = runEnd - runStart + 1
if runLength == elem.childNodes.length: # Every child has this if runLength == elem.childNodes.length: # Every child has this
@ -1170,6 +1196,7 @@ def createGroupsForCommonAttributes(elem):
return num return num
def removeUnusedAttributesOnParent(elem): def removeUnusedAttributesOnParent(elem):
""" """
This recursively calls this function on all children of the element passed in, This recursively calls this function on all children of the element passed in,
@ -1185,7 +1212,8 @@ def removeUnusedAttributesOnParent(elem):
num += removeUnusedAttributesOnParent(child) num += removeUnusedAttributesOnParent(child)
# only process the children if there are more than one element # only process the children if there are more than one element
if len(childElements) <= 1: return num if len(childElements) <= 1:
return num
# get all attribute values on this parent # get all attribute values on this parent
attrList = elem.attributes attrList = elem.attributes
@ -1223,6 +1251,7 @@ def removeUnusedAttributesOnParent(elem):
return num return num
def removeDuplicateGradientStops(doc): def removeDuplicateGradientStops(doc):
global numElemsRemoved global numElemsRemoved
num = 0 num = 0
@ -1241,8 +1270,10 @@ def removeDuplicateGradientStops(doc):
else: else:
offset = 0 offset = 0
# set the stop offset value to the integer or floating point equivalent # set the stop offset value to the integer or floating point equivalent
if int(offset) == offset: stop.setAttribute('offset', str(int(offset))) if int(offset) == offset:
else: stop.setAttribute('offset', str(offset)) stop.setAttribute('offset', str(int(offset)))
else:
stop.setAttribute('offset', str(offset))
color = stop.getAttribute('stop-color') color = stop.getAttribute('stop-color')
opacity = stop.getAttribute('stop-opacity') opacity = stop.getAttribute('stop-opacity')
@ -1261,6 +1292,7 @@ def removeDuplicateGradientStops(doc):
# linear gradients # linear gradients
return num return num
def collapseSinglyReferencedGradients(doc): def collapseSinglyReferencedGradients(doc):
global numElemsRemoved global numElemsRemoved
num = 0 num = 0
@ -1318,6 +1350,7 @@ def collapseSinglyReferencedGradients(doc):
num += 1 num += 1
return num return num
def removeDuplicateGradients(doc): def removeDuplicateGradients(doc):
global numElemsRemoved global numElemsRemoved
num = 0 num = 0
@ -1331,7 +1364,8 @@ def removeDuplicateGradients(doc):
# TODO: should slice grads from 'grad' here to optimize # TODO: should slice grads from 'grad' here to optimize
for ograd in grads: for ograd in grads:
# do not compare gradient to itself # do not compare gradient to itself
if grad == ograd: continue if grad == ograd:
continue
# compare grad to ograd (all properties, then all stops) # compare grad to ograd (all properties, then all stops)
# if attributes do not match, go to next gradient # if attributes do not match, go to next gradient
@ -1339,9 +1373,10 @@ def removeDuplicateGradients(doc):
for attr in ['gradientUnits', 'spreadMethod', 'gradientTransform', 'x1', 'y1', 'x2', 'y2', 'cx', 'cy', 'fx', 'fy', 'r']: for attr in ['gradientUnits', 'spreadMethod', 'gradientTransform', 'x1', 'y1', 'x2', 'y2', 'cx', 'cy', 'fx', 'fy', 'r']:
if grad.getAttribute(attr) != ograd.getAttribute(attr): if grad.getAttribute(attr) != ograd.getAttribute(attr):
someGradAttrsDoNotMatch = True someGradAttrsDoNotMatch = True
break; break
if someGradAttrsDoNotMatch: continue if someGradAttrsDoNotMatch:
continue
# compare xlink:href values too # compare xlink:href values too
if grad.getAttributeNS(NS['XLINK'], 'href') != ograd.getAttributeNS(NS['XLINK'], 'href'): if grad.getAttributeNS(NS['XLINK'], 'href') != ograd.getAttributeNS(NS['XLINK'], 'href'):
@ -1351,19 +1386,22 @@ def removeDuplicateGradients(doc):
stops = grad.getElementsByTagName('stop') stops = grad.getElementsByTagName('stop')
ostops = ograd.getElementsByTagName('stop') ostops = ograd.getElementsByTagName('stop')
if stops.length != ostops.length: continue if stops.length != ostops.length:
continue
# now compare stops # now compare stops
stopsNotEqual = False stopsNotEqual = False
for i in range(stops.length): for i in range(stops.length):
if stopsNotEqual: break if stopsNotEqual:
break
stop = stops.item(i) stop = stops.item(i)
ostop = ostops.item(i) ostop = ostops.item(i)
for attr in ['offset', 'stop-color', 'stop-opacity', 'style']: for attr in ['offset', 'stop-color', 'stop-opacity', 'style']:
if stop.getAttribute(attr) != ostop.getAttribute(attr): if stop.getAttribute(attr) != ostop.getAttribute(attr):
stopsNotEqual = True stopsNotEqual = True
break break
if stopsNotEqual: continue if stopsNotEqual:
continue
# ograd is a duplicate of grad, we schedule it to be removed UNLESS # ograd is a duplicate of grad, we schedule it to be removed UNLESS
# ograd is ALREADY considered a 'master' element # ograd is ALREADY considered a 'master' element
@ -1411,6 +1449,7 @@ def removeDuplicateGradients(doc):
num += 1 num += 1
return num return num
def _getStyle(node): def _getStyle(node):
u"""Returns the style attribute of a node as a dictionary.""" u"""Returns the style attribute of a node as a dictionary."""
if node.nodeType == 1 and len(node.getAttribute('style')) > 0: if node.nodeType == 1 and len(node.getAttribute('style')) > 0:
@ -1424,6 +1463,7 @@ def _getStyle(node):
else: else:
return {} return {}
def _setStyle(node, styleMap): def _setStyle(node, styleMap):
u"""Sets the style attribute of a node to the dictionary ``styleMap``.""" u"""Sets the style attribute of a node to the dictionary ``styleMap``."""
fixedStyle = ';'.join([prop + ':' + styleMap[prop] for prop in list(styleMap.keys())]) fixedStyle = ';'.join([prop + ':' + styleMap[prop] for prop in list(styleMap.keys())])
@ -1433,6 +1473,7 @@ def _setStyle(node, styleMap):
node.removeAttribute('style') node.removeAttribute('style')
return node return node
def repairStyle(node, options): def repairStyle(node, options):
num = 0 num = 0
styleMap = _getStyle(node) styleMap = _getStyle(node)
@ -1564,6 +1605,7 @@ def repairStyle(node, options):
return num return num
def styleInheritedFromParent(node, style): def styleInheritedFromParent(node, style):
""" """
Returns the value of 'style' that is inherited from the parents of the passed-in node Returns the value of 'style' that is inherited from the parents of the passed-in node
@ -1571,7 +1613,7 @@ def styleInheritedFromParent(node, style):
Warning: This method only considers presentation attributes and inline styles, Warning: This method only considers presentation attributes and inline styles,
any style sheets are ignored! any style sheets are ignored!
""" """
parentNode = node.parentNode; parentNode = node.parentNode
# return None if we reached the Document element # return None if we reached the Document element
if parentNode.nodeType == 9: if parentNode.nodeType == 9:
@ -1592,6 +1634,7 @@ def styleInheritedFromParent(node, style):
# check the next parent recursively if we did not find a value yet # check the next parent recursively if we did not find a value yet
return styleInheritedFromParent(parentNode, style) return styleInheritedFromParent(parentNode, style)
def styleInheritedByChild(node, style, nodeIsChild=False): def styleInheritedByChild(node, style, nodeIsChild=False):
""" """
Returns whether 'style' is inherited by any children of the passed-in node Returns whether 'style' is inherited by any children of the passed-in node
@ -1609,7 +1652,6 @@ def styleInheritedByChild(node, style, nodeIsChild=False):
if node.nodeType != 1: if node.nodeType != 1:
return False return False
if nodeIsChild: if nodeIsChild:
# if the current child node sets a new value for 'style' # if the current child node sets a new value for 'style'
# we can stop the search in the current branch of the DOM tree # we can stop the search in the current branch of the DOM tree
@ -1641,6 +1683,7 @@ def styleInheritedByChild(node, style, nodeIsChild=False):
# (e.g nodes without children at the end of the DOM tree, text nodes, ...) # (e.g nodes without children at the end of the DOM tree, text nodes, ...)
return True return True
def mayContainTextNodes(node): def mayContainTextNodes(node):
""" """
Returns True if the passed-in node is probably a text element, or at least Returns True if the passed-in node is probably a text element, or at least
@ -1814,6 +1857,7 @@ default_attributes = [
DefaultAttribute('yChannelSelector', 'A', elements='feDisplacementMap') DefaultAttribute('yChannelSelector', 'A', elements='feDisplacementMap')
] ]
def taint(taintedSet, taintedAttribute): def taint(taintedSet, taintedAttribute):
u"""Adds an attribute to a set of attributes. u"""Adds an attribute to a set of attributes.
@ -1825,6 +1869,7 @@ def taint(taintedSet, taintedAttribute):
taintedSet.add('marker') taintedSet.add('marker')
return taintedSet return taintedSet
def removeDefaultAttributeValue(node, attribute): def removeDefaultAttributeValue(node, attribute):
""" """
Removes the DefaultAttribute 'attribute' from 'node' if specified conditions are fulfilled Removes the DefaultAttribute 'attribute' from 'node' if specified conditions are fulfilled
@ -1851,12 +1896,14 @@ def removeDefaultAttributeValue(node, attribute):
return 0 return 0
def removeDefaultAttributeValues(node, options, tainted=set()): def removeDefaultAttributeValues(node, options, tainted=set()):
u"""'tainted' keeps a set of attributes defined in parent nodes. u"""'tainted' keeps a set of attributes defined in parent nodes.
For such attributes, we don't delete attributes with default values.""" For such attributes, we don't delete attributes with default values."""
num = 0 num = 0
if node.nodeType != 1: return 0 if node.nodeType != 1:
return 0
# Conditionally remove all default attributes defined in 'default_attributes' (a list of 'DefaultAttribute's) # Conditionally remove all default attributes defined in 'default_attributes' (a list of 'DefaultAttribute's)
for attribute in default_attributes: for attribute in default_attributes:
@ -1892,6 +1939,8 @@ def removeDefaultAttributeValues(node, options, tainted=set()):
rgb = re.compile(r"\s*rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*") rgb = re.compile(r"\s*rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)\s*")
rgbp = re.compile(r"\s*rgb\(\s*(\d*\.?\d+)%\s*,\s*(\d*\.?\d+)%\s*,\s*(\d*\.?\d+)%\s*\)\s*") rgbp = re.compile(r"\s*rgb\(\s*(\d*\.?\d+)%\s*,\s*(\d*\.?\d+)%\s*,\s*(\d*\.?\d+)%\s*\)\s*")
def convertColor(value): def convertColor(value):
""" """
Converts the input color string and returns a #RRGGBB (or #RGB if possible) string Converts the input color string and returns a #RRGGBB (or #RGB if possible) string
@ -1922,17 +1971,19 @@ def convertColor(value):
return s return s
def convertColors(element): def convertColors(element):
""" """
Recursively converts all color properties into #RRGGBB format if shorter Recursively converts all color properties into #RRGGBB format if shorter
""" """
numBytes = 0 numBytes = 0
if element.nodeType != 1: return 0 if element.nodeType != 1:
return 0
# set up list of color attributes for each element type # set up list of color attributes for each element type
attrsToConvert = [] attrsToConvert = []
if element.nodeName in ['rect', 'circle', 'ellipse', 'polygon', \ if element.nodeName in ['rect', 'circle', 'ellipse', 'polygon',
'line', 'polyline', 'path', 'g', 'a']: 'line', 'polyline', 'path', 'g', 'a']:
attrsToConvert = ['fill', 'stroke'] attrsToConvert = ['fill', 'stroke']
elif element.nodeName in ['stop']: elif element.nodeName in ['stop']:
@ -1971,6 +2022,8 @@ def convertColors(element):
# TODO: go over what this method does and see if there is a way to optimize it # TODO: go over what this method does and see if there is a way to optimize it
# TODO: go over the performance of this method and see if I can save memory/speed by # TODO: go over the performance of this method and see if I can save memory/speed by
# reusing data structures, etc # reusing data structures, etc
def cleanPath(element, options): def cleanPath(element, options):
""" """
Cleans the path string (d attribute) of the element Cleans the path string (d attribute) of the element
@ -2318,7 +2371,7 @@ def cleanPath(element, options):
newPath.append(('t', [data[i + 2], data[i + 3]])) newPath.append(('t', [data[i + 2], data[i + 3]]))
numPathSegmentsReduced += 1 numPathSegmentsReduced += 1
else: else:
j = 0; j = 0
while j <= 3: while j <= 3:
curveTuples.append(data[i + j]) curveTuples.append(data[i + j])
j += 1 j += 1
@ -2384,7 +2437,6 @@ def cleanPath(element, options):
element.setAttribute('d', newPathStr) element.setAttribute('d', newPathStr)
def parseListOfPoints(s): def parseListOfPoints(s):
""" """
Parse string into a list of points. Parse string into a list of points.
@ -2419,7 +2471,7 @@ def parseListOfPoints(s):
else: else:
# unless we accidentally split a number that was in scientific notation # unless we accidentally split a number that was in scientific notation
# and had a negative exponent (500.00e-1) # and had a negative exponent (500.00e-1)
prev = ""; prev = ""
if len(nums): if len(nums):
prev = nums[len(nums) - 1] prev = nums[len(nums) - 1]
if prev and prev[len(prev) - 1] in ['e', 'E']: if prev and prev[len(prev) - 1] in ['e', 'E']:
@ -2428,7 +2480,8 @@ def parseListOfPoints(s):
nums.append('-' + negcoords[j]) nums.append('-' + negcoords[j])
# if we have an odd number of points, return empty # if we have an odd number of points, return empty
if len(nums) % 2 != 0: return [] if len(nums) % 2 != 0:
return []
# now resolve into Decimal values # now resolve into Decimal values
i = 0 i = 0
@ -2444,7 +2497,6 @@ def parseListOfPoints(s):
return nums return nums
def cleanPolygon(elem, options): def cleanPolygon(elem, options):
""" """
Remove unnecessary closing point of polygon points attribute Remove unnecessary closing point of polygon points attribute
@ -2462,7 +2514,6 @@ def cleanPolygon(elem, options):
elem.setAttribute('points', scourCoordinates(pts, options, True)) elem.setAttribute('points', scourCoordinates(pts, options, True))
def cleanPolyline(elem, options): def cleanPolyline(elem, options):
""" """
Scour the polyline points attribute Scour the polyline points attribute
@ -2471,7 +2522,6 @@ def cleanPolyline(elem, options):
elem.setAttribute('points', scourCoordinates(pts, options, True)) elem.setAttribute('points', scourCoordinates(pts, options, True))
def serializePath(pathObj, options): def serializePath(pathObj, options):
""" """
Reserializes the path data with some cleanups. Reserializes the path data with some cleanups.
@ -2481,7 +2531,6 @@ def serializePath(pathObj, options):
return ''.join([cmd + scourCoordinates(data, options, (cmd == 'a')) for cmd, data in pathObj]) return ''.join([cmd + scourCoordinates(data, options, (cmd == 'a')) for cmd, data in pathObj])
def serializeTransform(transformObj): def serializeTransform(transformObj):
""" """
Reserializes the transform data with some cleanups. Reserializes the transform data with some cleanups.
@ -2494,7 +2543,6 @@ def serializeTransform(transformObj):
) )
def scourCoordinates(data, options, forceCommaWsp=False): def scourCoordinates(data, options, forceCommaWsp=False):
""" """
Serializes coordinate data with some cleanups: Serializes coordinate data with some cleanups:
@ -2545,7 +2593,6 @@ def scourCoordinates(data, options, forceCommaWsp = False):
return '' return ''
def scourLength(length): def scourLength(length):
""" """
Scours a length. Accepts units. Scours a length. Accepts units.
@ -2555,7 +2602,6 @@ def scourLength(length):
return scourUnitlessLength(length.value) + Unit.str(length.units) return scourUnitlessLength(length.value) + Unit.str(length.units)
def scourUnitlessLength(length, needsRendererWorkaround=False): # length is of a numeric type def scourUnitlessLength(length, needsRendererWorkaround=False): # length is of a numeric type
""" """
Scours the numeric part of a length only. Does not accept units. Scours the numeric part of a length only. Does not accept units.
@ -2605,7 +2651,6 @@ def scourUnitlessLength(length, needsRendererWorkaround=False): # length is of a
return nonsci return nonsci
def reducePrecision(element): def reducePrecision(element):
""" """
Because opacities, letter spacings, stroke widths and all that don't need Because opacities, letter spacings, stroke widths and all that don't need
@ -2652,7 +2697,6 @@ def reducePrecision(element):
return num return num
def optimizeAngle(angle): def optimizeAngle(angle):
""" """
Because any rotation can be expressed within 360 degrees Because any rotation can be expressed within 360 degrees
@ -2664,18 +2708,21 @@ def optimizeAngle(angle):
# The modulo operator yields results with the sign of the # The modulo operator yields results with the sign of the
# divisor, so for negative dividends, we preserve the sign # divisor, so for negative dividends, we preserve the sign
# of the angle. # of the angle.
if angle < 0: angle %= -360 if angle < 0:
else: angle %= 360 angle %= -360
else:
angle %= 360
# 720 degrees is unneccessary, as 360 covers all angles. # 720 degrees is unneccessary, as 360 covers all angles.
# As "-x" is shorter than "35x" and "-xxx" one character # As "-x" is shorter than "35x" and "-xxx" one character
# longer than positive angles <= 260, we constrain angle # longer than positive angles <= 260, we constrain angle
# range to [-90, 270[ (or, equally valid: ]-100, 260]). # range to [-90, 270[ (or, equally valid: ]-100, 260]).
if angle >= 270: angle -= 360 if angle >= 270:
elif angle < -90: angle += 360 angle -= 360
elif angle < -90:
angle += 360
return angle return angle
def optimizeTransform(transform): def optimizeTransform(transform):
""" """
Optimises a series of transformations parsed from a single Optimises a series of transformations parsed from a single
@ -2836,7 +2883,6 @@ def optimizeTransform(transform):
i += 1 i += 1
def optimizeTransforms(element, options): def optimizeTransforms(element, options):
""" """
Attempts to optimise transform specifications on the given node and its children. Attempts to optimise transform specifications on the given node and its children.
@ -2868,7 +2914,6 @@ def optimizeTransforms(element, options):
return num return num
def removeComments(element): def removeComments(element):
""" """
Removes comments from the element and its children. Removes comments from the element and its children.
@ -2883,7 +2928,6 @@ def removeComments(element):
removeComments(subelement) removeComments(subelement)
def embedRasters(element, options): def embedRasters(element, options):
import base64 import base64
import urllib import urllib
@ -2911,7 +2955,8 @@ def embedRasters(element, options):
# if this is not an absolute path, set path relative # if this is not an absolute path, set path relative
# to script file based on input arg # to script file based on input arg
infilename = '.' infilename = '.'
if options.infilename: infilename = options.infilename if options.infilename:
infilename = options.infilename
href = os.path.join(os.path.dirname(infilename), href) href = os.path.join(os.path.dirname(infilename), href)
rasterdata = '' rasterdata = ''
@ -2942,7 +2987,6 @@ def embedRasters(element, options):
del b64eRaster del b64eRaster
def properlySizeDoc(docElement, options): def properlySizeDoc(docElement, options):
# get doc width and height # get doc width and height
w = SVGLength(docElement.getAttribute('width')) w = SVGLength(docElement.getAttribute('width'))
@ -2984,9 +3028,9 @@ def properlySizeDoc(docElement, options):
docElement.removeAttribute('height') docElement.removeAttribute('height')
def remapNamespacePrefix(node, oldprefix, newprefix): def remapNamespacePrefix(node, oldprefix, newprefix):
if node == None or node.nodeType != 1: return if node == None or node.nodeType != 1:
return
if node.prefix == oldprefix: if node.prefix == oldprefix:
localName = node.localName localName = node.localName
@ -2999,7 +3043,7 @@ def remapNamespacePrefix(node, oldprefix, newprefix):
if newprefix != '': if newprefix != '':
newNode = doc.createElementNS(namespace, newprefix + ":" + localName) newNode = doc.createElementNS(namespace, newprefix + ":" + localName)
else: else:
newNode = doc.createElement(localName); newNode = doc.createElement(localName)
# add all the attributes # add all the attributes
attrList = node.attributes attrList = node.attributes
@ -3021,7 +3065,6 @@ def remapNamespacePrefix(node, oldprefix, newprefix):
remapNamespacePrefix(child, oldprefix, newprefix) remapNamespacePrefix(child, oldprefix, newprefix)
def makeWellFormed(str): def makeWellFormed(str):
# Don't escape quotation marks for now as they are fine in text nodes # Don't escape quotation marks for now as they are fine in text nodes
# as well as in attributes if used reciprocally # as well as in attributes if used reciprocally
@ -3039,7 +3082,6 @@ def makeWellFormed(str):
return ''.join([xml_ents[c] if c in xml_ents else c for c in str]) return ''.join([xml_ents[c] if c in xml_ents else c for c in str])
# hand-rolled serialization function that has the following benefits: # hand-rolled serialization function that has the following benefits:
# - pretty printing # - pretty printing
# - somewhat judicious use of whitespace # - somewhat judicious use of whitespace
@ -3051,8 +3093,10 @@ def serializeXML(element, options, ind = 0, preserveWhitespace = False):
I = '' I = ''
newline = '' newline = ''
if options.newlines: if options.newlines:
if options.indent_type == 'tab': I='\t' if options.indent_type == 'tab':
elif options.indent_type == 'space': I=' ' I = '\t'
elif options.indent_type == 'space':
I = ' '
I *= options.indent_depth I *= options.indent_depth
newline = '\n' newline = '\n'
@ -3096,7 +3140,8 @@ def serializeXML(element, options, ind = 0, preserveWhitespace = False):
attrIndices += [attrName2Index[name] for name in sorted(attrName2Index.keys())] attrIndices += [attrName2Index[name] for name in sorted(attrName2Index.keys())]
for index in attrIndices: for index in attrIndices:
attr = attrList.item(index) attr = attrList.item(index)
if attr.nodeName == 'id' or attr.nodeName == 'xml:id': continue if attr.nodeName == 'id' or attr.nodeName == 'xml:id':
continue
# if the attribute value contains a double-quote, use single-quotes # if the attribute value contains a double-quote, use single-quotes
quot = '"' quot = '"'
if attr.nodeValue.find('"') != -1: if attr.nodeValue.find('"') != -1:
@ -3156,17 +3201,19 @@ def serializeXML(element, options, ind = 0, preserveWhitespace = False):
else: # ignore the rest else: # ignore the rest
pass pass
if onNewLine: outParts.append(I * ind) if onNewLine:
outParts.append(I * ind)
outParts.extend(['</', element.nodeName, '>']) outParts.extend(['</', element.nodeName, '>'])
if indent > 0: outParts.append(newline) if indent > 0:
outParts.append(newline)
else: else:
outParts.append('/>') outParts.append('/>')
if indent > 0: outParts.append(newline) if indent > 0:
outParts.append(newline)
return "".join(outParts) return "".join(outParts)
# this is the main method # this is the main method
# input is a string representation of the input XML # input is a string representation of the input XML
# returns a string representation of the output XML # returns a string representation of the output XML
@ -3414,7 +3461,6 @@ def scourString(in_string, options=None):
return total_output return total_output
# used mostly by unit tests # used mostly by unit tests
# input is a filename # input is a filename
# returns the minidom doc representation of the SVG # returns the minidom doc representation of the SVG
@ -3438,19 +3484,18 @@ def scourXmlFile(filename, options=None):
return doc return doc
# GZ: Seems most other commandline tools don't do this, is it really wanted? # GZ: Seems most other commandline tools don't do this, is it really wanted?
class HeaderedFormatter(optparse.IndentedHelpFormatter): class HeaderedFormatter(optparse.IndentedHelpFormatter):
""" """
Show application name, version number, and copyright statement Show application name, version number, and copyright statement
above usage information. above usage information.
""" """
def format_usage(self, usage): def format_usage(self, usage):
return "%s %s\n%s\n%s" % (APP, VER, COPYRIGHT, return "%s %s\n%s\n%s" % (APP, VER, COPYRIGHT,
optparse.IndentedHelpFormatter.format_usage(self, usage)) optparse.IndentedHelpFormatter.format_usage(self, usage))
# GZ: would prefer this to be in a function or class scope, but tests etc need # GZ: would prefer this to be in a function or class scope, but tests etc need
# access to the defaults anyway # access to the defaults anyway
_options_parser = optparse.OptionParser( _options_parser = optparse.OptionParser(
@ -3575,7 +3620,6 @@ _option_group_compatibility.add_option("--error-on-flowtext",
_options_parser.add_option_group(_option_group_compatibility) _options_parser.add_option_group(_option_group_compatibility)
def parse_args(args=None, ignore_additional_args=False): def parse_args(args=None, ignore_additional_args=False):
options, rargs = _options_parser.parse_args(args) options, rargs = _options_parser.parse_args(args)
@ -3598,10 +3642,10 @@ def parse_args(args=None, ignore_additional_args=False):
return options return options
def generateDefaultOptions(): def generateDefaultOptions():
## FIXME: clean up this mess/hack and refactor arg parsing to argparse # FIXME: clean up this mess/hack and refactor arg parsing to argparse
class Struct: class Struct:
def __init__(self, **entries): def __init__(self, **entries):
self.__dict__.update(entries) self.__dict__.update(entries)
@ -3610,7 +3654,6 @@ def generateDefaultOptions():
return Struct(**d) return Struct(**d)
# sanitizes options by updating attributes in a set of defaults options while discarding unknown attributes # sanitizes options by updating attributes in a set of defaults options while discarding unknown attributes
def sanitizeOptions(options): def sanitizeOptions(options):
optionsDict = dict((key, getattr(options, key)) for key in dir(options) if not key.startswith('__')) optionsDict = dict((key, getattr(options, key)) for key in dir(options) if not key.startswith('__'))
@ -3621,7 +3664,6 @@ def sanitizeOptions(options):
return sanitizedOptions return sanitizedOptions
def maybe_gziped_file(filename, mode="r"): def maybe_gziped_file(filename, mode="r"):
if os.path.splitext(filename)[1].lower() in (".svgz", ".gz"): if os.path.splitext(filename)[1].lower() in (".svgz", ".gz"):
import gzip import gzip
@ -3629,7 +3671,6 @@ def maybe_gziped_file(filename, mode="r"):
return open(filename, mode) return open(filename, mode)
def getInOut(options): def getInOut(options):
if options.infilename: if options.infilename:
infile = maybe_gziped_file(options.infilename, "rb") infile = maybe_gziped_file(options.infilename, "rb")
@ -3660,7 +3701,6 @@ def getInOut(options):
return [infile, outfile] return [infile, outfile]
def getReport(): def getReport():
return ' Number of elements removed: ' + str(numElemsRemoved) + os.linesep + \ return ' Number of elements removed: ' + str(numElemsRemoved) + os.linesep + \
' Number of attributes removed: ' + str(numAttrsRemoved) + os.linesep + \ ' Number of attributes removed: ' + str(numAttrsRemoved) + os.linesep + \
@ -3677,7 +3717,6 @@ def getReport():
' Number of bytes saved in transformations: ' + str(numBytesSavedInTransforms) ' Number of bytes saved in transformations: ' + str(numBytesSavedInTransforms)
def start(options, input, output): def start(options, input, output):
start = walltime() start = walltime()

View file

@ -48,7 +48,10 @@ from decimal import *
from functools import partial from functools import partial
# Sentinel. # Sentinel.
class _EOF(object): class _EOF(object):
def __repr__(self): def __repr__(self):
return 'EOF' return 'EOF'
EOF = _EOF() EOF = _EOF()
@ -70,6 +73,7 @@ class Lexer(object):
http://www.gooli.org/blog/a-simple-lexer-in-python/ http://www.gooli.org/blog/a-simple-lexer-in-python/
""" """
def __init__(self, lexicon): def __init__(self, lexicon):
self.lexicon = lexicon self.lexicon = lexicon
parts = [] parts = []
@ -270,7 +274,6 @@ class SVGPathParser(object):
token = next_val_fn() token = next_val_fn()
return x, token return x, token
def rule_coordinate_pair(self, next_val_fn, token): def rule_coordinate_pair(self, next_val_fn, token):
# Inline these since this rule is so common. # Inline these since this rule is so common.
if token[0] not in self.number_tokens: if token[0] not in self.number_tokens:

View file

@ -66,6 +66,7 @@ from functools import partial
# Sentinel. # Sentinel.
class _EOF(object): class _EOF(object):
def __repr__(self): def __repr__(self):
return 'EOF' return 'EOF'
EOF = _EOF() EOF = _EOF()
@ -89,6 +90,7 @@ class Lexer(object):
http://www.gooli.org/blog/a-simple-lexer-in-python/ http://www.gooli.org/blog/a-simple-lexer-in-python/
""" """
def __init__(self, lexicon): def __init__(self, lexicon):
self.lexicon = lexicon self.lexicon = lexicon
parts = [] parts = []

View file

@ -48,6 +48,7 @@
# | DASHMATCH | FUNCTION S* any* ')' # | DASHMATCH | FUNCTION S* any* ')'
# | '(' S* any* ')' | '[' S* any* ']' ] S*; # | '(' S* any* ')' | '[' S* any* ']' ] S*;
def parseCssString(str): def parseCssString(str):
rules = [] rules = []
# first, split on } to get the rule chunks # first, split on } to get the rule chunks
@ -55,17 +56,20 @@ def parseCssString(str):
for chunk in chunks: for chunk in chunks:
# second, split on { to get the selector and the list of properties # second, split on { to get the selector and the list of properties
bits = chunk.split('{') bits = chunk.split('{')
if len(bits) != 2: continue if len(bits) != 2:
continue
rule = {} rule = {}
rule['selector'] = bits[0].strip() rule['selector'] = bits[0].strip()
# third, split on ; to get the property declarations # third, split on ; to get the property declarations
bites = bits[1].strip().split(';') bites = bits[1].strip().split(';')
if len(bites) < 1: continue if len(bites) < 1:
continue
props = {} props = {}
for bite in bites: for bite in bites:
# fourth, split on : to get the property name and value # fourth, split on : to get the property name and value
nibbles = bite.strip().split(':') nibbles = bite.strip().split(':')
if len(nibbles) != 2: continue if len(nibbles) != 2:
continue
props[nibbles[0].strip()] = nibbles[1].strip() props[nibbles[0].strip()] = nibbles[1].strip()
rule['properties'] = props rule['properties'] = props
rules.append(rule) rules.append(rule)

View file

@ -1,19 +1,19 @@
############################################################################### ###############################################################################
## #
## Copyright (C) 2013-2014 Tavendo GmbH # Copyright (C) 2013-2014 Tavendo GmbH
## #
## Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
## you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
## You may obtain a copy of the License at # You may obtain a copy of the License at
## #
## http://www.apache.org/licenses/LICENSE-2.0 # http://www.apache.org/licenses/LICENSE-2.0
## #
## Unless required by applicable law or agreed to in writing, software # Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS, # distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
## limitations under the License. # limitations under the License.
## #
############################################################################### ###############################################################################
import os import os

View file

@ -27,19 +27,24 @@ from scour.yocto_css import parseCssString
class Blank(unittest.TestCase): class Blank(unittest.TestCase):
def runTest(self): def runTest(self):
r = parseCssString('') r = parseCssString('')
self.assertEqual(len(r), 0, 'Blank string returned non-empty list') self.assertEqual(len(r), 0, 'Blank string returned non-empty list')
self.assertEqual(type(r), type([]), 'Blank string returned non list') self.assertEqual(type(r), type([]), 'Blank string returned non list')
class ElementSelector(unittest.TestCase): class ElementSelector(unittest.TestCase):
def runTest(self): def runTest(self):
r = parseCssString('foo {}') r = parseCssString('foo {}')
self.assertEqual(len(r), 1, 'Element selector not returned') self.assertEqual(len(r), 1, 'Element selector not returned')
self.assertEqual(r[0]['selector'], 'foo', 'Selector for foo not returned') self.assertEqual(r[0]['selector'], 'foo', 'Selector for foo not returned')
self.assertEqual(len(r[0]['properties']), 0, 'Property list for foo not empty') self.assertEqual(len(r[0]['properties']), 0, 'Property list for foo not empty')
class ElementSelectorWithProperty(unittest.TestCase): class ElementSelectorWithProperty(unittest.TestCase):
def runTest(self): def runTest(self):
r = parseCssString('foo { bar: baz}') r = parseCssString('foo { bar: baz}')
self.assertEqual(len(r), 1, 'Element selector not returned') self.assertEqual(len(r), 1, 'Element selector not returned')

File diff suppressed because it is too large Load diff