Skip to content

Commit 73678da

Browse files
author
Paul Prescod
committed
Reference cycle fixes
1 parent 8fcaa92 commit 73678da

File tree

4 files changed

+144
-144
lines changed

4 files changed

+144
-144
lines changed

Lib/xml/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
parser -- Python wrappers for XML parsers (currently only supports Expat).
99
1010
sax -- The Simple API for XML, developed by XML-Dev, led by David
11-
Megginson. This supports the SAX 2 API.
12-
11+
Megginson and ported to Python by Lars Marius Garsholm. This
12+
supports the SAX 2 API.
1313
"""

Lib/xml/dom/minidom.py

Lines changed: 116 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,19 @@ class Node:
2929
DOCUMENT_FRAGMENT_NODE = 11
3030
NOTATION_NODE = 12
3131

32-
allnodes=[]
32+
allnodes={}
33+
_debug=0
34+
_makeParentNodes=1
35+
debug=None
3336

3437
def __init__( self ):
3538
self.childNodes=[]
36-
Node.allnodes.append( repr( id( self ))+repr( self.__class__ ))
39+
if Node._debug:
40+
index=repr( id( self ))+repr( self.__class__ )
41+
Node.allnodes[index]=repr( self.__dict__ )
42+
if Node.debug==None:
43+
Node.debug=open( "debug4.out", "w" )
44+
Node.debug.write( "create %s\n"%index )
3745

3846
def __getattr__( self, key ):
3947
if key[0:2]=="__": raise AttributeError
@@ -72,12 +80,39 @@ def hasChildNodes( self ):
7280
if self.childNodes: return 1
7381
else: return 0
7482

83+
def _get_firstChild( self ):
84+
return self.childNodes[0]
85+
86+
def _get_lastChild( self ):
87+
return self.childNodes[-1]
88+
7589
def insertBefore( self, newChild, refChild):
7690
index=self.childNodes.index( refChild )
7791
self.childNodes.insert( index, newChild )
92+
if self._makeParentNodes:
93+
newChild.parentNode=self
7894

7995
def appendChild( self, node ):
8096
self.childNodes.append( node )
97+
return node
98+
99+
def replaceChild( self, newChild, oldChild ):
100+
index=self.childNodes.index( oldChild )
101+
self.childNodes[index]=oldChild
102+
103+
def removeChild( self, oldChild ):
104+
index=self.childNodes.index( oldChild )
105+
del self.childNodes[index]
106+
107+
def cloneNode( self, deep ):
108+
import new
109+
clone=new.instance( self.__class__, self.__dict__ )
110+
clone.attributes=self.attributes.copy()
111+
if not deep:
112+
clone.childNodes=[]
113+
else:
114+
clone.childNodes=map( lambda x: x.cloneNode, self.childNodes )
115+
return clone
81116

82117
def unlink( self ):
83118
self.parentNode=None
@@ -86,11 +121,14 @@ def unlink( self ):
86121
del self.childNodes[-1] # probably not most efficient!
87122
self.childNodes=None
88123
if self.attributes:
89-
for attr in self.attributes.values():
90-
attr.unlink()
91-
self.attributes=None
92-
index=Node.allnodes.index( repr( id( self ))+repr( self.__class__ ))
93-
del Node.allnodes[index]
124+
for attr in self._attrs.values():
125+
self.removeAttributeNode( attr )
126+
assert not len( self._attrs )
127+
assert not len( self._attrsNS )
128+
if Node._debug:
129+
index=repr( id( self ))+repr( self.__class__ )
130+
self.debug.write( "Deleting: %s\n" % index )
131+
del Node.allnodes[index]
94132

95133
def _write_data( writer, data):
96134
"Writes datachars to writer."
@@ -100,11 +138,6 @@ def _write_data( writer, data):
100138
data=string.replace(data,">",">")
101139
writer.write(data)
102140

103-
def _closeElement( element ):
104-
del element.parentNode
105-
for node in element.elements:
106-
_closeElement( node )
107-
108141
def _getElementsByTagNameHelper( parent, name, rc ):
109142
for node in parent.childNodes:
110143
if node.nodeType==Node.ELEMENT_NODE and\
@@ -123,17 +156,16 @@ def _getElementsByTagNameNSHelper( parent, nsURI, localName, rc ):
123156

124157
class Attr(Node):
125158
nodeType=Node.ATTRIBUTE_NODE
126-
def __init__( self, qName, namespaceURI="", prefix="",
127-
localName=None ):
128-
Node.__init__( self )
129-
assert qName
159+
def __init__( self, qName, namespaceURI="", localName=None,
160+
prefix=None ):
130161
# skip setattr for performance
131-
self.__dict__["nodeName"] = self.__dict__["name"] = qName
132162
self.__dict__["localName"]=localName or qName
133-
self.__dict__["prefix"]=prefix
163+
self.__dict__["nodeName"] = self.__dict__["name"] = qName
134164
self.__dict__["namespaceURI"]=namespaceURI
135-
# nodeValue and value are set elsewhere
165+
self.__dict__["prefix"]=prefix
136166
self.attributes=None
167+
Node.__init__( self )
168+
# nodeValue and value are set elsewhere
137169

138170
def __setattr__( self, name, value ):
139171
if name in ("value", "nodeValue" ):
@@ -142,12 +174,13 @@ def __setattr__( self, name, value ):
142174
self.__dict__[name]=value
143175

144176
class AttributeList:
145-
# the attribute list is a transient interface to the underlying dictionaries
146-
# mutations here will change the underlying element's dictionary
177+
"""the attribute list is a transient interface to the underlying
178+
dictionaries. mutations here will change the underlying element's
179+
dictionary"""
147180
def __init__( self, attrs, attrsNS ):
148-
self.__attrs=attrs
149-
self.__attrsNS=attrs
150-
self.length=len( self.__attrs.keys() )
181+
self._attrs=attrs
182+
self._attrsNS=attrsNS
183+
self.length=len( self._attrs.keys() )
151184

152185
def item( self, index ):
153186
try:
@@ -157,40 +190,46 @@ def item( self, index ):
157190

158191
def items( self ):
159192
return map( lambda node: (node.tagName, node.value),
160-
self.__attrs.values() )
193+
self._attrs.values() )
161194

162195
def itemsNS( self ):
163196
return map( lambda node: ((node.URI, node.localName), node.value),
164-
self.__attrs.values() )
197+
self._attrs.values() )
165198

166199
def keys( self ):
167-
return self.__attrs.keys()
200+
return self._attrs.keys()
168201

169202
def keysNS( self ):
170-
return self.__attrsNS.keys()
203+
return self._attrsNS.keys()
171204

172205
def values( self ):
173-
return self.__attrs.values()
206+
return self._attrs.values()
174207

175208
def __len__( self ):
176209
return self.length
177210

178211
def __cmp__( self, other ):
179-
if self.__attrs is other.__attrs:
212+
if self._attrs is getattr( other, "_attrs", None ):
180213
return 0
181214
else:
182215
return cmp( id( self ), id( other ) )
183216

184217
#FIXME: is it appropriate to return .value?
185218
def __getitem__( self, attname_or_tuple ):
186-
if type( attname_or_tuple ) == type( (1,2) ):
187-
return self.__attrsNS[attname_or_tuple].value
219+
if type( attname_or_tuple ) == type( () ):
220+
return self._attrsNS[attname_or_tuple]
188221
else:
189-
return self.__attrs[attname_or_tuple].value
222+
return self._attrs[attname_or_tuple]
190223

191224
def __setitem__( self, attname ):
192225
raise TypeError, "object does not support item assignment"
193-
226+
227+
def __delitem__( self, attname_or_tuple ):
228+
node=self[attname_or_tuple]
229+
node.unlink()
230+
del self._attrs[node.name]
231+
del self._attrsNS[(node.namespaceURI, node.localName)]
232+
194233
class Element( Node ):
195234
nodeType=Node.ELEMENT_NODE
196235
def __init__( self, tagName, namespaceURI="", prefix="",
@@ -202,18 +241,18 @@ def __init__( self, tagName, namespaceURI="", prefix="",
202241
self.namespaceURI=namespaceURI
203242
self.nodeValue=None
204243

205-
self.__attrs={} # attributes are double-indexed:
206-
self.__attrsNS={}# tagName -> Attribute
244+
self._attrs={} # attributes are double-indexed:
245+
self._attrsNS={}# tagName -> Attribute
207246
# URI,localName -> Attribute
208247
# in the future: consider lazy generation of attribute objects
209248
# this is too tricky for now because of headaches
210249
# with namespaces.
211250

212251
def getAttribute( self, attname ):
213-
return self.__attrs[attname].value
252+
return self._attrs[attname].value
214253

215254
def getAttributeNS( self, namespaceURI, localName ):
216-
return self.__attrsNS[(namespaceURI, localName)].value
255+
return self._attrsNS[(namespaceURI, localName)].value
217256

218257
def setAttribute( self, attname, value ):
219258
attr=Attr( attname )
@@ -222,26 +261,37 @@ def setAttribute( self, attname, value ):
222261
self.setAttributeNode( attr )
223262

224263
def setAttributeNS( self, namespaceURI, qualifiedName, value ):
225-
attr=createAttributeNS( namespaceURI, qualifiedName )
264+
prefix,localname=_nssplit( qualifiedName )
226265
# for performance
266+
attr = Attr( qualifiedName, namespaceURI, localname, prefix )
227267
attr.__dict__["value"]=attr.__dict__["nodeValue"]=value
228268
self.setAttributeNode( attr )
229269

270+
def getAttributeNode( self, attrname ):
271+
return self._attrs.get( attrname )
272+
273+
def getAttributeNodeNS( self, namespaceURI, localName ):
274+
return self._attrsNS[(namespaceURI, localName)]
275+
230276
def setAttributeNode( self, attr ):
231-
self.__attrs[attr.name]=attr
232-
self.__attrsNS[(attr.namespaceURI,attr.localName)]=attr
277+
old=self._attrs.get( attr.name, None)
278+
if old:
279+
old.unlink()
280+
self._attrs[attr.name]=attr
281+
self._attrsNS[(attr.namespaceURI,attr.localName)]=attr
233282

234283
def removeAttribute( self, name ):
235-
attr = self.__attrs[name]
284+
attr = self._attrs[name]
236285
self.removeAttributeNode( attr )
237286

238287
def removeAttributeNS( self, namespaceURI, localName ):
239-
attr = self.__attrsNS[(uri, localName)]
288+
attr = self._attrsNS[(namespaceURI, localName)]
240289
self.removeAttributeNode( attr )
241290

242291
def removeAttributeNode( self, node ):
243-
del self.__attrs[node.name]
244-
del self.__attrsNS[(node.namespaceURI, node.localName)]
292+
node.unlink()
293+
del self._attrs[node.name]
294+
del self._attrsNS[(node.namespaceURI, node.localName)]
245295

246296
def getElementsByTagName( self, name ):
247297
return _getElementsByTagNameHelper( self, name, [] )
@@ -271,7 +321,7 @@ def writexml(self, writer):
271321
writer.write("/>")
272322

273323
def _get_attributes( self ):
274-
return AttributeList( self.__attrs, self.__attrsNS )
324+
return AttributeList( self._attrs, self._attrsNS )
275325

276326
class Comment( Node ):
277327
nodeType=Node.COMMENT_NODE
@@ -313,15 +363,30 @@ def __repr__(self):
313363
def writexml( self, writer ):
314364
_write_data( writer, self.data )
315365

366+
def _nssplit( qualifiedName ):
367+
fields = string.split(qualifiedName, ':')
368+
if len(fields) == 2:
369+
return fields
370+
elif len(fields) == 1:
371+
return( '', fields[0] )
372+
316373
class Document( Node ):
317374
nodeType=Node.DOCUMENT_NODE
375+
documentElement=None
318376
def __init__( self ):
319377
Node.__init__( self )
320-
self.documentElement=None
321378
self.attributes=None
322379
self.nodeName="#document"
323380
self.nodeValue=None
324381

382+
def appendChild( self, node ):
383+
if node.nodeType==Node.ELEMENT_NODE and self.documentElement:
384+
raise TypeError, "Two document elements disallowed"
385+
else:
386+
self.documentElement=node
387+
Node.appendChild( self, node )
388+
return node
389+
325390
createElement=Element
326391

327392
createTextNode=Text
@@ -333,32 +398,16 @@ def __init__( self ):
333398
createAttribute=Attr
334399

335400
def createElementNS(self, namespaceURI, qualifiedName):
336-
fields = string.split(qualifiedName, ':')
337-
if len(fields) == 2:
338-
prefix = fields[0]
339-
localName = fields[1]
340-
elif len(fields) == 1:
341-
prefix = ''
342-
localName = fields[0]
343-
return Element(self, qualifiedName, namespaceURI, prefix, localName)
401+
prefix,localName=_nssplit( qualifiedName )
402+
return Element(qualifiedName, namespaceURI, prefix, localName)
344403

345404
def createAttributeNS(self, namespaceURI, qualifiedName):
346-
fields = string.split(qualifiedName,':')
347-
if len(fields) == 2:
348-
localName = fields[1]
349-
prefix = fields[0]
350-
elif len(fields) == 1:
351-
localName = fields[0]
352-
prefix = None
353-
return Attr(qualifiedName, namespaceURI, prefix, localName)
405+
prefix,localName=_nssplit( qualifiedName )
406+
return Attr(namespaceURI, qualifiedName, localName, prefix)
354407

355408
def getElementsByTagNameNS(self,namespaceURI,localName):
356409
_getElementsByTagNameNSHelper( self, namespaceURI, localName )
357410

358-
def close( self ):
359-
for node in self.elements:
360-
_closeElement( node )
361-
362411
def unlink( self ):
363412
self.documentElement=None
364413
Node.unlink( self )

0 commit comments

Comments
 (0)