-
Notifications
You must be signed in to change notification settings - Fork 2
/
node.py
103 lines (86 loc) · 2.57 KB
/
node.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
"""
Some basic additions to the lxml element node class.
"""
from lxml import etree
class RefactorLibNodeBase(etree.ElementBase):
@property
def encoding(self):
# My encoding is the encoding of my root, if any
return self.getroottree().docinfo.encoding
def remove_call(self):
raise NotImplementedError('remove_call')
def replace_self(self, other):
parent = self.getparent()
parent.replace(self, other)
def remove_self(self):
parent = self.getparent()
parent.remove(self)
def totext(self, encoding=None, with_tail=True, **kwargs):
if encoding is None:
encoding = self.encoding
return etree.tostring(self, encoding=encoding, method='text', with_tail=with_tail, **kwargs)
def tostring(self, encoding=None, method=None, with_tail=True, **kwargs):
if encoding is None:
encoding = self.encoding
return etree.tostring(self, encoding=encoding, method=method, with_tail=with_tail, **kwargs)
def following_text(self):
"""
Get the first non-empty piece of text after this node.
See also: http://lxml.de/tutorial.html#using-xpath-to-find-text
"""
return one(self.xpath('./following::text()[.!=""][1]'))
def preceding_text(self):
"""
Get the first non-empty piece of text before this node.
See also: http://lxml.de/tutorial.html#using-xpath-to-find-text
"""
return one(self.xpath('./preceding::text()[.!=""][1]'))
def clear_indent(self):
"""
Clear any indent preceding this node.
"""
indent = self.preceding_text()
attr = 'text' if indent.is_text else 'tail'
indent_owner = indent.getparent()
setattr(indent_owner, attr, indent.rstrip(' \t'))
def find_indent_textnode(self):
"""
Find and return the raw text node that includes the indentation for
this node. Other, non-whitespace charcters may be included.
"""
text = self.preceding_text()
while '\n' not in text:
prev = text.getparent().preceding_text()
if prev.endswith('\n'):
break
else:
text = prev
return text
def xpath_one(self, xpath):
return one(self.xpath(xpath))
def __nonzero__(self):
"""
Nodes should always test True.
This is forward-compatible with the newest lxml version.
"""
return True
def one(mylist):
"""
assert that there's only one thing, and get it.
"""
if len(mylist) != 1:
raise ValueError(
'Expected exactly one item. Got %i: %r'
% (
len(mylist),
list(
item.tostring()
if isinstance(item, etree.ElementBase)
else item
for item in mylist
)
)
)
return mylist[0]
node_lookup = etree.ElementDefaultClassLookup(element=RefactorLibNodeBase)
__all__ = ('RefactorLibNodeBase',)