From scoder at codespeak.net Tue Aug 1 07:42:36 2006
From: scoder at codespeak.net (scoder at codespeak.net)
Date: Tue, 1 Aug 2006 07:42:36 +0200 (CEST)
Subject: [Lxml-checkins] r30827 - in lxml/trunk/src/lxml: . tests
Message-ID: <20060801054236.088C410076@code0.codespeak.net>
Author: scoder
Date: Tue Aug 1 07:42:34 2006
New Revision: 30827
Modified:
lxml/trunk/src/lxml/etree.pyx
lxml/trunk/src/lxml/tests/test_elementtree.py
Log:
make copy/deepcopy work for ElementTree objects
Modified: lxml/trunk/src/lxml/etree.pyx
==============================================================================
--- lxml/trunk/src/lxml/etree.pyx (original)
+++ lxml/trunk/src/lxml/etree.pyx Tue Aug 1 07:42:34 2006
@@ -395,6 +395,15 @@
"""
return self._context_node
+ def __copy__(self):
+ return ElementTree(self._context_node)
+
+ def __deepcopy__(self, memo):
+ if self._context_node is None:
+ return ElementTree()
+ else:
+ return ElementTree( self._context_node.__copy__() )
+
property docinfo:
"""Information about the document provided by parser and DTD. This
value is only defined for ElementTree objects based on the root node
Modified: lxml/trunk/src/lxml/tests/test_elementtree.py
==============================================================================
--- lxml/trunk/src/lxml/tests/test_elementtree.py (original)
+++ lxml/trunk/src/lxml/tests/test_elementtree.py Tue Aug 1 07:42:34 2006
@@ -2106,6 +2106,20 @@
el = self.etree.parse(StringIO(isoxml)).getroot()
self.assertEquals(utext, el.text)
+ def test_deepcopy_elementtree(self):
+ Element = self.etree.Element
+ ElementTree = self.etree.ElementTree
+
+ a = Element('a')
+ a.text = "Foo"
+ atree = ElementTree(a)
+
+ btree = copy.deepcopy(atree)
+ self.assertEqual("Foo", atree.getroot().text)
+ self.assertEqual("Foo", btree.getroot().text)
+ self.assertFalse(btree is atree)
+ self.assertFalse(btree.getroot() is atree.getroot())
+
def test_deepcopy(self):
Element = self.etree.Element
@@ -2172,6 +2186,21 @@
self.assertEquals(
root[0][0].get('{tns}foo'),
copy.deepcopy(root[0][0]).get('{tns}foo') )
+
+ def test_deepcopy_append(self):
+ # previously caused a crash
+ Element = self.etree.Element
+ tostring = self.etree.tostring
+
+ a = Element('a')
+ b = copy.deepcopy(a)
+ a.append( Element('C') )
+ b.append( Element('X') )
+
+ self.assertEquals('',
+ tostring(a).replace(' ', ''))
+ self.assertEquals('',
+ tostring(b).replace(' ', ''))
def test_shallowcopy(self):
Element = self.etree.Element
@@ -2186,21 +2215,19 @@
self.assertEquals('Bar', b.text)
self.assertEquals('Foo', a.text)
# XXX ElementTree will share nodes, but lxml.etree won't..
-
- def test_deepcopy_append(self):
- # previously caused a crash
+
+ def test_shallowcopy_elementtree(self):
Element = self.etree.Element
- tostring = self.etree.tostring
+ ElementTree = self.etree.ElementTree
a = Element('a')
- b = copy.deepcopy(a)
- a.append( Element('C') )
- b.append( Element('X') )
+ a.text = 'Foo'
+ atree = ElementTree(a)
- self.assertEquals('',
- tostring(a).replace(' ', ''))
- self.assertEquals('',
- tostring(b).replace(' ', ''))
+ btree = copy.copy(atree)
+ self.assertFalse(btree is atree)
+ self.assert_(btree.getroot() is atree.getroot())
+ self.assertEquals('Foo', atree.getroot().text)
def test_element_boolean(self):
etree = self.etree
From scoder at codespeak.net Tue Aug 1 07:43:38 2006
From: scoder at codespeak.net (scoder at codespeak.net)
Date: Tue, 1 Aug 2006 07:43:38 +0200 (CEST)
Subject: [Lxml-checkins] r30828 - lxml/trunk
Message-ID: <20060801054338.CD31410076@code0.codespeak.net>
Author: scoder
Date: Tue Aug 1 07:43:36 2006
New Revision: 30828
Modified:
lxml/trunk/CHANGES.txt
Log:
mark ET copy/deepcopy bug fixed
Modified: lxml/trunk/CHANGES.txt
==============================================================================
--- lxml/trunk/CHANGES.txt (original)
+++ lxml/trunk/CHANGES.txt Tue Aug 1 07:43:36 2006
@@ -13,6 +13,8 @@
Bugs fixed
----------
+* Copying/deepcopying did not work for ElementTree objects
+
* The EXSLT ``regexp:match`` function now works as defined (except for some
differences in the regular expression syntax)
From scoder at codespeak.net Tue Aug 1 07:44:55 2006
From: scoder at codespeak.net (scoder at codespeak.net)
Date: Tue, 1 Aug 2006 07:44:55 +0200 (CEST)
Subject: [Lxml-checkins] r30829 - in lxml/branch/lxml-1.0: . src/lxml
src/lxml/tests
Message-ID: <20060801054455.556E410076@code0.codespeak.net>
Author: scoder
Date: Tue Aug 1 07:44:51 2006
New Revision: 30829
Modified:
lxml/branch/lxml-1.0/CHANGES.txt
lxml/branch/lxml-1.0/src/lxml/etree.pyx
lxml/branch/lxml-1.0/src/lxml/tests/test_elementtree.py
Log:
make copy/deepcopy work for ElementTree objects
Modified: lxml/branch/lxml-1.0/CHANGES.txt
==============================================================================
--- lxml/branch/lxml-1.0/CHANGES.txt (original)
+++ lxml/branch/lxml-1.0/CHANGES.txt Tue Aug 1 07:44:51 2006
@@ -14,6 +14,8 @@
Bugs fixed
----------
+* Copying/deepcopying did not work for ElementTree objects
+
* Setting an attribute to a non-string value did not raise an exception
* Element.remove() deleted the tail text from the removed Element
Modified: lxml/branch/lxml-1.0/src/lxml/etree.pyx
==============================================================================
--- lxml/branch/lxml-1.0/src/lxml/etree.pyx (original)
+++ lxml/branch/lxml-1.0/src/lxml/etree.pyx Tue Aug 1 07:44:51 2006
@@ -377,6 +377,15 @@
"""
return self._context_node
+ def __copy__(self):
+ return ElementTree(self._context_node)
+
+ def __deepcopy__(self, memo):
+ if self._context_node is None:
+ return ElementTree()
+ else:
+ return ElementTree( self._context_node.__copy__() )
+
property docinfo:
"""Information about the document provided by parser and DTD. This
value is only defined for ElementTree objects based on the root node
Modified: lxml/branch/lxml-1.0/src/lxml/tests/test_elementtree.py
==============================================================================
--- lxml/branch/lxml-1.0/src/lxml/tests/test_elementtree.py (original)
+++ lxml/branch/lxml-1.0/src/lxml/tests/test_elementtree.py Tue Aug 1 07:44:51 2006
@@ -1980,6 +1980,20 @@
el = self.etree.parse(StringIO(isoxml)).getroot()
self.assertEquals(utext, el.text)
+ def test_deepcopy_elementtree(self):
+ Element = self.etree.Element
+ ElementTree = self.etree.ElementTree
+
+ a = Element('a')
+ a.text = "Foo"
+ atree = ElementTree(a)
+
+ btree = copy.deepcopy(atree)
+ self.assertEqual("Foo", atree.getroot().text)
+ self.assertEqual("Foo", btree.getroot().text)
+ self.assertFalse(btree is atree)
+ self.assertFalse(btree.getroot() is atree.getroot())
+
def test_deepcopy(self):
Element = self.etree.Element
@@ -2046,6 +2060,21 @@
self.assertEquals(
root[0][0].get('{tns}foo'),
copy.deepcopy(root[0][0]).get('{tns}foo') )
+
+ def test_deepcopy_append(self):
+ # previously caused a crash
+ Element = self.etree.Element
+ tostring = self.etree.tostring
+
+ a = Element('a')
+ b = copy.deepcopy(a)
+ a.append( Element('C') )
+ b.append( Element('X') )
+
+ self.assertEquals('',
+ tostring(a).replace(' ', ''))
+ self.assertEquals('',
+ tostring(b).replace(' ', ''))
def test_shallowcopy(self):
Element = self.etree.Element
@@ -2060,21 +2089,19 @@
self.assertEquals('Bar', b.text)
self.assertEquals('Foo', a.text)
# XXX ElementTree will share nodes, but lxml.etree won't..
-
- def test_deepcopy_append(self):
- # previously caused a crash
+
+ def test_shallowcopy_elementtree(self):
Element = self.etree.Element
- tostring = self.etree.tostring
+ ElementTree = self.etree.ElementTree
a = Element('a')
- b = copy.deepcopy(a)
- a.append( Element('C') )
- b.append( Element('X') )
+ a.text = 'Foo'
+ atree = ElementTree(a)
- self.assertEquals('',
- tostring(a).replace(' ', ''))
- self.assertEquals('',
- tostring(b).replace(' ', ''))
+ btree = copy.copy(atree)
+ self.assertFalse(btree is atree)
+ self.assert_(btree.getroot() is atree.getroot())
+ self.assertEquals('Foo', atree.getroot().text)
def test_element_boolean(self):
etree = self.etree
From scoder at codespeak.net Tue Aug 1 12:49:44 2006
From: scoder at codespeak.net (scoder at codespeak.net)
Date: Tue, 1 Aug 2006 12:49:44 +0200 (CEST)
Subject: [Lxml-checkins] r30835 - in lxml/branch/capi/src/lxml: . tests
Message-ID: <20060801104944.81AF31007A@code0.codespeak.net>
Author: scoder
Date: Tue Aug 1 12:49:43 2006
New Revision: 30835
Modified:
lxml/branch/capi/src/lxml/objectify.pyx
lxml/branch/capi/src/lxml/tests/test_objectify.py
Log:
forgot to rename function calls after renaming function
Modified: lxml/branch/capi/src/lxml/objectify.pyx
==============================================================================
--- lxml/branch/capi/src/lxml/objectify.pyx (original)
+++ lxml/branch/capi/src/lxml/objectify.pyx Tue Aug 1 12:49:43 2006
@@ -80,7 +80,7 @@
PYTYPE_ATTRIBUTE = cetree.namespacedNameFromNsName(
_PYTYPE_NAMESPACE, _PYTYPE_ATTRIBUTE_NAME)
-setPytypeAttribute()
+setPytypeAttributeTag()
# namespace for XML Schema instance
Modified: lxml/branch/capi/src/lxml/tests/test_objectify.py
==============================================================================
--- lxml/branch/capi/src/lxml/tests/test_objectify.py (original)
+++ lxml/branch/capi/src/lxml/tests/test_objectify.py Tue Aug 1 12:49:43 2006
@@ -36,7 +36,7 @@
def tearDown(self):
self.etree.Namespace("otherNs").clear()
- objectify.setPytypeAttribute()
+ objectify.setPytypeAttributeTag()
objectify.unregister()
def test_str(self):
@@ -317,7 +317,7 @@
'''
pytype_ns, pytype_name = objectify.PYTYPE_ATTRIBUTE[1:].split('}')
- objectify.setPytypeAttribute("{TEST}test")
+ objectify.setPytypeAttributeTag("{TEST}test")
root = XML(xml)
objectify.annotate(root)
@@ -327,7 +327,7 @@
attribs = root.xpath("//@py:test", {"py" : "TEST"})
self.assertEquals(7, len(attribs))
- objectify.setPytypeAttribute()
+ objectify.setPytypeAttributeTag()
pytype_ns, pytype_name = objectify.PYTYPE_ATTRIBUTE[1:].split('}')
self.assertNotEqual("test", pytype_ns.lower())
From scoder at codespeak.net Tue Aug 1 13:18:27 2006
From: scoder at codespeak.net (scoder at codespeak.net)
Date: Tue, 1 Aug 2006 13:18:27 +0200 (CEST)
Subject: [Lxml-checkins] r30836 - lxml/branch/capi/src/lxml
Message-ID: <20060801111827.008AD1007D@code0.codespeak.net>
Author: scoder
Date: Tue Aug 1 13:18:26 2006
New Revision: 30836
Modified:
lxml/branch/capi/src/lxml/classlookup.pyx
lxml/branch/capi/src/lxml/etree.pyx
lxml/branch/capi/src/lxml/nsclasses.pxi
Log:
moved ElementDefaultClassLookup and ElementNamespaceClassLookup from lxml.elements.classlookup into lxml.etree to let namespace lookup support fallback mechanisms, some additional restructuring
Modified: lxml/branch/capi/src/lxml/classlookup.pyx
==============================================================================
--- lxml/branch/capi/src/lxml/classlookup.pyx (original)
+++ lxml/branch/capi/src/lxml/classlookup.pyx Tue Aug 1 13:18:26 2006
@@ -17,19 +17,8 @@
# initialize C-API of lxml.etree
cetree.import_etree(etree)
-
-cdef class ElementNamespaceClassLookup(ElementClassLookup):
- """Looks up Element class in the Namespace registry.
- """
- # uses default lookup
-
-
-cdef class ElementDefaultClassLookup(ElementClassLookup):
- """Always returns the default Element class.
- """
- def __init__(self):
- self._lookup_function = cetree.lookupDefaultElementClass
-
+ElementNamespaceClassLookup = etree.ElementNamespaceClassLookup
+ElementDefaultClassLookup = etree.ElementDefaultClassLookup
cdef class AttributeBasedElementClassLookup(FallbackElementClassLookup):
"""Checks an attribute of an Element and looks up the value in a class
@@ -40,7 +29,8 @@
* class mapping (Python dict mapping attribute values to Element classes)
* fallback (optional fallback lookup mechanism)
- A None key in the class mapping will be checked if the attribute is missing.
+ A None key in the class mapping will be checked if the attribute is
+ missing.
"""
cdef object _class_mapping
cdef object _pytag
Modified: lxml/branch/capi/src/lxml/etree.pyx
==============================================================================
--- lxml/branch/capi/src/lxml/etree.pyx (original)
+++ lxml/branch/capi/src/lxml/etree.pyx Tue Aug 1 13:18:26 2006
@@ -1770,10 +1770,36 @@
self.fallback = lookup
self._fallback_function = lookup._lookup_function
- cdef object _callFallback(self, doc, tree.xmlNode* c_node):
+ cdef object _callFallback(self, doc, xmlNode* c_node):
return self._fallback_function(self.fallback, doc, c_node)
-# default: Namespace classes
+cdef class ElementDefaultClassLookup(ElementClassLookup):
+ """Element class lookup scheme that always returns the default Element
+ class.
+ """
+ def __init__(self):
+ self._lookup_function = _lookupDefaultElementClass
+
+cdef object _lookupDefaultElementClass(_state, _Document _doc, xmlNode* c_node):
+ "Trivial class lookup function that always returns the default class."
+ if c_node.type == tree.XML_ELEMENT_NODE:
+ return __DEFAULT_ELEMENT_CLASS
+ elif c_node.type == tree.XML_COMMENT_NODE:
+ return __DEFAULT_COMMENT_CLASS
+ elif c_node.type == tree.XML_PI_NODE:
+ return __DEFAULT_PI_CLASS
+ else:
+ assert 0, "Unknown node type: %s" % c_node.type
+
+cdef class ElementNamespaceClassLookup(FallbackElementClassLookup):
+ """Element class lookup scheme that searches the Element class in the
+ Namespace registry.
+ """
+ def __init__(self, ElementClassLookup fallback=None):
+ FallbackElementClassLookup.__init__(self, fallback)
+ self._lookup_function = _find_nselement_class
+
+# default lookup: Namespace classes
cdef _element_class_lookup_function DEFAULT_ELEMENT_CLASS_LOOKUP
DEFAULT_ELEMENT_CLASS_LOOKUP = _find_nselement_class
@@ -1781,6 +1807,7 @@
LOOKUP_ELEMENT_CLASS = DEFAULT_ELEMENT_CLASS_LOOKUP
cdef object ELEMENT_CLASS_LOOKUP_STATE
+ELEMENT_CLASS_LOOKUP_STATE = None
cdef void _setElementClassLookupFunction(
_element_class_lookup_function function, object state):
@@ -1799,6 +1826,41 @@
_setElementClassLookupFunction(lookup._lookup_function, lookup)
+
+################################################################################
+# Custom Element classes
+
+cdef public class ElementBase(_Element) [ type LxmlElementBaseType,
+ object LxmlElementBase ]:
+ """All custom Element classes must inherit from this one.
+
+ Note that subclasses *must not* override __init__ or __new__ as it is
+ absolutely undefined when these objects will be created or destroyed. All
+ persistent state of elements must be stored in the underlying XML. If you
+ really need to initialize the object after creation, you can implement an
+ ``_init(self)`` method that will be called after object creation.
+ """
+
+def setDefaultElementClass(cls=None):
+ global __DEFAULT_ELEMENT_CLASS
+ if cls is None:
+ __DEFAULT_ELEMENT_CLASS = _Element
+ elif not python.PyType_Check(cls) or not issubclass(cls, ElementBase):
+ raise LxmlRegistryError, \
+ "Registered element classes must be subtypes of ElementBase"
+ else:
+ __DEFAULT_ELEMENT_CLASS = cls
+
+cdef object __DEFAULT_ELEMENT_CLASS
+__DEFAULT_ELEMENT_CLASS = _Element
+
+cdef object __DEFAULT_COMMENT_CLASS
+__DEFAULT_COMMENT_CLASS = _Comment
+
+cdef object __DEFAULT_PI_CLASS
+__DEFAULT_PI_CLASS = _ProcessingInstruction
+
+
################################################################################
# Include submodules
Modified: lxml/branch/capi/src/lxml/nsclasses.pxi
==============================================================================
--- lxml/branch/capi/src/lxml/nsclasses.pxi (original)
+++ lxml/branch/capi/src/lxml/nsclasses.pxi Tue Aug 1 13:18:26 2006
@@ -6,48 +6,6 @@
class NamespaceRegistryError(LxmlRegistryError):
pass
-cdef public class ElementBase(_Element) [ type LxmlElementBaseType,
- object LxmlElementBase ]:
- """All custom Element classes must inherit from this one.
-
- Note that subclasses *must not* override __init__ or __new__ as it is
- absolutely undefined when these objects will be created or destroyed. All
- persistent state of elements must be stored in the underlying XML. If you
- really need to initialize the object after creation, you can implement an
- ``_init(self)`` method that will be called after object creation.
- """
-
-def setDefaultElementClass(cls=None):
- global __DEFAULT_ELEMENT_CLASS
- if cls is None:
- __DEFAULT_ELEMENT_CLASS = _Element
- elif not python.PyType_Check(cls) or not issubclass(cls, ElementBase):
- raise LxmlRegistryError, \
- "Registered element classes must be subtypes of ElementBase"
- else:
- __DEFAULT_ELEMENT_CLASS = cls
-
-cdef object _lookupDefaultElementClass(_state, _doc, xmlNode* c_node):
- "Trivial class lookup function that always returns the default class."
- if c_node.type == tree.XML_ELEMENT_NODE:
- return __DEFAULT_ELEMENT_CLASS
- elif c_node.type == tree.XML_COMMENT_NODE:
- return __DEFAULT_COMMENT_CLASS
- elif c_node.type == tree.XML_PI_NODE:
- return __DEFAULT_PI_CLASS
- else:
- assert 0, "Unknown node type: %s" % c_node.type
-
-
-cdef object __DEFAULT_ELEMENT_CLASS
-__DEFAULT_ELEMENT_CLASS = _Element
-
-cdef object __DEFAULT_COMMENT_CLASS
-__DEFAULT_COMMENT_CLASS = _Comment
-
-cdef object __DEFAULT_PI_CLASS
-__DEFAULT_PI_CLASS = _ProcessingInstruction
-
cdef object __NAMESPACE_REGISTRIES
__NAMESPACE_REGISTRIES = {}
@@ -217,7 +175,9 @@
cdef _NamespaceRegistry registry
cdef char* c_namespace_utf
if c_node.type != tree.XML_ELEMENT_NODE:
- return _lookupDefaultElementClass(state, doc, c_node)
+ if state is None:
+ return _lookupDefaultElementClass(None, doc, c_node)
+ return (state)._callFallback(doc, c_node)
c_namespace_utf = _getNs(c_node)
if c_namespace_utf is not NULL:
dict_result = python.PyDict_GetItemString(
@@ -225,22 +185,22 @@
else:
dict_result = python.PyDict_GetItem(
__NAMESPACE_REGISTRIES, None)
- if dict_result is NULL:
- return __DEFAULT_ELEMENT_CLASS
+ if dict_result is not NULL:
+ registry = <_NamespaceRegistry>dict_result
+ classes = registry._entries
- registry = <_NamespaceRegistry>dict_result
- classes = registry._entries
+ if c_node.name is not NULL:
+ dict_result = python.PyDict_GetItemString(
+ classes, c_node.name)
+ else:
+ dict_result = NULL
- if c_node.name is not NULL:
- dict_result = python.PyDict_GetItemString(
- classes, c_node.name)
- else:
- dict_result = NULL
+ if dict_result is NULL:
+ dict_result = python.PyDict_GetItem(classes, None)
- if dict_result is NULL:
- dict_result = python.PyDict_GetItem(classes, None)
+ if dict_result is not NULL:
+ return