[Lxml-checkins] r33271 - in lxml/branch/lxml-1.1: . src/lxml

scoder at codespeak.net scoder at codespeak.net
Fri Oct 13 19:18:28 CEST 2006


Author: scoder
Date: Fri Oct 13 19:18:26 2006
New Revision: 33271

Modified:
   lxml/branch/lxml-1.1/CHANGES.txt
   lxml/branch/lxml-1.1/src/lxml/apihelpers.pxi
   lxml/branch/lxml-1.1/src/lxml/etree.pyx
   lxml/branch/lxml-1.1/src/lxml/etreepublic.pxd
   lxml/branch/lxml-1.1/src/lxml/objectify.pyx
   lxml/branch/lxml-1.1/src/lxml/parser.pxi
   lxml/branch/lxml-1.1/src/lxml/proxy.pxi
   lxml/branch/lxml-1.1/src/lxml/public-api.pxi
   lxml/branch/lxml-1.1/src/lxml/xslt.pxi
Log:
merged in fixes from trunk

Modified: lxml/branch/lxml-1.1/CHANGES.txt
==============================================================================
--- lxml/branch/lxml-1.1/CHANGES.txt	(original)
+++ lxml/branch/lxml-1.1/CHANGES.txt	Fri Oct 13 19:18:26 2006
@@ -8,6 +8,9 @@
 Features added
 --------------
 
+* New C-API function makeElement() to create new elements with text,
+  tail, attributes and namespaces
+
 * Reuse original parser flags for XInclude
 
 * Simplified support for handling XSLT processing instructions
@@ -15,6 +18,10 @@
 Bugs fixed
 ----------
 
+* Memory leak for external URLs in _XSLTProcessingInstruction.parseXSL()
+
+* Memory leak when garbage collecting tailed root elements
+
 * HTML script/style content was not propagated to .text
 
 * Show text xincluded between text nodes correctly in .text and .tail

Modified: lxml/branch/lxml-1.1/src/lxml/apihelpers.pxi
==============================================================================
--- lxml/branch/lxml-1.1/src/lxml/apihelpers.pxi	(original)
+++ lxml/branch/lxml-1.1/src/lxml/apihelpers.pxi	Fri Oct 13 19:18:26 2006
@@ -81,8 +81,10 @@
         return None
 
 cdef _Element _makeElement(tag, xmlDoc* c_doc, _Document doc,
-                           _BaseParser parser, attrib, nsmap, extra_attrs):
-    """Create a new element and initialize namespaces and attributes.
+                           _BaseParser parser, text, tail, attrib, nsmap,
+                           extra_attrs):
+    """Create a new element and initialize text content, namespaces and
+    attributes.
 
     This helper function will reuse as much of the existing document as
     possible:
@@ -102,13 +104,52 @@
     elif c_doc is NULL:
         c_doc = _newDoc()
     c_node = _createElement(c_doc, name_utf)
-    if doc is None:
-        tree.xmlDocSetRootElement(c_doc, c_node)
-        doc = _documentFactory(c_doc, parser)
-    # add namespaces to node if necessary
-    doc._setNodeNamespaces(c_node, ns_utf, nsmap)
-    _initNodeAttributes(c_node, doc, attrib, extra_attrs)
-    return _elementFactory(doc, c_node)
+    try:
+        if text is not None:
+            _setNodeText(c_node, text)
+        if tail is not None:
+            _setTailText(c_node, tail)
+        if doc is None:
+            tree.xmlDocSetRootElement(c_doc, c_node)
+            doc = _documentFactory(c_doc, parser)
+        # add namespaces to node if necessary
+        doc._setNodeNamespaces(c_node, ns_utf, nsmap)
+        _initNodeAttributes(c_node, doc, attrib, extra_attrs)
+        return _elementFactory(doc, c_node)
+    except:
+        # free allocated c_node/c_doc unless Python does it for us
+        if c_node.doc is not c_doc:
+            # node not yet in document => will not be freed by document
+            if tail is not None:
+                _removeText(c_node.next) # tail
+            tree.xmlFreeNode(c_node)
+        if doc is None:
+            # c_doc will not be freed by doc
+            tree.xmlFreeDoc(c_doc)
+        raise
+
+cdef _initNodeAttributes(xmlNode* c_node, _Document doc, attrib, extra):
+    """Initialise the attributes of an element node.
+    """
+    cdef xmlNs* c_ns
+    # 'extra' is not checked here (expected to be a keyword dict)
+    if attrib is not None and not hasattr(attrib, 'items'):
+        raise TypeError, "Invalid attribute dictionary: %s" % type(attrib)
+    if extra is not None and extra:
+        if attrib is None:
+            attrib = extra
+        else:
+            attrib.update(extra)
+    if attrib:
+        for name, value in attrib.items():
+            attr_ns_utf, attr_name_utf = _getNsTag(name)
+            value_utf = _utf8(value)
+            if attr_ns_utf is None:
+                tree.xmlNewProp(c_node, _cstr(attr_name_utf), _cstr(value_utf))
+            else:
+                c_ns = doc._findOrBuildNodeNs(c_node, _cstr(attr_ns_utf))
+                tree.xmlNewNsProp(c_node, c_ns,
+                                  _cstr(attr_name_utf), _cstr(value_utf))
 
 cdef object _attributeValue(xmlNode* c_element, xmlAttr* c_attrib_node):
     cdef char* value

