/[thuban]/branches/WIP-pyshapelib-bramz/test/test_save.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/test/test_save.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1678 - (show annotations)
Thu Aug 28 13:36:23 2003 UTC (21 years, 6 months ago) by bh
Original Path: trunk/thuban/test/test_save.py
File MIME type: text/x-python
File size: 23794 byte(s)
(SaveSessionTest.testLayerProjection): Bind the session to
self.session so that it gets destroyed properly

1 # Copyright (c) 2002, 2003 by Intevation GmbH
2 # Authors:
3 # Bernhard Herzog <[email protected]>
4 #
5 # This program is free software under the GPL (>=v2)
6 # Read the file COPYING coming with Thuban for details.
7
8 """
9 Test saving a thuban session as XML
10 """
11
12 __version__ = "$Revision$"
13 # $Source$
14 # $Id$
15
16 import os
17 import unittest
18 from StringIO import StringIO
19
20 import xmlsupport
21 import postgissupport
22
23 import support
24 support.initthuban()
25
26 import dbflib
27
28 from Thuban.Lib.fileutil import relative_filename
29 from Thuban.Model.save import XMLWriter, save_session, sort_data_stores
30 from Thuban.Model.session import Session
31 from Thuban.Model.map import Map
32 from Thuban.Model.layer import Layer, RasterLayer
33 from Thuban.Model.proj import Projection
34 from Thuban.Model.table import DBFTable
35 from Thuban.Model.transientdb import TransientJoinedTable
36 from Thuban.Model.data import DerivedShapeStore
37
38 from Thuban.Model.classification import ClassGroupSingleton, ClassGroupRange, \
39 ClassGroupProperties
40
41 from Thuban.Model.range import Range
42
43 from Thuban.Model.postgisdb import PostGISConnection, PostGISShapeStore
44
45
46 class XMLWriterTest(unittest.TestCase):
47
48 def testEncode(self):
49 """Test XMLWriter.encode"""
50 writer = XMLWriter()
51 eq = self.assertEquals
52
53 eq(writer.encode("hello world"), "hello world")
54 eq(writer.encode(unicode("hello world")), unicode("hello world"))
55
56 eq(writer.encode("\x80\x90\xc2\x100"),
57 "\xc2\x80\xc2\x90\xc3\x82\x100")
58 eq(writer.encode(u"\x80\x90\xc2\x100"),
59 "\xc2\x80\xc2\x90\xc3\x82\x100")
60 eq(writer.encode(u"\xFF5E"), "\xc3\xbf5E")
61
62 eq(writer.encode('&"\'<>'), "&amp;&quot;&apos;&lt;&gt;")
63 eq(writer.encode(unicode('&"\'<>')), "&amp;&quot;&apos;&lt;&gt;")
64
65 class SaveSessionTest(unittest.TestCase, support.FileTestMixin,
66 xmlsupport.ValidationTest):
67
68 dtd = "http://thuban.intevation.org/dtds/thuban-0.9.dtd"
69 thubanids = [((dtd, n), (None, "id")) for n in
70 ["fileshapesource", "filetable", "jointable",
71 "derivedshapesource", "dbshapesource", "dbconnection"]]
72 thubanidrefs = [((dtd, n), (None, m)) for n, m in
73 [("layer", "shapestore"),
74 ("jointable", "left"),
75 ("jointable", "right"),
76 ("derivedshapesource", "table"),
77 ("derivedshapesource", "shapesource"),
78 ("dbshapesource", "dbconn")]]
79 del n, m, dtd
80
81 def tearDown(self):
82 """Call self.session.Destroy
83
84 Test cases that create session should bind it to self.session so
85 that it gets destroyed properly
86 """
87 if hasattr(self, "session"):
88 self.session.Destroy()
89 self.session = None
90
91 def compare_xml(self, xml1, xml2):
92 list1 = xmlsupport.sax_eventlist(xml1, ids = self.thubanids,
93 idrefs = self.thubanidrefs)
94 list2 = xmlsupport.sax_eventlist(xml2, ids = self.thubanids,
95 idrefs = self.thubanidrefs)
96 if list1 != list2:
97 for a, b in zip(list1, list2):
98 if a != b:
99 self.fail("%r != %r" % (a, b))
100
101
102 def testEmptySession(self):
103 """Save an empty session"""
104 session = Session("empty session")
105 filename = self.temp_file_name("save_emptysession.thuban")
106 save_session(session, filename)
107 session.Destroy()
108
109 file = open(filename)
110 written_contents = file.read()
111 file.close()
112 self.compare_xml(written_contents,
113 '<?xml version="1.0" encoding="UTF-8"?>\n'
114 '<!DOCTYPE session SYSTEM "thuban-0.9.dtd">\n'
115 '<session title="empty session" '
116 'xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd">'
117 '\n</session>\n')
118
119 self.validate_data(written_contents)
120
121 def testSingleLayer(self):
122 """Save a session with a single map with a single layer"""
123 # deliberately put an apersand in the title :)
124 session = Session("single map&layer")
125 proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
126 map = Map("Test Map", projection = proj)
127 session.AddMap(map)
128 # use shapefile from the example data
129 shpfile = os.path.join(os.path.dirname(__file__),
130 os.pardir, "Data", "iceland", "political.shp")
131 layer = Layer("My Layer", session.OpenShapefile(shpfile))
132 map.AddLayer(layer)
133
134 filename = self.temp_file_name("save_singlemap.thuban")
135 save_session(session, filename)
136
137 file = open(filename)
138 written_contents = file.read()
139 file.close()
140 expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
141 <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
142 <session title="single map&amp;layer"
143 xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd">
144 <fileshapesource id="D1" filename="%s" filetype="shapefile"/>
145 <map title="Test Map">
146 <projection name="Unknown">
147 <parameter value="zone=26"/>
148 <parameter value="proj=utm"/>
149 <parameter value="ellps=clrk66"/>
150 </projection>
151 <layer title="My Layer" shapestore="D1"
152 fill="None" stroke="#000000" stroke_width="1" visible="%s"/>
153 </map>
154 </session>'''
155
156 expected_contents = expected_template % \
157 (os.path.join("..", "..", "Data", "iceland", "political.shp"),
158 "true")
159
160 self.compare_xml(written_contents, expected_contents)
161
162 self.validate_data(written_contents)
163
164 layer.SetVisible(False)
165 save_session(session, filename)
166
167 file = open(filename)
168 written_contents = file.read()
169 file.close()
170 expected_contents = expected_template % \
171 (os.path.join("..", "..", "Data", "iceland", "political.shp"),
172 "false")
173 self.compare_xml(written_contents, expected_contents)
174 self.validate_data(written_contents)
175
176 session.Destroy()
177
178 def testLayerProjection(self):
179 """Test saving layers with projections"""
180 # deliberately put an apersand in the title :)
181 session = self.session = Session("single map&layer")
182 proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
183 map = Map("Test Map", projection = proj)
184 session.AddMap(map)
185 # use shapefile from the example data
186 shpfile = os.path.join(os.path.dirname(__file__),
187 os.pardir, "Data", "iceland", "political.shp")
188 layer = Layer("My Layer", session.OpenShapefile(shpfile))
189 proj = Projection(["proj=lcc", "ellps=clrk66"], "Layer Projection")
190 layer.SetProjection(proj)
191 map.AddLayer(layer)
192
193 filename = self.temp_file_name("save_layerproj.thuban")
194 save_session(session, filename)
195
196 file = open(filename)
197 written_contents = file.read()
198 file.close()
199 expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
200 <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
201 <session title="single map&amp;layer"
202 xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd">
203 <fileshapesource id="D1" filename="%s" filetype="shapefile"/>
204 <map title="Test Map">
205 <projection name="Unknown">
206 <parameter value="zone=26"/>
207 <parameter value="proj=utm"/>
208 <parameter value="ellps=clrk66"/>
209 </projection>
210 <layer title="My Layer" shapestore="D1"
211 fill="None" stroke="#000000" stroke_width="1" visible="true">
212 <projection name="Layer Projection">
213 <parameter value="proj=lcc"/>
214 <parameter value="ellps=clrk66"/>
215 </projection>
216 </layer>
217 </map>
218 </session>''' % os.path.join("..", "..", "Data", "iceland",
219 "political.shp")
220 #print written_contents
221 #print "********************************************"
222 #print expected_contents
223 self.compare_xml(written_contents, expected_contents)
224
225 self.validate_data(written_contents)
226
227 def testRasterLayer(self):
228 # deliberately put an apersand in the title :)
229 session = Session("single map&layer")
230 map = Map("Test Map")
231 session.AddMap(map)
232 # use shapefile from the example data
233 imgfile = os.path.join(os.path.dirname(__file__),
234 os.pardir, "Data", "iceland", "island.tif")
235 layer = RasterLayer("My RasterLayer", imgfile)
236 map.AddLayer(layer)
237
238 filename = self.temp_file_name("%s.thuban" % self.id())
239 save_session(session, filename)
240 session.Destroy()
241
242 file = open(filename)
243 written_contents = file.read()
244 file.close()
245 expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
246 <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
247 <session title="single map&amp;layer"
248 xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd">
249 <map title="Test Map">
250 <rasterlayer title="My RasterLayer" filename="%s"
251 visible="true">
252 </rasterlayer>
253 </map>
254 </session>''' % os.path.join(os.pardir, os.pardir, "Data", "iceland",
255 "island.tif")
256 #print written_contents
257 #print "********************************************"
258 #print expected_contents
259 self.compare_xml(written_contents, expected_contents)
260
261 self.validate_data(written_contents)
262
263 def testClassifiedLayer(self):
264 """Save a session with a single map with classifications"""
265 # deliberately put an apersand in the title :)
266 session = Session("Map with Classifications")
267 proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
268 map = Map("Test Map", projection = proj)
269 session.AddMap(map)
270 # use shapefile from the example data
271 shpfile = os.path.join(os.path.dirname(__file__),
272 os.pardir, "Data", "iceland", "political.shp")
273 layer = Layer("My Layer", session.OpenShapefile(shpfile))
274 map.AddLayer(layer)
275 layer2 = Layer("My Layer", layer.ShapeStore())
276 map.AddLayer(layer2)
277
278 clazz = layer.GetClassification()
279
280 layer.SetClassificationColumn("AREA")
281
282 clazz.AppendGroup(ClassGroupSingleton(42, ClassGroupProperties(),
283 "single"))
284 clazz.AppendGroup(ClassGroupSingleton("text", ClassGroupProperties(),
285 "single-text"))
286
287 clazz.AppendGroup(ClassGroupRange((0, 42),
288 ClassGroupProperties(),
289 "range"))
290
291 range = ClassGroupRange(Range("[0;42]"))
292 range.SetProperties(ClassGroupProperties())
293 range.SetLabel("new-range")
294 clazz.AppendGroup(range)
295
296
297 clazz = layer2.GetClassification()
298 layer2.SetClassificationColumn("POPYCOUN")
299
300 # Classification with Latin 1 text
301 clazz.AppendGroup(ClassGroupSingleton('\xe4\xf6\xfc', # ae, oe, ue
302 ClassGroupProperties(),
303 '\xdcml\xe4uts')) # Uemlaeuts
304
305
306 filename = self.temp_file_name("%s.thuban" % self.id())
307 save_session(session, filename)
308
309 file = open(filename)
310 written_contents = file.read()
311 file.close()
312 expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
313 <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
314 <session title="Map with Classifications"
315 xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd">
316 <fileshapesource id="D1" filename="%s" filetype="shapefile"/>
317 <map title="Test Map">
318 <projection name="Unknown">
319 <parameter value="zone=26"/>
320 <parameter value="proj=utm"/>
321 <parameter value="ellps=clrk66"/>
322 </projection>
323 <layer title="My Layer" shapestore="D1"
324 fill="None" stroke="#000000" stroke_width="1" visible="%s">
325 <classification field="AREA" field_type="double">
326 <clnull label="">
327 <cldata fill="None" stroke="#000000" stroke_width="1"/>
328 </clnull>
329 <clpoint value="42" label="single">
330 <cldata fill="None" stroke="#000000" stroke_width="1"/>
331 </clpoint>
332 <clpoint value="text" label="single-text">
333 <cldata fill="None" stroke="#000000" stroke_width="1"/>
334 </clpoint>
335 <clrange range="[0;42[" label="range">
336 <cldata fill="None" stroke="#000000" stroke_width="1"/>
337 </clrange>
338 <clrange range="[0;42]" label="new-range">
339 <cldata fill="None" stroke="#000000" stroke_width="1"/>
340 </clrange>
341 </classification>
342 </layer>
343 <layer title="My Layer" shapestore="D1"
344 fill="None" stroke="#000000" stroke_width="1" visible="true">
345 <classification field="POPYCOUN" field_type="string">
346 <clnull label="">
347 <cldata fill="None" stroke="#000000" stroke_width="1"/>
348 </clnull>
349 <clpoint value="\xc3\xa4\xc3\xb6\xc3\xbc"
350 label="\xc3\x9cml\xc3\xa4uts">
351 <cldata fill="None" stroke="#000000" stroke_width="1"/>
352 </clpoint>
353 </classification>
354 </layer>
355 </map>
356 </session>'''
357
358 expected_contents = expected_template % \
359 (os.path.join("..", "..", "Data", "iceland", "political.shp"),
360 "true")
361
362 #print written_contents
363 #print "********************************************"
364 #print expected_contents
365 self.compare_xml(written_contents, expected_contents)
366
367 self.validate_data(written_contents)
368
369 session.Destroy()
370
371 def test_dbf_table(self):
372 """Test saving a session with a dbf table link"""
373 session = self.session = Session("a DBF Table session")
374 # use shapefile from the example data
375 dbffile = os.path.join(os.path.dirname(__file__),
376 os.pardir, "Data", "iceland", "political.dbf")
377 table = session.AddTable(DBFTable(dbffile))
378
379 filename = self.temp_file_name("save_singletable.thuban")
380 save_session(session, filename)
381
382 file = open(filename)
383 written_contents = file.read()
384 file.close()
385 expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
386 <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
387 <session title="a DBF Table session"
388 xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd">
389 <filetable id="D1" filename="%s" filetype="DBF" title="political"/>
390 </session>'''
391
392 expected_contents = (expected_template
393 % os.path.join(os.pardir, os.pardir, "Data",
394 "iceland", "political.dbf"))
395 self.compare_xml(written_contents, expected_contents)
396 self.validate_data(written_contents)
397
398 def test_joined_table(self):
399 """Test saving a session with joined table"""
400 # Create a simple table to use in the join
401 dbffile = self.temp_file_name("save_joinedtable.dbf")
402 dbf = dbflib.create(dbffile)
403 dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
404 dbf.add_field("TEXT", dbflib.FTString, 10, 0)
405 dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
406 dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
407 dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
408 dbf.close()
409
410 # Create the session and a map
411 session = Session("A Joined Table session")
412 try:
413 map = Map("Test Map")
414 session.AddMap(map)
415
416 # Add the dbf file to the session
417 dbftable = session.AddTable(DBFTable(dbffile))
418
419 # Create a layer with the shapefile to use in the join
420 shpfile = os.path.join(os.path.abspath(os.path.dirname(__file__)),
421 os.pardir, "Data", "iceland",
422 "roads-line.shp")
423 layer = Layer("My Layer", session.OpenShapefile(shpfile))
424 map.AddLayer(layer)
425
426 # Do the join
427 store = layer.ShapeStore()
428 #for col in store.Table().Columns():
429 # print col.name
430 joined = TransientJoinedTable(session.TransientDB(),
431 store.Table(), "RDLNTYPE",
432 dbftable, "RDTYPE",
433 outer_join = True)
434 store = session.AddShapeStore(DerivedShapeStore(store, joined))
435 layer.SetShapeStore(store)
436
437 # Save the session
438 filename = self.temp_file_name("save_joinedtable.thuban")
439 save_session(session, filename)
440
441 # Read it back and compare
442 file = open(filename)
443 written_contents = file.read()
444 file.close()
445 expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
446 <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
447 <session title="A Joined Table session"
448 xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd">
449 <fileshapesource filename="%(shpfile)s"
450 filetype="shapefile" id="D142197204"/>
451 <filetable filename="%(dbffile)s"
452 title="save_joinedtable"
453 filetype="DBF" id="D141881756"/>
454 <jointable id="D142180284"
455 title="Join of roads-line and save_joinedtable"
456 leftcolumn="RDLNTYPE" left="D142197204"
457 rightcolumn="RDTYPE" right="D141881756"
458 jointype="LEFT OUTER" />
459 <derivedshapesource id="D141915644"
460 table="D142180284"
461 shapesource="D142197204"/>
462 <map title="Test Map">
463 <layer title="My Layer"
464 shapestore="D141915644" visible="true"
465 stroke="#000000" stroke_width="1" fill="None"/>
466 </map>
467 </session>'''
468
469 expected_contents = expected_template % {
470 "dbffile": relative_filename(self.temp_dir(), dbffile),
471 "shpfile": relative_filename(self.temp_dir(), shpfile)
472 }
473 self.compare_xml(written_contents, expected_contents)
474 self.validate_data(written_contents)
475 finally:
476 session.Destroy()
477 session = None
478
479
480 def test_save_postgis(self):
481 """Test saving a session with a postgis connection"""
482
483 class NonConnection(PostGISConnection):
484 """connection class that doesn't actually connect """
485 def connect(self):
486 pass
487
488 class NonConnectionStore(PostGISShapeStore):
489 """Shapestore that doesn't try to access the server"""
490 def _fetch_table_information(self):
491 pass
492
493 session = Session("A PostGIS Session")
494 try:
495 dbconn = NonConnection(dbname="plugh", host="xyzzy", port="42",
496 user="grue")
497 session.AddDBConnection(dbconn)
498 map = Map("Test Map")
499 session.AddMap(map)
500 store = NonConnectionStore(dbconn, "roads")
501 session.AddShapeStore(store)
502 layer = Layer("Roads to Nowhere", store)
503 map.AddLayer(layer)
504
505 # Save the session
506 filename = self.temp_file_name(self.id() + ".thuban")
507 save_session(session, filename)
508
509 # Read it back and compare
510 file = open(filename)
511 written = file.read()
512 file.close()
513 expected = '''<?xml version="1.0" encoding="UTF-8"?>
514 <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
515 <session title="A PostGIS Session"
516 xmlns="http://thuban.intevation.org/dtds/thuban-0.9.dtd">
517 <dbconnection id="DB"
518 dbtype="postgis" dbname="plugh"
519 host="xyzzy" port="42"
520 user="grue"/>
521 <dbshapesource id="roads" dbconn="DB" tablename="roads"/>
522 <map title="Test Map">
523 <layer title="Roads to Nowhere"
524 shapestore="roads" visible="true"
525 stroke="#000000" stroke_width="1" fill="None"/>
526 </map>
527 </session>'''
528 self.compare_xml(written, expected)
529 self.validate_data(written)
530 finally:
531 session.Destroy()
532
533
534 class MockDataStore:
535
536 """A very simple data store that only has dependencies"""
537
538 def __init__(self, name, *dependencies):
539 self.name = name
540 self.dependencies = dependencies
541
542 def __repr__(self):
543 return self.name
544
545 def Dependencies(self):
546 return self.dependencies
547
548
549 class TestStoreSort(unittest.TestCase):
550
551 def check_sort(self, containers, sorted):
552 """Check whether the list of data containers is sorted"""
553 # check whether sorted is in the right order
554 seen = {}
555 for container in sorted:
556 self.failIf(id(container) in seen,
557 "Container %r at least twice in %r" % (container,
558 sorted))
559 for dep in container.Dependencies():
560 self.assert_(id(dep) in seen,
561 "Dependency %r of %r not yet seen" % (dep,
562 container))
563 seen[id(container)] = 1
564 # check whether all of containers is in sorted
565 for container in containers:
566 self.assert_(id(container) in seen,
567 "Container %r in containers but not in sorted")
568 self.assertEquals(len(containers), len(sorted))
569
570 def test_sort_data_stores(self):
571 """Test Thuban.Model.save.sort_data_stores"""
572 d1 = MockDataStore("d1")
573 d2 = MockDataStore("d2")
574 d3 = MockDataStore("d3", d1)
575 d4 = MockDataStore("d4", d1, d3)
576
577 containers = [d4, d1, d2, d3]
578 self.check_sort(containers, sort_data_stores(containers))
579 containers = [d1, d3, d2, d4]
580 self.check_sort(containers, sort_data_stores(containers))
581
582
583
584 if __name__ == "__main__":
585 # Fake the __file__ global because it's needed by a test
586 import sys
587 __file__ = sys.argv[0]
588 support.run_tests()

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26