-
Notifications
You must be signed in to change notification settings - Fork 26
/
Copy pathdiff.py
108 lines (95 loc) · 4.58 KB
/
diff.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
import re
from collections import namedtuple
import xmldiff
import xmldiff.main
from lxml import etree
from PIL import Image, ImageChops
import cairosvg
import io
UpdateAttribx = namedtuple("UpdateAttribx", 'node name value old')
MoveNodex = namedtuple("MoveNodex", 'node target position nodex targetx')
def main(f_out, f_out_py):
parser = etree.XMLParser(remove_blank_text=True)
orig_tree = etree.parse(f_out, parser)
py_tree = etree.parse(f_out_py, parser)
diff = xmldiff.main.diff_trees(orig_tree, py_tree)
unknown = []
for action in diff:
if isinstance(action, xmldiff.actions.UpdateAttrib):
node = orig_tree.xpath(action.node)[0]
if node.tag[-3:] == "svg" and action.name == "viewBox":
# The viewBox format differs, both are legal notations (space vs. comma-separated)
if re.sub(r"\s+", ",", node.attrib[action.name]) == action.value:
continue
elif re.sub(r"\s+", "", node.attrib[action.name]) == re.sub(r"\s+", "", action.value):
# Whitespace differences are okay
continue
else:
py = action.value
js = node.attrib[action.name]
if action.name in ["transform", "d", "x"]:
# Floating point and int differences
pattern_float = re.compile(r'(?<![\d.])([0-9]+)(?![\d.])')
pattern_comma = re.compile(r'\s*,\s*')
py = pattern_float.sub(r'\1.0', py)
js = pattern_float.sub(r'\1.0', js)
py = pattern_comma.sub(r',', py)
js = pattern_comma.sub(r',', js)
if py == js:
continue
# Python >3.5, remove once we are over 2.7..
# action = UpdateAttribx(**{ **action._asdict(), "old": node.attrib[action.name]})
action_dict = action._asdict()
action_dict["old"] = node.attrib[action.name]
action = UpdateAttribx(**action_dict)
elif isinstance(action, xmldiff.actions.InsertAttrib):
node = orig_tree.xpath(action.node)[0]
if node.tag[-3:] == "svg" and action.name in ["baseProfile", "version"]:
# svgwrite adds more info to the svg element
continue
elif isinstance(action, xmldiff.actions.MoveNode):
node = orig_tree.xpath(action.node)[0]
node.getparent().remove(node)
target = orig_tree.xpath(action.target)[0]
target.insert(action.position, node)
if node.tag.endswith("}style"):
# This is okay
continue
action_dict = action._asdict()
action_dict["nodex"] = etree.tostring(node)
action_dict["targetx"] = etree.tostring(target)
action = MoveNodex(**action_dict)
elif isinstance(action, xmldiff.actions.UpdateTextIn):
node = orig_tree.xpath(action.node)[0]
if action.text is None:
if node.tag[-2:] == "}g" and node.attrib["id"] == "groups_0":
# Upstream bug, reported: https://github.com/wavedrom/wavedrom/issues/251
continue
elif node.text is None:
pass
elif re.sub(r"\s+", "", node.text) == re.sub(r"\s+", "", action.text):
# Whitespace differences are okay
continue
action = action._replace(node=etree.tostring(node))
elif isinstance(action, xmldiff.actions.InsertNode):
# Not okay, but we must do the same to preserve the valid tree for further checks
target = orig_tree.xpath(action.target)[0]
node = target.makeelement(action.tag)
target.insert(action.position, node)
action = action._replace(target=etree.tostring(orig_tree.xpath(action.target)[0]))
elif isinstance(action, xmldiff.actions.DeleteNode):
node = orig_tree.xpath(action.node)[0]
node.getparent().remove(node)
action = action._replace(node=etree.tostring(node))
unknown.append(action)
return unknown
def diff_raster(f_out_js, f_out_py):
with open(f_out_js, encoding="utf-8") as fileObj_svg_js:
svg_js = fileObj_svg_js.read()
with open(f_out_py, encoding="utf-8") as fileObj_svg_py:
svg_py = fileObj_svg_py.read()
png_js = cairosvg.svg2png(svg_js)
png_py = cairosvg.svg2png(svg_py)
image_js = Image.open(io.BytesIO(png_js))
image_py = Image.open(io.BytesIO(png_py))
return ImageChops.difference(image_js, image_py)