Modified: lxml/branch/lxml-1.1/src/lxml/etree.pyx
==============================================================================
--- lxml/branch/lxml-1.1/src/lxml/etree.pyx	(original)
+++ lxml/branch/lxml-1.1/src/lxml/etree.pyx	Fri Oct 13 19:18:26 2006
@@ -1152,7 +1152,8 @@
     def makeelement(self, _tag, attrib=None, nsmap=None, **_extra):
         """Creates a new element associated with the same document.
         """
-        return _makeElement(_tag, NULL, self._doc, None, attrib, nsmap, _extra)
+        return _makeElement(_tag, NULL, self._doc, None, None, None,
+                            attrib, nsmap, _extra)
 
     def find(self, path):
         """Finds the first matching subelement, by tag name or path.
@@ -1564,35 +1565,15 @@
     c_node = tree.xmlNewDocPI(c_doc, target, text)
     return c_node
 
-cdef _initNodeAttributes(xmlNode* c_node, _Document doc, attrib, extra):
-    cdef xmlNs* c_ns
-    # 'extra' is not checked here (expected to be a keyword dict)
-    if attrib is not None and not hasattr(attrib, 'items'):
-        raise TypeError, "Invalid attribute dictionary: %s" % type(attrib)
-    if extra:
-        if attrib is None:
-            attrib = extra
-        else:
-            attrib.update(extra)
-    if attrib:
-        for name, value in attrib.items():
-            attr_ns_utf, attr_name_utf = _getNsTag(name)
-            value_utf = _utf8(value)
-            if attr_ns_utf is None:
-                tree.xmlNewProp(c_node, _cstr(attr_name_utf), _cstr(value_utf))
-            else:
-                c_ns = doc._findOrBuildNodeNs(c_node, _cstr(attr_ns_utf))
-                tree.xmlNewNsProp(c_node, c_ns,
-                                  _cstr(attr_name_utf), _cstr(value_utf))
-
-
 # module-level API for ElementTree
 
 def Element(_tag, attrib=None, nsmap=None, **_extra):
-    """Element factory. This function returns an object implementing the Element interface.
+    """Element factory.  This function returns an object implementing the
+    Element interface.
     """
     ### also look at _Element.makeelement() and _BaseParser.makeelement() ###
-    return _makeElement(_tag, NULL, None, None, attrib, nsmap, _extra)
+    return _makeElement(_tag, NULL, None, None, None, None,
+                        attrib, nsmap, _extra)
 
 def Comment(text=None):
     """Comment element factory. This factory function creates a special element that will

Modified: lxml/branch/lxml-1.1/src/lxml/etreepublic.pxd
==============================================================================
--- lxml/branch/lxml-1.1/src/lxml/etreepublic.pxd	(original)
+++ lxml/branch/lxml-1.1/src/lxml/etreepublic.pxd	Fri Oct 13 19:18:26 2006
@@ -61,7 +61,12 @@
     # create an ElementTree subclass for an Element
     cdef _ElementTree newElementTree(_NodeBase context_node, object subclass)
 
-    # deep copy a node to include in in the Document
+    # create a new Element for an existing or new document (doc = None)
+    # builds Python object after setting text, tail, namespaces and attributes
+    cdef _Element makeElement(tag, _Document doc, parser,
+                              text, tail, attrib, nsmap)
+
+    # deep copy a node to include it in the Document
     cdef _Element deepcopyNodeToDocument(_Document doc, tree.xmlNode* c_root)
 
     # set the internal lookup function for Element/Comment/PI classes

Modified: lxml/branch/lxml-1.1/src/lxml/objectify.pyx
==============================================================================
--- lxml/branch/lxml-1.1/src/lxml/objectify.pyx	(original)
+++ lxml/branch/lxml-1.1/src/lxml/objectify.pyx	Fri Oct 13 19:18:26 2006
@@ -1461,17 +1461,16 @@
 
     Call without arguments to reset to the original parser.
     """
-    global parser, _makeelement
+    global parser
     if new_parser is None:
         parser = __DEFAULT_PARSER
     elif isinstance(new_parser, etree.XMLParser):
         parser = new_parser
     else:
         raise TypeError, "parser must inherit from lxml.etree.XMLParser"
-    _makeelement = parser.makeelement
 
-cdef object _makeelement
-_makeelement = parser.makeelement
+cdef _Element _makeElement(tag, text, attrib, nsmap):
+    return cetree.makeElement(tag, None, parser, text, None, attrib, nsmap)
 
 ################################################################################
 # Module level factory functions
@@ -1501,7 +1500,7 @@
     if _pytype is None:
         _pytype = TREE_PYTYPE
     _attributes[PYTYPE_ATTRIBUTE] = _pytype
-    return _makeelement(_tag, _attributes, nsmap)
+    return _makeElement(_tag, None, _attributes, nsmap)
 
 def DataElement(_value, attrib=None, nsmap=None, _pytype=None, _xsi=None,
                 **_attributes):
@@ -1549,6 +1548,4 @@
     if _pytype is not None:
         python.PyDict_SetItem(_attributes, PYTYPE_ATTRIBUTE, _pytype)
 
-    element = _makeelement("value", _attributes, nsmap)
-    cetree.setNodeText(element._c_node, strval)
-    return element
+    return _makeElement("value", strval, _attributes, nsmap)

Modified: lxml/branch/lxml-1.1/src/lxml/parser.pxi
==============================================================================
--- lxml/branch/lxml-1.1/src/lxml/parser.pxi	(original)
+++ lxml/branch/lxml-1.1/src/lxml/parser.pxi	Fri Oct 13 19:18:26 2006
@@ -420,7 +420,8 @@
     def makeelement(self, _tag, attrib=None, nsmap=None, **_extra):
         """Creates a new element associated with this parser.
         """
-        return _makeElement(_tag, NULL, None, self, attrib, nsmap, _extra)
+        return _makeElement(_tag, NULL, None, self, None, None,
+                            attrib, nsmap, _extra)
 
     cdef xmlDoc* _parseUnicodeDoc(self, utext, char* c_filename) except NULL:
         """Parse unicode document, share dictionary if possible.

Modified: lxml/branch/lxml-1.1/src/lxml/proxy.pxi
==============================================================================
--- lxml/branch/lxml-1.1/src/lxml/proxy.pxi	(original)
+++ lxml/branch/lxml-1.1/src/lxml/proxy.pxi	Fri Oct 13 19:18:26 2006
@@ -104,6 +104,7 @@
     c_top = getDeallocationTop(c_node)
     if c_top is not NULL:
         #print "freeing:", c_top.name
+        _removeText(c_top.next) # tail
         tree.xmlFreeNode(c_top)
 
 cdef xmlNode* getDeallocationTop(xmlNode* c_node):

Modified: lxml/branch/lxml-1.1/src/lxml/public-api.pxi
==============================================================================
--- lxml/branch/lxml-1.1/src/lxml/public-api.pxi	(original)
+++ lxml/branch/lxml-1.1/src/lxml/public-api.pxi	Fri Oct 13 19:18:26 2006
@@ -21,6 +21,10 @@
         raise TypeError
     return _elementFactory(doc, c_node)
 
+cdef public _Element makeElement(tag, _Document doc, parser,
+                                 text, tail, attrib, nsmap):
+    return _makeElement(tag, NULL, doc, parser, text, tail, attrib, nsmap, None)
+
 cdef public void setElementClassLookupFunction(
     _element_class_lookup_function function, state):
     _setElementClassLookupFunction(function, state)

Modified: lxml/branch/lxml-1.1/src/lxml/xslt.pxi
==============================================================================
--- lxml/branch/lxml-1.1/src/lxml/xslt.pxi	(original)
+++ lxml/branch/lxml-1.1/src/lxml/xslt.pxi	Fri Oct 13 19:18:26 2006
@@ -582,9 +582,12 @@
             c_href = tree.xmlBuildURI(
                 c_href,
                 tree.xmlNodeGetBase(self._c_node.doc, self._c_node))
-            if c_href is NULL:
-                c_href = _cstr(href_utf)
-            result_doc = _parseDocument(funicode(c_href), parser)
+            if c_href is not NULL:
+                href = funicode(c_href)
+                tree.xmlFree(c_href)
+            else:
+                href = funicode(_cstr(href_utf))
+            result_doc = _parseDocument(href, parser)
             return _elementTreeFactory(result_doc, None)
 
         # ID reference to embedded stylesheet


More information about the lxml-checkins mailing list