/[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 1845 - (show annotations)
Tue Oct 21 10:49:50 2003 UTC (21 years, 4 months ago) by bh
Original Path: trunk/thuban/test/test_save.py
File MIME type: text/x-python
File size: 24293 byte(s)
(SaveSessionTest.dtd)
(SaveSessionTest.testEmptySession)
(SaveSessionTest.testLayerProjection)
(SaveSessionTest.testRasterLayer)
(SaveSessionTest.testClassifiedLayer)
(SaveSessionTest.test_dbf_table)
(SaveSessionTest.test_joined_table)
(SaveSessionTest.test_save_postgis): Update to 1.0-dev namespace
(SaveSessionTest.testSingleLayer): Update to 1.0-dev namespace and
use a and epsg projection to test saving them

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-1.0-dev.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-1.0.dtd">\n'
115 '<session title="empty session" '
116 'xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.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(["proj=utm", "zone=27", "ellps=WGS84",
126 "datum=WGS84", "units=m"],
127 name = "WGS 84 / UTM zone 27N",
128 epsg = "32627")
129 map = Map("Test Map", projection = proj)
130 session.AddMap(map)
131 # use shapefile from the example data
132 shpfile = os.path.join(os.path.dirname(__file__),
133 os.pardir, "Data", "iceland", "political.shp")
134 layer = Layer("My Layer", session.OpenShapefile(shpfile))
135 map.AddLayer(layer)
136
137 filename = self.temp_file_name("save_singlemap.thuban")
138 save_session(session, filename)
139
140 file = open(filename)
141 written_contents = file.read()
142 file.close()
143 expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
144 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
145 <session title="single map&amp;layer"
146 xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd">
147 <fileshapesource id="D1" filename="%s" filetype="shapefile"/>
148 <map title="Test Map">
149 <projection epsg="32627" name="WGS 84 / UTM zone 27N">
150 <parameter value="proj=utm"/>
151 <parameter value="zone=27"/>
152 <parameter value="ellps=WGS84"/>
153 <parameter value="datum=WGS84"/>
154 <parameter value="units=m"/>
155 </projection>
156 <layer title="My Layer" shapestore="D1"
157 fill="None" stroke="#000000" stroke_width="1" visible="%s"/>
158 </map>
159 </session>'''
160
161 expected_contents = expected_template % \
162 (os.path.join("..", "..", "Data", "iceland", "political.shp"),
163 "true")
164
165 self.compare_xml(written_contents, expected_contents)
166
167 self.validate_data(written_contents)
168
169 layer.SetVisible(False)
170 save_session(session, filename)
171
172 file = open(filename)
173 written_contents = file.read()
174 file.close()
175 expected_contents = expected_template % \
176 (os.path.join("..", "..", "Data", "iceland", "political.shp"),
177 "false")
178 self.compare_xml(written_contents, expected_contents)
179 self.validate_data(written_contents)
180
181 session.Destroy()
182
183 def testLayerProjection(self):
184 """Test saving layers with projections"""
185 # deliberately put an apersand in the title :)
186 session = self.session = Session("single map&layer")
187 proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
188 map = Map("Test Map", projection = proj)
189 session.AddMap(map)
190 # use shapefile from the example data
191 shpfile = os.path.join(os.path.dirname(__file__),
192 os.pardir, "Data", "iceland", "political.shp")
193 layer = Layer("My Layer", session.OpenShapefile(shpfile))
194 proj = Projection(["proj=lcc", "ellps=clrk66",
195 "lat_1=0", "lat_2=20"],
196 "Layer Projection")
197 layer.SetProjection(proj)
198 map.AddLayer(layer)
199
200 filename = self.temp_file_name("save_layerproj.thuban")
201 save_session(session, filename)
202
203 file = open(filename)
204 written_contents = file.read()
205 file.close()
206 expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
207 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
208 <session title="single map&amp;layer"
209 xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd">
210 <fileshapesource id="D1" filename="%s" filetype="shapefile"/>
211 <map title="Test Map">
212 <projection name="Unknown">
213 <parameter value="zone=26"/>
214 <parameter value="proj=utm"/>
215 <parameter value="ellps=clrk66"/>
216 </projection>
217 <layer title="My Layer" shapestore="D1"
218 fill="None" stroke="#000000" stroke_width="1" visible="true">
219 <projection name="Layer Projection">
220 <parameter value="proj=lcc"/>
221 <parameter value="ellps=clrk66"/>
222 <parameter value="lat_1=0"/>
223 <parameter value="lat_2=20"/>
224 </projection>
225 </layer>
226 </map>
227 </session>''' % os.path.join("..", "..", "Data", "iceland",
228 "political.shp")
229 #print written_contents
230 #print "********************************************"
231 #print expected_contents
232 self.compare_xml(written_contents, expected_contents)
233
234 self.validate_data(written_contents)
235
236 def testRasterLayer(self):
237 # deliberately put an apersand in the title :)
238 session = Session("single map&layer")
239 map = Map("Test Map")
240 session.AddMap(map)
241 # use shapefile from the example data
242 imgfile = os.path.join(os.path.dirname(__file__),
243 os.pardir, "Data", "iceland", "island.tif")
244 layer = RasterLayer("My RasterLayer", imgfile)
245 map.AddLayer(layer)
246
247 filename = self.temp_file_name("%s.thuban" % self.id())
248 save_session(session, filename)
249 session.Destroy()
250
251 file = open(filename)
252 written_contents = file.read()
253 file.close()
254 expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
255 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
256 <session title="single map&amp;layer"
257 xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd">
258 <map title="Test Map">
259 <rasterlayer title="My RasterLayer" filename="%s"
260 visible="true">
261 </rasterlayer>
262 </map>
263 </session>''' % os.path.join(os.pardir, os.pardir, "Data", "iceland",
264 "island.tif")
265 #print written_contents
266 #print "********************************************"
267 #print expected_contents
268 self.compare_xml(written_contents, expected_contents)
269
270 self.validate_data(written_contents)
271
272 def testClassifiedLayer(self):
273 """Save a session with a single map with classifications"""
274 # deliberately put an apersand in the title :)
275 session = Session("Map with Classifications")
276 proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
277 map = Map("Test Map", projection = proj)
278 session.AddMap(map)
279 # use shapefile from the example data
280 shpfile = os.path.join(os.path.dirname(__file__),
281 os.pardir, "Data", "iceland", "political.shp")
282 layer = Layer("My Layer", session.OpenShapefile(shpfile))
283 map.AddLayer(layer)
284 layer2 = Layer("My Layer", layer.ShapeStore())
285 map.AddLayer(layer2)
286
287 clazz = layer.GetClassification()
288
289 layer.SetClassificationColumn("AREA")
290
291 clazz.AppendGroup(ClassGroupSingleton(42, ClassGroupProperties(),
292 "single"))
293 clazz.AppendGroup(ClassGroupSingleton("text", ClassGroupProperties(),
294 "single-text"))
295
296 clazz.AppendGroup(ClassGroupRange((0, 42),
297 ClassGroupProperties(),
298 "range"))
299
300 range = ClassGroupRange(Range("[0;42]"))
301 range.SetProperties(ClassGroupProperties())
302 range.SetLabel("new-range")
303 clazz.AppendGroup(range)
304
305
306 clazz = layer2.GetClassification()
307 layer2.SetClassificationColumn("POPYCOUN")
308
309 # Classification with Latin 1 text
310 clazz.AppendGroup(ClassGroupSingleton('\xe4\xf6\xfc', # ae, oe, ue
311 ClassGroupProperties(),
312 '\xdcml\xe4uts')) # Uemlaeuts
313
314
315 filename = self.temp_file_name("%s.thuban" % self.id())
316 save_session(session, filename)
317
318 file = open(filename)
319 written_contents = file.read()
320 file.close()
321 expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
322 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
323 <session title="Map with Classifications"
324 xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd">
325 <fileshapesource id="D1" filename="%s" filetype="shapefile"/>
326 <map title="Test Map">
327 <projection name="Unknown">
328 <parameter value="zone=26"/>
329 <parameter value="proj=utm"/>
330 <parameter value="ellps=clrk66"/>
331 </projection>
332 <layer title="My Layer" shapestore="D1"
333 fill="None" stroke="#000000" stroke_width="1" visible="%s">
334 <classification field="AREA" field_type="double">
335 <clnull label="">
336 <cldata fill="None" stroke="#000000" stroke_width="1"/>
337 </clnull>
338 <clpoint value="42" label="single">
339 <cldata fill="None" stroke="#000000" stroke_width="1"/>
340 </clpoint>
341 <clpoint value="text" label="single-text">
342 <cldata fill="None" stroke="#000000" stroke_width="1"/>
343 </clpoint>
344 <clrange range="[0;42[" label="range">
345 <cldata fill="None" stroke="#000000" stroke_width="1"/>
346 </clrange>
347 <clrange range="[0;42]" label="new-range">
348 <cldata fill="None" stroke="#000000" stroke_width="1"/>
349 </clrange>
350 </classification>
351 </layer>
352 <layer title="My Layer" shapestore="D1"
353 fill="None" stroke="#000000" stroke_width="1" visible="true">
354 <classification field="POPYCOUN" field_type="string">
355 <clnull label="">
356 <cldata fill="None" stroke="#000000" stroke_width="1"/>
357 </clnull>
358 <clpoint value="\xc3\xa4\xc3\xb6\xc3\xbc"
359 label="\xc3\x9cml\xc3\xa4uts">
360 <cldata fill="None" stroke="#000000" stroke_width="1"/>
361 </clpoint>
362 </classification>
363 </layer>
364 </map>
365 </session>'''
366
367 expected_contents = expected_template % \
368 (os.path.join("..", "..", "Data", "iceland", "political.shp"),
369 "true")
370
371 #print written_contents
372 #print "********************************************"
373 #print expected_contents
374 self.compare_xml(written_contents, expected_contents)
375
376 self.validate_data(written_contents)
377
378 session.Destroy()
379
380 def test_dbf_table(self):
381 """Test saving a session with a dbf table link"""
382 session = self.session = Session("a DBF Table session")
383 # use shapefile from the example data
384 dbffile = os.path.join(os.path.dirname(__file__),
385 os.pardir, "Data", "iceland", "political.dbf")
386 table = session.AddTable(DBFTable(dbffile))
387
388 filename = self.temp_file_name("save_singletable.thuban")
389 save_session(session, filename)
390
391 file = open(filename)
392 written_contents = file.read()
393 file.close()
394 expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
395 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
396 <session title="a DBF Table session"
397 xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd">
398 <filetable id="D1" filename="%s" filetype="DBF" title="political"/>
399 </session>'''
400
401 expected_contents = (expected_template
402 % os.path.join(os.pardir, os.pardir, "Data",
403 "iceland", "political.dbf"))
404 self.compare_xml(written_contents, expected_contents)
405 self.validate_data(written_contents)
406
407 def test_joined_table(self):
408 """Test saving a session with joined table"""
409 # Create a simple table to use in the join
410 dbffile = self.temp_file_name("save_joinedtable.dbf")
411 dbf = dbflib.create(dbffile)
412 dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
413 dbf.add_field("TEXT", dbflib.FTString, 10, 0)
414 dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
415 dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
416 dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
417 dbf.close()
418
419 # Create the session and a map
420 session = Session("A Joined Table session")
421 try:
422 map = Map("Test Map")
423 session.AddMap(map)
424
425 # Add the dbf file to the session
426 dbftable = session.AddTable(DBFTable(dbffile))
427
428 # Create a layer with the shapefile to use in the join
429 shpfile = os.path.join(os.path.abspath(os.path.dirname(__file__)),
430 os.pardir, "Data", "iceland",
431 "roads-line.shp")
432 layer = Layer("My Layer", session.OpenShapefile(shpfile))
433 map.AddLayer(layer)
434
435 # Do the join
436 store = layer.ShapeStore()
437 #for col in store.Table().Columns():
438 # print col.name
439 joined = TransientJoinedTable(session.TransientDB(),
440 store.Table(), "RDLNTYPE",
441 dbftable, "RDTYPE",
442 outer_join = True)
443 store = session.AddShapeStore(DerivedShapeStore(store, joined))
444 layer.SetShapeStore(store)
445
446 # Save the session
447 filename = self.temp_file_name("save_joinedtable.thuban")
448 save_session(session, filename)
449
450 # Read it back and compare
451 file = open(filename)
452 written_contents = file.read()
453 file.close()
454 expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
455 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
456 <session title="A Joined Table session"
457 xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd">
458 <fileshapesource filename="%(shpfile)s"
459 filetype="shapefile" id="D142197204"/>
460 <filetable filename="%(dbffile)s"
461 title="save_joinedtable"
462 filetype="DBF" id="D141881756"/>
463 <jointable id="D142180284"
464 title="Join of roads-line and save_joinedtable"
465 leftcolumn="RDLNTYPE" left="D142197204"
466 rightcolumn="RDTYPE" right="D141881756"
467 jointype="LEFT OUTER" />
468 <derivedshapesource id="D141915644"
469 table="D142180284"
470 shapesource="D142197204"/>
471 <map title="Test Map">
472 <layer title="My Layer"
473 shapestore="D141915644" visible="true"
474 stroke="#000000" stroke_width="1" fill="None"/>
475 </map>
476 </session>'''
477
478 expected_contents = expected_template % {
479 "dbffile": relative_filename(self.temp_dir(), dbffile),
480 "shpfile": relative_filename(self.temp_dir(), shpfile)
481 }
482 self.compare_xml(written_contents, expected_contents)
483 self.validate_data(written_contents)
484 finally:
485 session.Destroy()
486 session = None
487
488
489 def test_save_postgis(self):
490 """Test saving a session with a postgis connection"""
491
492 class NonConnection(PostGISConnection):
493 """connection class that doesn't actually connect """
494 def connect(self):
495 pass
496
497 class NonConnectionStore(PostGISShapeStore):
498 """Shapestore that doesn't try to access the server"""
499 def _fetch_table_information(self):
500 pass
501
502 session = Session("A PostGIS Session")
503 try:
504 dbconn = NonConnection(dbname="plugh", host="xyzzy", port="42",
505 user="grue")
506 session.AddDBConnection(dbconn)
507 map = Map("Test Map")
508 session.AddMap(map)
509 store = NonConnectionStore(dbconn, "roads")
510 session.AddShapeStore(store)
511 layer = Layer("Roads to Nowhere", store)
512 map.AddLayer(layer)
513
514 # Save the session
515 filename = self.temp_file_name(self.id() + ".thuban")
516 save_session(session, filename)
517
518 # Read it back and compare
519 file = open(filename)
520 written = file.read()
521 file.close()
522 expected = '''<?xml version="1.0" encoding="UTF-8"?>
523 <!DOCTYPE session SYSTEM "thuban-1.0.dtd">
524 <session title="A PostGIS Session"
525 xmlns="http://thuban.intevation.org/dtds/thuban-1.0-dev.dtd">
526 <dbconnection id="DB"
527 dbtype="postgis" dbname="plugh"
528 host="xyzzy" port="42"
529 user="grue"/>
530 <dbshapesource id="roads" dbconn="DB" tablename="roads"/>
531 <map title="Test Map">
532 <layer title="Roads to Nowhere"
533 shapestore="roads" visible="true"
534 stroke="#000000" stroke_width="1" fill="None"/>
535 </map>
536 </session>'''
537 self.compare_xml(written, expected)
538 self.validate_data(written)
539 finally:
540 session.Destroy()
541
542
543 class MockDataStore:
544
545 """A very simple data store that only has dependencies"""
546
547 def __init__(self, name, *dependencies):
548 self.name = name
549 self.dependencies = dependencies
550
551 def __repr__(self):
552 return self.name
553
554 def Dependencies(self):
555 return self.dependencies
556
557
558 class TestStoreSort(unittest.TestCase):
559
560 def check_sort(self, containers, sorted):
561 """Check whether the list of data containers is sorted"""
562 # check whether sorted is in the right order
563 seen = {}
564 for container in sorted:
565 self.failIf(id(container) in seen,
566 "Container %r at least twice in %r" % (container,
567 sorted))
568 for dep in container.Dependencies():
569 self.assert_(id(dep) in seen,
570 "Dependency %r of %r not yet seen" % (dep,
571 container))
572 seen[id(container)] = 1
573 # check whether all of containers is in sorted
574 for container in containers:
575 self.assert_(id(container) in seen,
576 "Container %r in containers but not in sorted")
577 self.assertEquals(len(containers), len(sorted))
578
579 def test_sort_data_stores(self):
580 """Test Thuban.Model.save.sort_data_stores"""
581 d1 = MockDataStore("d1")
582 d2 = MockDataStore("d2")
583 d3 = MockDataStore("d3", d1)
584 d4 = MockDataStore("d4", d1, d3)
585
586 containers = [d4, d1, d2, d3]
587 self.check_sort(containers, sort_data_stores(containers))
588 containers = [d1, d3, d2, d4]
589 self.check_sort(containers, sort_data_stores(containers))
590
591
592
593 if __name__ == "__main__":
594 # Fake the __file__ global because it's needed by a test
595 import sys
596 __file__ = sys.argv[0]
597 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