📄 pymeldlite.py
字号:
return raise KeyError, "No element named %r" % name def __iadd__(self, other): """`object1 += object2` appends a string or a clone of a Meld to the end of another Meld's content. This is used to build things like HTML tables, which are collections of other objects (eg. table rows). See *Real-world example* in the main documentation.""" if self._readonly: raise ReadOnlyError, READ_ONLY_MESSAGE if isinstance(other, Meld): nodes = [other._tree.getElementNode().clone()] else: nodes = self._nodeListFromSource(other) self._tree.children.extend(nodes) return self def __mod__(self, values): """`object % value`, `object % sequence`, or `object % dictionary` all mimic the `%` operator for strings: >>> xml = '<x><y id="greeting">Hello</y> <z id="who">World</z></x>' >>> x = Meld(xml) >>> print x % ("Howdy", "everybody") <x><y id="greeting">Howdy</y> <z id="who">everybody</z></x> >>> print x % {'who': 'all'} <x><y id="greeting">Hello</y> <z id="who">all</z></x> Assignment for sequences happens in the same order that nodes with 'id' attributes appear in the document, not including the top-level node (because if the top-level node were included, you'd only ever be able to assign to that and nothing else): >>> xml = '''<a id="a"> ... <b> <!-- `b` has no ID, hence is ignored. --> ... <c id="c">First one</c> ... <d id="d">Second one</d> ... </b> ... <e id="e">Third one; the content includes 'f': ... <f id="f">Removed when 'e' is assigned to</f> ... </e> ... </a>''' >>> a = Meld(xml) >>> print a % ('One, with a <z id="new">new</z> node', 'Two', 'Three') <a id="a"> <b> <!-- `b` has no ID, hence is ignored. --> <c id="c">One, with a <z id="new">new</z> node</c> <d id="d">Two</d> </b> <e id="e">Three</e> </a> Giving the wrong number of elements to `%` raises the same exceptions as the builtin string `%` operator. Unlike the builtin `%` operator, dictionaries don't need to specify all the keys: >>> print x % "Howdy" Traceback (most recent call last): ... TypeError: not enough arguments >>> print x % ("Howdy", "everybody", "everywhere") Traceback (most recent call last): ... TypeError: not all arguments converted >>> print x % {"greeting": "Howdy"} <x><y id="greeting">Howdy</y> <z id="who">World</z></x> """ # Figure out whether we have a dictionary, a sequence, or a lone value. returnObject = self.clone() if hasattr(values, 'values') and callable(values.values): # It's a dictionary. keys = values.keys() sequence = values.values() elif hasattr(values, '__getitem__') and \ not isinstance(values, str): # It's a sequence. keys = None sequence = list(values) else: # Assume it's a plain value. keys = None sequence = [values] # If we've derived a set of keys, just assign the values. if keys: for key, value in zip(keys, sequence): node = returnObject._findByID(returnObject._tree, key) if node: returnObject._replaceNodeContent(node, value) else: # No keys, so set the values in the order they appear. This is # a depth-first in-order search, pruned wherever we find a match # (otherwise we'd start assigning into places we'd just # assigned). We reverse the sequences so we can use pop(). stack = returnObject._tree.getElementNode().children[:] stack.reverse() sequence.reverse() while stack and sequence: element = stack.pop() if element.attributes.has_key('id'): self._replaceNodeContent(element, sequence.pop()) else: for index in range(len(element.children)): stack.append(element.children[-1 - index]) if sequence: raise TypeError, "not all arguments converted" while stack: if stack.pop().attributes.has_key('id'): raise TypeError, "not enough arguments" return returnObject def __add__(self, other): """`object1 + object2` turns both objects into strings and returns the concatenation of the strings: >>> a = Meld('<html><span id="x">1</span></html>') >>> b = Meld('<html><span id="y">2</span></html>') >>> c = Meld('<html><span id="z">3</span></html>') >>> print a + b <html><span id="x">1</span></html><html><span id="y">2</span></html> >>> print a.x + b.y + c.z <span id="x">1</span><span id="y">2</span><span id="z">3</span> """ if isinstance(other, Meld): other = other._tree.toText() return self._tree.toText() + other def __radd__(self, other): """See `__add__`""" # The case where `other` is a Meld can never happen, because # __add__ will be called instead. return other + self._tree.toText() def __str__(self): """Returns the XML that this `Meld` represents. Don't call this directly - instead convert a `Meld` to a string using `str(object)`. `print` does this automatically, which is why none of the examples calls `str`.""" return str(self._tree.toText())############################################################################### Self-test code.### Extra tests, for features that aren't tested by the (visible) docstrings:__test__ = {'_Node': _Node,'_RootNode': _RootNode,'_ElementNode': _ElementNode,'_TextNode': _TextNode,'_TreeGenerator': _TreeGenerator,'_generateTree': _generateTree,'<?xml>': """>>> print Meld('''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>... <html>Stuff</html>''')<?xml version="1.0" encoding="UTF-8" standalone="yes"?><html>Stuff</html>""",'DOCTYPE (system)': """>>> print Meld('''<!DOCTYPE NAME SYSTEM "name.dtd">... <name>Stuff</name>''')<!DOCTYPE name SYSTEM "name.dtd"><name>Stuff</name>""",'DOCTYPE (small)': """>>> print Meld('''<!DOCTYPE name PUBLIC "-//ORG//NAME//EN" "name.dtd">... <name>Stuff</name>''')<!DOCTYPE name PUBLIC "-//ORG//NAME//EN" "name.dtd"><name>Stuff</name>""",'DOCTYPE (full)': """>>> print Meld('''<!DOCTYPE name [... <!ELEMENT terms (hhItem1, hhItem2)>... <!ELEMENT hhItem1 (#PCDATA)>... <!ELEMENT hhItem2 (#PCDATA)>... ]>... <name>Stuff</name>''')<!DOCTYPE name [ <!ELEMENT terms (hhItem1, hhItem2)> <!ELEMENT hhItem1 (#PCDATA)> <!ELEMENT hhItem2 (#PCDATA)>]><name>Stuff</name>""",'DOCTYPE (HTML hackery)': """>>> html = '''<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">... <html>Stuff</html>'''>>> print Meld(html)<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html>Stuff</html>""",'XML proc': """>>> print Meld('''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>... <?codewarrior exportversion="1.0.1" ideversion="4.2" ?>... <!DOCTYPE PROJECT [... <!ELEMENT PROJECT (TARGETLIST, TARGETORDER, GROUPLIST, DESIGNLIST?)>... ]>... <PROJECT>Stuff</PROJECT>''')<?xml version="1.0" encoding="UTF-8" standalone="yes"?><?codewarrior exportversion="1.0.1" ideversion="4.2" ?><!DOCTYPE PROJECT [<!ELEMENT PROJECT (TARGETLIST, TARGETORDER, GROUPLIST, DESIGNLIST?)>]><PROJECT>Stuff</PROJECT>""",'comment': """>>> page = Meld('''<x><!-- Comment --></x>''')>>> print page<x><!-- Comment --></x>""",'entities and charrefs': """>>> page = Meld('''<html><body>• This "and that"...... <span id="s" title=""Quoted" & Not">x</span></body></html>''')>>> print page.s.title"Quoted" & Not>>> page.s.title = page.s.title + " <>">>> print page.s.title"Quoted" & Not <>>>> print page.s<span id="s" title=""Quoted" & Not <>">x</span>""",'self-closing tags': """>>> page = Meld('''<span id="spam">Stuff</span>''')>>> page.spam = "">>> print page<span id="spam"/>>>> page = Meld('''<textarea name="spam"/>''') # nonSelfClose special case>>> print page<textarea name="spam"></textarea>""",'assigning to _content': """>>> page = Meld('''<html><span id="s">Old</span></html>''')>>> page.s._content = "New">>> print page<html><span id="s">New</span></html>>>> page._content = "All new">>> print page<html>All new</html>""",'deleting _content': """>>> page = Meld('''<html><span id="s">Old</span></html>''')>>> del page.s._content>>> print page<html><span id="s"/></html>""",'constructing from an unknown type': """>>> page = Meld(1)Traceback (most recent call last):...TypeError: Melds must be constructed from ASCII strings""",'accessing a non-existent attribute': """>>> page = Meld('<html></html>')>>> print page.spamTraceback (most recent call last):...AttributeError: No element or attribute named 'spam'>>> del page.spamTraceback (most recent call last):...AttributeError: No element or attribute named 'spam'""",'cdata': """>>> html = '''<html><script id="cdataExample">//<![CDATA[... window.alert("This is not valid XML: <spam> << & >> etc.");... //]]>... </script></html>'''>>> page = Meld(html)>>> print page.cdataExample<script id="cdataExample">//<![CDATA[window.alert("This is not valid XML: <spam> << & >> etc.");//]]></script>""",'add new things':""">>> page = Meld('''<html><textarea id="empty"></textarea></html>''')>>> page.empty = "Not any more">>> page.empty.cols = 60>>> print page<html><textarea cols="60" id="empty">Not any more</textarea></html>""",'readonly': """>>> page = Meld('''<html><span id='no'>No!</span></html>''', readonly=True)>>> page.no = "Yes?"Traceback (most recent call last):...ReadOnlyError: You can't modify this read-only Meld object>>> page.no.attribute = "Yes?"Traceback (most recent call last):...ReadOnlyError: You can't modify this read-only Meld object>>> page.no += "More?"Traceback (most recent call last):...ReadOnlyError: You can't modify this read-only Meld object>>> del page.noTraceback (most recent call last):...ReadOnlyError: You can't modify this read-only Meld object""",'copy from one to another': """>>> a = Meld('<html><span id="one">One</span></html>')>>> b = Meld('<html><span id="two">Two</span></html>')>>> a.one = b.two>>> print a<html><span id="one"><span id="two">Two</span></span></html>>>> b.two = "New">>> print a # Checking for side-effects<html><span id="one"><span id="two">Two</span></span></html>""",'mixed-type add, radd and iadd': """>>> a = Meld('<html><span id="one">1</span></html>')>>> print a.one + "x"<span id="one">1</span>x>>> print "x" + a.onex<span id="one">1</span>>>> a.one += "y<z></z>">>> print a<html><span id="one">1y<z/></span></html>""",'no unicode': r""">>> u = Meld(u'<html><span id="one">One</span></html>')Traceback (most recent call last):...TypeError: Melds must be constructed from ASCII strings""",'private attributes': """>>> page = Meld('<html>x</html>')>>> page._private = "Spam">>> print repr(page._private)'Spam'>>> print page<html>x</html>>>> del page._private>>> print repr(page._private)Traceback (most recent call last):...AttributeError: _private>>> del page._privateTraceback (most recent call last):...AttributeError: _private>>> print page<html>x</html>""",'bad XML characters': """>>> page = Meld('''<x>... Valentines Day Special \x96 2 bikinis for the price of one \x01... </x>''') # No exception.>>> print page<x>Valentines Day Special – 2 bikinis for the price of one ?</x>"""}# Entrian.Coverage: Pragma Stopdef test(): """Tests the `PyMeldLite` module, performing code coverage analysis if `Entrian.Coverage` is available. Returns `(failed, total)`, a la `doctest.testmod`.""" import doctest try: from Entrian import Coverage Coverage.start('PyMeldLite') except ImportError: Coverage = False import PyMeldLite result = doctest.testmod(PyMeldLite) if Coverage: analysis = Coverage.getAnalysis() analysis.printAnalysis() return resultif __name__ == '__main__': failed, total = test() if failed == 0: # Else `doctest.testmod` prints the failures. print "All %d tests passed." % total
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -