-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathutils.py
More file actions
100 lines (77 loc) · 2.51 KB
/
utils.py
File metadata and controls
100 lines (77 loc) · 2.51 KB
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
from types import SimpleNamespace
class ImmutableDict(dict):
"""
An immutable and hashable dictionary for state management
TODO: Functions are _not_ hashable, but they are allowed
for now. This will cause problems for tree comparison,
but we could probably wrap them in a string representation.
"""
def __setitem__(self, key, value):
raise TypeError("ImmutableDict is immutable")
def __delitem__(self, key):
raise TypeError("ImmutableDict is immutable")
def __hash__(self):
return hash(frozenset(self.items()))
def __eq__(self, other):
return hash(self) == hash(other)
def __repr__(self):
return f"ImmutableDict({super().__repr__()})"
def __str__(self):
return f"ImmutableDict({super().__str__()})"
def __getattribute__(self, name):
if name not in ["keys"] and name in self.keys():
return self[name]
else:
return super().__getattribute__(name)
def map_string(string, dict):
"""
Replace characters in a string according to a mapping dictionary
"""
return "".join(dict.get(c, c) for c in string)
class HTMLBuilder:
"""
Function-chaining HTML builder.
The 'cursed' syntax gets replaced with a chain of HTMLBuilder calls.
"""
def __init__(self):
self._root = None
self._stack = []
@property
def top(self):
if len(self._stack) == 0:
return None
return self._stack[-1]
@property
def root(self):
return self._root
def tag(self, tag_name, *args, **kwargs):
tag = SimpleNamespace()
tag.args = args
tag.kwargs = kwargs
tag.name = tag_name
tag.children = []
if self._root is None:
self._root = tag
if self.top:
tag.parent = self.top
self.top.children.append(tag)
self._stack.append(tag)
return self
def text(self, text):
self.top.kwargs["text"] = text
return self
def param(self, name, func):
self.top.kwargs[name] = func()
return self
def pop(self):
self._stack.pop()
return self
def _to_dict(self, tag):
return {
"tag": tag.name,
"attrib": tag.kwargs,
"text": tag.args[0] if len(tag.args) > 0 else None,
"children": [self._to_dict(c) for c in tag.children]
}
def to_dict(self):
return self._to_dict(self._root)