diff options
author | Shubham Saini <shubham6405@gmail.com> | 2018-12-11 10:01:23 +0000 |
---|---|---|
committer | Shubham Saini <shubham6405@gmail.com> | 2018-12-11 10:01:23 +0000 |
commit | 68df54d6629ec019142eb149dd037774f2d11e7c (patch) | |
tree | 345bc22d46b4e01a4ba8303b94278952a4ed2b9e /venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/html5lib/treebuilders/base.py |
First commit
Diffstat (limited to 'venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/html5lib/treebuilders/base.py')
-rw-r--r-- | venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/html5lib/treebuilders/base.py | 417 |
1 files changed, 417 insertions, 0 deletions
diff --git a/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/html5lib/treebuilders/base.py b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/html5lib/treebuilders/base.py new file mode 100644 index 0000000..ed32fcb --- /dev/null +++ b/venv/lib/python3.7/site-packages/pip-10.0.1-py3.7.egg/pip/_vendor/html5lib/treebuilders/base.py | |||
@@ -0,0 +1,417 @@ | |||
1 | from __future__ import absolute_import, division, unicode_literals | ||
2 | from pip._vendor.six import text_type | ||
3 | |||
4 | from ..constants import scopingElements, tableInsertModeElements, namespaces | ||
5 | |||
6 | # The scope markers are inserted when entering object elements, | ||
7 | # marquees, table cells, and table captions, and are used to prevent formatting | ||
8 | # from "leaking" into tables, object elements, and marquees. | ||
9 | Marker = None | ||
10 | |||
11 | listElementsMap = { | ||
12 | None: (frozenset(scopingElements), False), | ||
13 | "button": (frozenset(scopingElements | set([(namespaces["html"], "button")])), False), | ||
14 | "list": (frozenset(scopingElements | set([(namespaces["html"], "ol"), | ||
15 | (namespaces["html"], "ul")])), False), | ||
16 | "table": (frozenset([(namespaces["html"], "html"), | ||
17 | (namespaces["html"], "table")]), False), | ||
18 | "select": (frozenset([(namespaces["html"], "optgroup"), | ||
19 | (namespaces["html"], "option")]), True) | ||
20 | } | ||
21 | |||
22 | |||
23 | class Node(object): | ||
24 | """Represents an item in the tree""" | ||
25 | def __init__(self, name): | ||
26 | """Creates a Node | ||
27 | |||
28 | :arg name: The tag name associated with the node | ||
29 | |||
30 | """ | ||
31 | # The tag name assocaited with the node | ||
32 | self.name = name | ||
33 | # The parent of the current node (or None for the document node) | ||
34 | self.parent = None | ||
35 | # The value of the current node (applies to text nodes and comments) | ||
36 | self.value = None | ||
37 | # A dict holding name -> value pairs for attributes of the node | ||
38 | self.attributes = {} | ||
39 | # A list of child nodes of the current node. This must include all | ||
40 | # elements but not necessarily other node types. | ||
41 | self.childNodes = [] | ||
42 | # A list of miscellaneous flags that can be set on the node. | ||
43 | self._flags = [] | ||
44 | |||
45 | def __str__(self): | ||
46 | attributesStr = " ".join(["%s=\"%s\"" % (name, value) | ||
47 | for name, value in | ||
48 | self.attributes.items()]) | ||
49 | if attributesStr: | ||
50 | return "<%s %s>" % (self.name, attributesStr) | ||
51 | else: | ||
52 | return "<%s>" % (self.name) | ||
53 | |||
54 | def __repr__(self): | ||
55 | return "<%s>" % (self.name) | ||
56 | |||
57 | def appendChild(self, node): | ||
58 | """Insert node as a child of the current node | ||
59 | |||
60 | :arg node: the node to insert | ||
61 | |||
62 | """ | ||
63 | raise NotImplementedError | ||
64 | |||
65 | def insertText(self, data, insertBefore=None): | ||
66 | """Insert data as text in the current node, positioned before the | ||
67 | start of node insertBefore or to the end of the node's text. | ||
68 | |||
69 | :arg data: the data to insert | ||
70 | |||
71 | :arg insertBefore: True if you want to insert the text before the node | ||
72 | and False if you want to insert it after the node | ||
73 | |||
74 | """ | ||
75 | raise NotImplementedError | ||
76 | |||
77 | def insertBefore(self, node, refNode): | ||
78 | """Insert node as a child of the current node, before refNode in the | ||
79 | list of child nodes. Raises ValueError if refNode is not a child of | ||
80 | the current node | ||
81 | |||
82 | :arg node: the node to insert | ||
83 | |||
84 | :arg refNode: the child node to insert the node before | ||
85 | |||
86 | """ | ||
87 | raise NotImplementedError | ||
88 | |||
89 | def removeChild(self, node): | ||
90 | """Remove node from the children of the current node | ||
91 | |||
92 | :arg node: the child node to remove | ||
93 | |||
94 | """ | ||
95 | raise NotImplementedError | ||
96 | |||
97 | def reparentChildren(self, newParent): | ||
98 | """Move all the children of the current node to newParent. | ||
99 | This is needed so that trees that don't store text as nodes move the | ||
100 | text in the correct way | ||
101 | |||
102 | :arg newParent: the node to move all this node's children to | ||
103 | |||
104 | """ | ||
105 | # XXX - should this method be made more general? | ||
106 | for child in self.childNodes: | ||
107 | newParent.appendChild(child) | ||
108 | self.childNodes = [] | ||
109 | |||
110 | def cloneNode(self): | ||
111 | """Return a shallow copy of the current node i.e. a node with the same | ||
112 | name and attributes but with no parent or child nodes | ||
113 | """ | ||
114 | raise NotImplementedError | ||
115 | |||
116 | def hasContent(self): | ||
117 | """Return true if the node has children or text, false otherwise | ||
118 | """ | ||
119 | raise NotImplementedError | ||
120 | |||
121 | |||
122 | class ActiveFormattingElements(list): | ||
123 | def append(self, node): | ||
124 | equalCount = 0 | ||
125 | if node != Marker: | ||
126 | for element in self[::-1]: | ||
127 | if element == Marker: | ||
128 | break | ||
129 | if self.nodesEqual(element, node): | ||
130 | equalCount += 1 | ||
131 | if equalCount == 3: | ||
132 | self.remove(element) | ||
133 | break | ||
134 | list.append(self, node) | ||
135 | |||
136 | def nodesEqual(self, node1, node2): | ||
137 | if not node1.nameTuple == node2.nameTuple: | ||
138 | return False | ||
139 | |||
140 | if not node1.attributes == node2.attributes: | ||
141 | return False | ||
142 | |||
143 | return True | ||
144 | |||
145 | |||
146 | class TreeBuilder(object): | ||
147 | """Base treebuilder implementation | ||
148 | |||
149 | * documentClass - the class to use for the bottommost node of a document | ||
150 | * elementClass - the class to use for HTML Elements | ||
151 | * commentClass - the class to use for comments | ||
152 | * doctypeClass - the class to use for doctypes | ||
153 | |||
154 | """ | ||
155 | # pylint:disable=not-callable | ||
156 | |||
157 | # Document class | ||
158 | documentClass = None | ||
159 | |||
160 | # The class to use for creating a node | ||
161 | elementClass = None | ||
162 | |||
163 | # The class to use for creating comments | ||
164 | commentClass = None | ||
165 | |||
166 | # The class to use for creating doctypes | ||
167 | doctypeClass = None | ||
168 | |||
169 | # Fragment class | ||
170 | fragmentClass = None | ||
171 | |||
172 | def __init__(self, namespaceHTMLElements): | ||
173 | """Create a TreeBuilder | ||
174 | |||
175 | :arg namespaceHTMLElements: whether or not to namespace HTML elements | ||
176 | |||
177 | """ | ||
178 | if namespaceHTMLElements: | ||
179 | self.defaultNamespace = "http://www.w3.org/1999/xhtml" | ||
180 | else: | ||
181 | self.defaultNamespace = None | ||
182 | self.reset() | ||
183 | |||
184 | def reset(self): | ||
185 | self.openElements = [] | ||
186 | self.activeFormattingElements = ActiveFormattingElements() | ||
187 | |||
188 | # XXX - rename these to headElement, formElement | ||
189 | self.headPointer = None | ||
190 | self.formPointer = None | ||
191 | |||
192 | self.insertFromTable = False | ||
193 | |||
194 | self.document = self.documentClass() | ||
195 | |||
196 | def elementInScope(self, target, variant=None): | ||
197 | |||
198 | # If we pass a node in we match that. if we pass a string | ||
199 | # match any node with that name | ||
200 | exactNode = hasattr(target, "nameTuple") | ||
201 | if not exactNode: | ||
202 | if isinstance(target, text_type): | ||
203 | target = (namespaces["html"], target) | ||
204 | assert isinstance(target, tuple) | ||
205 | |||
206 | listElements, invert = listElementsMap[variant] | ||
207 | |||
208 | for node in reversed(self.openElements): | ||
209 | if exactNode and node == target: | ||
210 | return True | ||
211 | elif not exactNode and node.nameTuple == target: | ||
212 | return True | ||
213 | elif (invert ^ (node.nameTuple in listElements)): | ||
214 | return False | ||
215 | |||
216 | assert False # We should never reach this point | ||
217 | |||
218 | def reconstructActiveFormattingElements(self): | ||
219 | # Within this algorithm the order of steps described in the | ||
220 | # specification is not quite the same as the order of steps in the | ||
221 | # code. It should still do the same though. | ||
222 | |||
223 | # Step 1: stop the algorithm when there's nothing to do. | ||
224 | if not self.activeFormattingElements: | ||
225 | return | ||
226 | |||
227 | # Step 2 and step 3: we start with the last element. So i is -1. | ||
228 | i = len(self.activeFormattingElements) - 1 | ||
229 | entry = self.activeFormattingElements[i] | ||
230 | if entry == Marker or entry in self.openElements: | ||
231 | return | ||
232 | |||
233 | # Step 6 | ||
234 | while entry != Marker and entry not in self.openElements: | ||
235 | if i == 0: | ||
236 | # This will be reset to 0 below | ||
237 | i = -1 | ||
238 | break | ||
239 | i -= 1 | ||
240 | # Step 5: let entry be one earlier in the list. | ||
241 | entry = self.activeFormattingElements[i] | ||
242 | |||
243 | while True: | ||
244 | # Step 7 | ||
245 | i += 1 | ||
246 | |||
247 | # Step 8 | ||
248 | entry = self.activeFormattingElements[i] | ||
249 | clone = entry.cloneNode() # Mainly to get a new copy of the attributes | ||
250 | |||
251 | # Step 9 | ||
252 | element = self.insertElement({"type": "StartTag", | ||
253 | "name": clone.name, | ||
254 | "namespace": clone.namespace, | ||
255 | "data": clone.attributes}) | ||
256 | |||
257 | # Step 10 | ||
258 | self.activeFormattingElements[i] = element | ||
259 | |||
260 | # Step 11 | ||
261 | if element == self.activeFormattingElements[-1]: | ||
262 | break | ||
263 | |||
264 | def clearActiveFormattingElements(self): | ||
265 | entry = self.activeFormattingElements.pop() | ||
266 | while self.activeFormattingElements and entry != Marker: | ||
267 | entry = self.activeFormattingElements.pop() | ||
268 | |||
269 | def elementInActiveFormattingElements(self, name): | ||
270 | """Check if an element exists between the end of the active | ||
271 | formatting elements and the last marker. If it does, return it, else | ||
272 | return false""" | ||
273 | |||
274 | for item in self.activeFormattingElements[::-1]: | ||
275 | # Check for Marker first because if it's a Marker it doesn't have a | ||
276 | # name attribute. | ||
277 | if item == Marker: | ||
278 | break | ||
279 | elif item.name == name: | ||
280 | return item | ||
281 | return False | ||
282 | |||
283 | def insertRoot(self, token): | ||
284 | element = self.createElement(token) | ||
285 | self.openElements.append(element) | ||
286 | self.document.appendChild(element) | ||
287 | |||
288 | def insertDoctype(self, token): | ||
289 | name = token["name"] | ||
290 | publicId = token["publicId"] | ||
291 | systemId = token["systemId"] | ||
292 | |||
293 | doctype = self.doctypeClass(name, publicId, systemId) | ||
294 | self.document.appendChild(doctype) | ||
295 | |||
296 | def insertComment(self, token, parent=None): | ||
297 | if parent is None: | ||
298 | parent = self.openElements[-1] | ||
299 | parent.appendChild(self.commentClass(token["data"])) | ||
300 | |||
301 | def createElement(self, token): | ||
302 | """Create an element but don't insert it anywhere""" | ||
303 | name = token["name"] | ||
304 | namespace = token.get("namespace", self.defaultNamespace) | ||
305 | element = self.elementClass(name, namespace) | ||
306 | element.attributes = token["data"] | ||
307 | return element | ||
308 | |||
309 | def _getInsertFromTable(self): | ||
310 | return self._insertFromTable | ||
311 | |||
312 | def _setInsertFromTable(self, value): | ||
313 | """Switch the function used to insert an element from the | ||
314 | normal one to the misnested table one and back again""" | ||
315 | self._insertFromTable = value | ||
316 | if value: | ||
317 | self.insertElement = self.insertElementTable | ||
318 | else: | ||
319 | self.insertElement = self.insertElementNormal | ||
320 | |||
321 | insertFromTable = property(_getInsertFromTable, _setInsertFromTable) | ||
322 | |||
323 | def insertElementNormal(self, token): | ||
324 | name = token["name"] | ||
325 | assert isinstance(name, text_type), "Element %s not unicode" % name | ||
326 | namespace = token.get("namespace", self.defaultNamespace) | ||
327 | element = self.elementClass(name, namespace) | ||
328 | element.attributes = token["data"] | ||
329 | self.openElements[-1].appendChild(element) | ||
330 | self.openElements.append(element) | ||
331 | return element | ||
332 | |||
333 | def insertElementTable(self, token): | ||
334 | """Create an element and insert it into the tree""" | ||
335 | element = self.createElement(token) | ||
336 | if self.openElements[-1].name not in tableInsertModeElements: | ||
337 | return self.insertElementNormal(token) | ||
338 | else: | ||
339 | # We should be in the InTable mode. This means we want to do | ||
340 | # special magic element rearranging | ||
341 | parent, insertBefore = self.getTableMisnestedNodePosition() | ||
342 | if insertBefore is None: | ||
343 | parent.appendChild(element) | ||
344 | else: | ||
345 | parent.insertBefore(element, insertBefore) | ||
346 | self.openElements.append(element) | ||
347 | return element | ||
348 | |||
349 | def insertText(self, data, parent=None): | ||
350 | """Insert text data.""" | ||
351 | if parent is None: | ||
352 | parent = self.openElements[-1] | ||
353 | |||
354 | if (not self.insertFromTable or (self.insertFromTable and | ||
355 | self.openElements[-1].name | ||
356 | not in tableInsertModeElements)): | ||
357 | parent.insertText(data) | ||
358 | else: | ||
359 | # We should be in the InTable mode. This means we want to do | ||
360 | # special magic element rearranging | ||
361 | parent, insertBefore = self.getTableMisnestedNodePosition() | ||
362 | parent.insertText(data, insertBefore) | ||
363 | |||
364 | def getTableMisnestedNodePosition(self): | ||
365 | """Get the foster parent element, and sibling to insert before | ||
366 | (or None) when inserting a misnested table node""" | ||
367 | # The foster parent element is the one which comes before the most | ||
368 | # recently opened table element | ||
369 | # XXX - this is really inelegant | ||
370 | lastTable = None | ||
371 | fosterParent = None | ||
372 | insertBefore = None | ||
373 | for elm in self.openElements[::-1]: | ||
374 | if elm.name == "table": | ||
375 | lastTable = elm | ||
376 | break | ||
377 | if lastTable: | ||
378 | # XXX - we should really check that this parent is actually a | ||
379 | # node here | ||
380 | if lastTable.parent: | ||
381 | fosterParent = lastTable.parent | ||
382 | insertBefore = lastTable | ||
383 | else: | ||
384 | fosterParent = self.openElements[ | ||
385 | self.openElements.index(lastTable) - 1] | ||
386 | else: | ||
387 | fosterParent = self.openElements[0] | ||
388 | return fosterParent, insertBefore | ||
389 | |||
390 | def generateImpliedEndTags(self, exclude=None): | ||
391 | name = self.openElements[-1].name | ||
392 | # XXX td, th and tr are not actually needed | ||
393 | if (name in frozenset(("dd", "dt", "li", "option", "optgroup", "p", "rp", "rt")) and | ||
394 | name != exclude): | ||
395 | self.openElements.pop() | ||
396 | # XXX This is not entirely what the specification says. We should | ||
397 | # investigate it more closely. | ||
398 | self.generateImpliedEndTags(exclude) | ||
399 | |||
400 | def getDocument(self): | ||
401 | """Return the final tree""" | ||
402 | return self.document | ||
403 | |||
404 | def getFragment(self): | ||
405 | """Return the final fragment""" | ||
406 | # assert self.innerHTML | ||
407 | fragment = self.fragmentClass() | ||
408 | self.openElements[0].reparentChildren(fragment) | ||
409 | return fragment | ||
410 | |||
411 | def testSerializer(self, node): | ||
412 | """Serialize the subtree of node in the format required by unit tests | ||
413 | |||
414 | :arg node: the node from which to start serializing | ||
415 | |||
416 | """ | ||
417 | raise NotImplementedError | ||