lxml.tests.test_classlookup
1
2
3 """
4 Tests for different Element class lookup mechanisms.
5 """
6
7
8 import unittest , os . path , sys , gc
9
10 this_dir = os . path . dirname ( __file__ )
11 if this_dir not in sys . path :
12 sys . path . insert ( 0 , this_dir )
13
14 from common_imports import etree , HelperTestCase , SillyFileLike , fileInTestDir
15 from common_imports import canonicalize , _bytes , _str , BytesIO , StringIO
16
17 xml_str = _bytes ( '''\
18 <root xmlns="myNS" xmlns:other="otherNS">
19 <c1 a1="A1" a2="A2" other:a3="A3">
20 <c2 a1="C2">0</c2>
21 <c2>1</c2>
22 <other:c2>2</other:c2>
23 </c1>
24 </root>''' )
25
26
28 """Basic tests for element proxy behaviour.
29 """
30 etree = etree
31
36
43
53
55 root = etree . XML ( '<a><b><c/></b></a>' )
56 old_elements = set ( root . iter ( ) )
57 elements = root . iter ( )
58 del root
59 gc . collect ( )
60
61 missing = len ( old_elements )
62 self . assertEqual ( 3 , missing )
63 for new in elements :
64 for old in old_elements :
65 if old == new :
66 self . assertTrue ( old is new )
67 missing -= 1
68 break
69 else :
70 self . assertTrue ( False , "element '%s' is missing" % new . tag )
71 self . assertEqual ( 0 , missing )
72
79
90
98
106
107
133
135 class TestElement ( etree . ElementBase ) :
136 FIND_ME = "default element"
137 class TestComment ( etree . CommentBase ) :
138 FIND_ME = "default comment"
139 class TestPI ( etree . PIBase ) :
140 FIND_ME = "default pi"
141
142 parser = etree . XMLParser ( )
143
144 lookup = etree . ElementDefaultClassLookup (
145 element = TestElement , comment = TestComment , pi = TestPI )
146 parser . set_element_class_lookup ( lookup )
147
148 root = etree . XML ( _bytes ( """<?xml version='1.0'?>
149 <root>
150 <?myPI?>
151 <!-- hi -->
152 </root>
153 """ ) , parser )
154
155 self . assertEqual ( "default element" , root . FIND_ME )
156 self . assertEqual ( "default pi" , root [ 0 ] . FIND_ME )
157 self . assertEqual ( "default comment" , root [ 1 ] . FIND_ME )
158
160 class TestElement ( etree . ElementBase ) :
161 FIND_ME = "default element"
162 class TestComment ( etree . CommentBase ) :
163 FIND_ME = "default comment"
164 class TestPI ( etree . PIBase ) :
165 FIND_ME = "default pi"
166
167 parser = etree . XMLPullParser ( events = ( 'start' , 'end' , 'comment' , 'pi' ) )
168 lookup = etree . ElementDefaultClassLookup (
169 element = TestElement , comment = TestComment , pi = TestPI )
170 parser . set_element_class_lookup ( lookup )
171
172 events_seen = [ ]
173
174 def add_events ( events ) :
175 for ev , el in events :
176 events_seen . append ( ( ev , el . FIND_ME ) )
177
178 parser . feed ( """<?xml version='1.0'?>
179 <root>
180 <?myPI?>
181 """ )
182 add_events ( parser . read_events ( ) )
183
184 parser . feed ( "<!-- hi -->" )
185 add_events ( parser . read_events ( ) )
186
187 parser . feed ( "</root>" )
188 root = parser . close ( )
189 add_events ( parser . read_events ( ) )
190
191 self . assertEqual ( [
192 ( 'start' , "default element" ) ,
193 ( 'pi' , "default pi" ) ,
194 ( 'comment' , "default comment" ) ,
195 ( 'end' , "default element" ) ,
196 ] , events_seen )
197
198 self . assertEqual ( "default element" , root . FIND_ME )
199 self . assertEqual ( "default pi" , root [ 0 ] . FIND_ME )
200 self . assertEqual ( "default comment" , root [ 1 ] . FIND_ME )
201
203 class MyLookup ( etree . CustomElementClassLookup ) :
204 def lookup ( self , t , d , ns , name ) :
205 if name == 'none' :
206 return None
207 elif name == 'obj' :
208 return object ( )
209 else :
210 return etree . ElementBase
211
212 parser = etree . XMLParser ( )
213 parser . set_element_class_lookup ( MyLookup ( ) )
214
215 root = etree . XML ( _bytes ( '<none/>' ) , parser )
216 self . assertEqual ( 'none' , root . tag )
217
218 self . assertRaises (
219 TypeError ,
220 etree . XML , _bytes ( "<obj />" ) , parser )
221
222 root = etree . XML ( _bytes ( '<root/>' ) , parser )
223 self . assertEqual ( 'root' , root . tag )
224
226 class MyLookup ( etree . CustomElementClassLookup ) :
227 def lookup ( self , t , d , ns , name ) :
228 if t == 'element' :
229 if name == 'root' :
230 return etree . ElementBase
231 return etree . CommentBase
232 elif t == 'comment' :
233 return etree . PIBase
234 elif t == 'PI' :
235 return etree . EntityBase
236 elif t == 'entity' :
237 return etree . ElementBase
238 else :
239 raise ValueError ( 'got type %s' % t )
240
241 parser = etree . XMLParser ( resolve_entities = False )
242 parser . set_element_class_lookup ( MyLookup ( ) )
243
244 root = etree . XML ( _bytes ( '<root></root>' ) , parser )
245 self . assertEqual ( 'root' , root . tag )
246 self . assertEqual ( etree . ElementBase , type ( root ) )
247
248 root = etree . XML ( _bytes ( "<root><test/></root>" ) , parser )
249 self . assertRaises ( TypeError , root . __getitem__ , 0 )
250
251 root = etree . XML ( _bytes ( "<root><!-- test --></root>" ) , parser )
252 self . assertRaises ( TypeError , root . __getitem__ , 0 )
253
254 root = etree . XML ( _bytes ( "<root><?test?></root>" ) , parser )
255 self . assertRaises ( TypeError , root . __getitem__ , 0 )
256
257 root = etree . XML (
258 _bytes ( '<!DOCTYPE root [<!ENTITY myent "ent">]>'
259 '<root>&myent;</root>' ) ,
260 parser )
261 self . assertRaises ( TypeError , root . __getitem__ , 0 )
262
263 root = etree . XML ( _bytes ( '<root><root/></root>' ) , parser )
264 self . assertEqual ( 'root' , root [ 0 ] . tag )
265
267 class TestElement ( etree . ElementBase ) :
268 FIND_ME = "attribute_based"
269
270 class_dict = { "A1" : TestElement }
271
272 lookup = etree . AttributeBasedElementClassLookup (
273 "a1" , class_dict )
274 etree . set_element_class_lookup ( lookup )
275
276 root = etree . XML ( xml_str )
277 self . assertFalse ( hasattr ( root , 'FIND_ME' ) )
278 self . assertEqual ( root [ 0 ] . FIND_ME ,
279 TestElement . FIND_ME )
280 self . assertFalse ( hasattr ( root [ 0 ] [ 0 ] , 'FIND_ME' ) )
281
283 class TestElement ( etree . ElementBase ) :
284 FIND_ME = "custom"
285
286 class MyLookup ( etree . CustomElementClassLookup ) :
287 def lookup ( self , t , d , ns , name ) :
288 if name == 'c1' :
289 return TestElement
290
291 etree . set_element_class_lookup ( MyLookup ( ) )
292
293 root = etree . XML ( xml_str )
294 self . assertFalse ( hasattr ( root , 'FIND_ME' ) )
295 self . assertEqual ( root [ 0 ] . FIND_ME ,
296 TestElement . FIND_ME )
297 self . assertFalse ( hasattr ( root [ 0 ] [ 1 ] , 'FIND_ME' ) )
298
300 class TestElement1 ( etree . ElementBase ) :
301 FIND_ME = "custom"
302
303 class TestElement2 ( etree . ElementBase ) :
304 FIND_ME = "nsclasses"
305
306 class MyLookup ( etree . CustomElementClassLookup ) :
307 def lookup ( self , t , d , ns , name ) :
308 if name == 'c1' :
309 return TestElement1
310
311 lookup = etree . ElementNamespaceClassLookup ( MyLookup ( ) )
312 etree . set_element_class_lookup ( lookup )
313
314 ns = lookup . get_namespace ( "otherNS" )
315 ns [ None ] = TestElement2
316
317 root = etree . XML ( xml_str )
318 self . assertFalse ( hasattr ( root , 'FIND_ME' ) )
319 self . assertEqual ( root [ 0 ] . FIND_ME ,
320 TestElement1 . FIND_ME )
321 self . assertFalse ( hasattr ( root [ 0 ] [ 1 ] , 'FIND_ME' ) )
322 self . assertEqual ( root [ 0 ] [ - 1 ] . FIND_ME ,
323 TestElement2 . FIND_ME )
324
326 class TestElement ( etree . ElementBase ) :
327 FIND_ME = "parser_based"
328
329 lookup = etree . ParserBasedElementClassLookup ( )
330 etree . set_element_class_lookup ( lookup )
331
332 class MyLookup ( etree . CustomElementClassLookup ) :
333 def lookup ( self , t , d , ns , name ) :
334 return TestElement
335
336 parser = etree . XMLParser ( )
337 parser . set_element_class_lookup ( MyLookup ( ) )
338
339 root = etree . parse ( BytesIO ( xml_str ) , parser ) . getroot ( )
340 self . assertEqual ( root . FIND_ME ,
341 TestElement . FIND_ME )
342 self . assertEqual ( root [ 0 ] . FIND_ME ,
343 TestElement . FIND_ME )
344
345 root = etree . parse ( BytesIO ( xml_str ) ) . getroot ( )
346 self . assertFalse ( hasattr ( root , 'FIND_ME' ) )
347 self . assertFalse ( hasattr ( root [ 0 ] , 'FIND_ME' ) )
348
350 XML = self . etree . XML
351
352 class TestElement ( etree . ElementBase ) :
353 FIND_ME = "here"
354
355 root = None
356 class MyLookup ( etree . CustomElementClassLookup ) :
357 el = None
358 def lookup ( self , t , d , ns , name ) :
359 if root is not None :
360 if self . el is None and name == "a" :
361 self . el = [ ]
362 self . el . append ( root . find ( name ) )
363 return TestElement
364
365 parser = self . etree . XMLParser ( )
366 parser . set_element_class_lookup ( MyLookup ( ) )
367
368 root = XML ( _bytes ( '<root><a>A</a><b xmlns="test">B</b></root>' ) ,
369 parser )
370
371 a = root [ 0 ]
372 self . assertEqual ( a . tag , "a" )
373 self . assertEqual ( root [ 0 ] . tag , "a" )
374 del a
375 self . assertEqual ( root [ 0 ] . tag , "a" )
376
378 class Lookup ( etree . CustomElementClassLookup ) :
379 def __init__ ( self ) :
380
381 pass
382
383 def lookup ( self , node_type , document , namespace , name ) :
384 return Foo
385
386 class Foo ( etree . ElementBase ) :
387 def custom ( self ) :
388 return "test"
389
390 parser = self . etree . XMLParser ( )
391 parser . set_element_class_lookup ( Lookup ( ) )
392
393 root = etree . XML ( '<foo/>' , parser )
394
395 self . assertEqual ( "test" , root . custom ( ) )
396
397
399 suite = unittest . TestSuite ( )
400 suite . addTests ( [ unittest . makeSuite ( ProxyTestCase ) ] )
401 suite . addTests ( [ unittest . makeSuite ( ClassLookupTestCase ) ] )
402 return suite
403
404 if __name__ == '__main__' :
405 print ( 'to test use test.py %s' % __file__ )
406