/[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 2551 - (show annotations)
Thu Jan 27 14:19:41 2005 UTC (20 years, 1 month ago) by jonathan
Original Path: trunk/thuban/test/test_save.py
File MIME type: text/x-python
File size: 24124 byte(s)
Add a new dialog box for raster layers. The dialog box allows
the user to toggle a mask that is generated by ProjectRasterFile
and is used to only draw the real parts of the projected image.

1 # Copyright (c) 2002, 2003, 2004 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.1-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.1.dtd">\n'
115 '<session title="empty session" '
116 'xmlns="http://thuban.intevation.org/dtds/thuban-1.1-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.1.dtd">
145 <session title="single map&amp;layer"
146 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
147 <fileshapesource id="D1"
148 filename="../../Data/iceland/political.shp"
149 filetype="shapefile"/>
150 <map title="Test Map">
151 <projection epsg="32627" name="WGS 84 / UTM zone 27N">
152 <parameter value="proj=utm"/>
153 <parameter value="zone=27"/>
154 <parameter value="ellps=WGS84"/>
155 <parameter value="datum=WGS84"/>
156 <parameter value="units=m"/>
157 </projection>
158 <layer title="My Layer" shapestore="D1"
159 fill="None" stroke="#000000" stroke_width="1" visible="%s"/>
160 </map>
161 </session>'''
162
163 expected_contents = expected_template % "true"
164
165 self.compare_xml(written_contents, expected_contents)
166
167 self.validate_data(written_contents)
168
169 # Repeat with an invisible layer
170 layer.SetVisible(False)
171 save_session(session, filename)
172
173 file = open(filename)
174 written_contents = file.read()
175 file.close()
176 expected_contents = expected_template % "false"
177 self.compare_xml(written_contents, expected_contents)
178 self.validate_data(written_contents)
179
180 session.Destroy()
181
182 def testLayerProjection(self):
183 """Test saving layers with projections"""
184 # deliberately put an apersand in the title :)
185 session = self.session = Session("single map&layer")
186 proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
187 map = Map("Test Map", projection = proj)
188 session.AddMap(map)
189 # use shapefile from the example data
190 shpfile = os.path.join(os.path.dirname(__file__),
191 os.pardir, "Data", "iceland", "political.shp")
192 layer = Layer("My Layer", session.OpenShapefile(shpfile))
193 proj = Projection(["proj=lcc", "ellps=clrk66",
194 "lat_1=0", "lat_2=20"],
195 "Layer Projection")
196 layer.SetProjection(proj)
197 map.AddLayer(layer)
198
199 filename = self.temp_file_name("save_layerproj.thuban")
200 save_session(session, filename)
201
202 file = open(filename)
203 written_contents = file.read()
204 file.close()
205 expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
206 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
207 <session title="single map&amp;layer"
208 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
209 <fileshapesource id="D1"
210 filename="../../Data/iceland/political.shp"
211 filetype="shapefile"/>
212 <map title="Test Map">
213 <projection name="Unknown">
214 <parameter value="zone=26"/>
215 <parameter value="proj=utm"/>
216 <parameter value="ellps=clrk66"/>
217 </projection>
218 <layer title="My Layer" shapestore="D1"
219 fill="None" stroke="#000000" stroke_width="1" visible="true">
220 <projection name="Layer Projection">
221 <parameter value="proj=lcc"/>
222 <parameter value="ellps=clrk66"/>
223 <parameter value="lat_1=0"/>
224 <parameter value="lat_2=20"/>
225 </projection>
226 </layer>
227 </map>
228 </session>'''
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 layer.SetUseMask(True)
246 map.AddLayer(layer)
247
248 filename = self.temp_file_name("%s.thuban" % self.id())
249 save_session(session, filename)
250 session.Destroy()
251
252 file = open(filename)
253 written_contents = file.read()
254 file.close()
255 expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
256 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
257 <session title="single map&amp;layer"
258 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
259 <map title="Test Map">
260 <rasterlayer title="My RasterLayer"
261 filename="../../Data/iceland/island.tif"
262 visible="true" use_mask="true">
263 </rasterlayer>
264 </map>
265 </session>'''
266 #print written_contents
267 #print "********************************************"
268 #print expected_contents
269 self.compare_xml(written_contents, expected_contents)
270
271 self.validate_data(written_contents)
272
273 def testClassifiedLayer(self):
274 """Save a session with a single map with classifications"""
275 # deliberately put an apersand in the title :)
276 session = Session("Map with Classifications")
277 proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
278 map = Map("Test Map", projection = proj)
279 session.AddMap(map)
280 # use shapefile from the example data
281 shpfile = os.path.join(os.path.dirname(__file__),
282 os.pardir, "Data", "iceland", "political.shp")
283 layer = Layer("My Layer", session.OpenShapefile(shpfile))
284 map.AddLayer(layer)
285 layer2 = Layer("My Layer", layer.ShapeStore())
286 map.AddLayer(layer2)
287
288 clazz = layer.GetClassification()
289
290 layer.SetClassificationColumn("AREA")
291
292 clazz.AppendGroup(ClassGroupSingleton(42, ClassGroupProperties(),
293 "single"))
294 clazz.AppendGroup(ClassGroupSingleton("text", ClassGroupProperties(),
295 "single-text"))
296
297 clazz.AppendGroup(ClassGroupRange((0, 42),
298 ClassGroupProperties(),
299 "range"))
300
301 range = ClassGroupRange(Range("[0;42]"))
302 range.SetProperties(ClassGroupProperties())
303 range.SetLabel("new-range")
304 clazz.AppendGroup(range)
305
306
307 clazz = layer2.GetClassification()
308 layer2.SetClassificationColumn("POPYCOUN")
309
310 # Classification with Latin 1 text
311 clazz.AppendGroup(ClassGroupSingleton('\xe4\xf6\xfc', # ae, oe, ue
312 ClassGroupProperties(),
313 '\xdcml\xe4uts')) # Uemlaeuts
314
315
316 filename = self.temp_file_name("%s.thuban" % self.id())
317 save_session(session, filename)
318
319 file = open(filename)
320 written_contents = file.read()
321 file.close()
322 expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
323 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
324 <session title="Map with Classifications"
325 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
326 <fileshapesource id="D1"
327 filename="../../Data/iceland/political.shp"
328 filetype="shapefile"/>
329 <map title="Test Map">
330 <projection name="Unknown">
331 <parameter value="zone=26"/>
332 <parameter value="proj=utm"/>
333 <parameter value="ellps=clrk66"/>
334 </projection>
335 <layer title="My Layer" shapestore="D1"
336 fill="None" stroke="#000000" stroke_width="1" visible="true">
337 <classification field="AREA" field_type="double">
338 <clnull label="">
339 <cldata fill="None" stroke="#000000" stroke_width="1"/>
340 </clnull>
341 <clpoint value="42" label="single">
342 <cldata fill="None" stroke="#000000" stroke_width="1"/>
343 </clpoint>
344 <clpoint value="text" label="single-text">
345 <cldata fill="None" stroke="#000000" stroke_width="1"/>
346 </clpoint>
347 <clrange range="[0;42[" label="range">
348 <cldata fill="None" stroke="#000000" stroke_width="1"/>
349 </clrange>
350 <clrange range="[0;42]" label="new-range">
351 <cldata fill="None" stroke="#000000" stroke_width="1"/>
352 </clrange>
353 </classification>
354 </layer>
355 <layer title="My Layer" shapestore="D1"
356 fill="None" stroke="#000000" stroke_width="1" visible="true">
357 <classification field="POPYCOUN" field_type="string">
358 <clnull label="">
359 <cldata fill="None" stroke="#000000" stroke_width="1"/>
360 </clnull>
361 <clpoint value="\xc3\xa4\xc3\xb6\xc3\xbc"
362 label="\xc3\x9cml\xc3\xa4uts">
363 <cldata fill="None" stroke="#000000" stroke_width="1"/>
364 </clpoint>
365 </classification>
366 </layer>
367 </map>
368 </session>'''
369
370 #print written_contents
371 #print "********************************************"
372 #print expected_contents
373 self.compare_xml(written_contents, expected_contents)
374
375 self.validate_data(written_contents)
376
377 session.Destroy()
378
379 def test_dbf_table(self):
380 """Test saving a session with a dbf table link"""
381 session = self.session = Session("a DBF Table session")
382 # use shapefile from the example data
383 dbffile = os.path.join(os.path.dirname(__file__),
384 os.pardir, "Data", "iceland", "political.dbf")
385 table = session.AddTable(DBFTable(dbffile))
386
387 filename = self.temp_file_name("save_singletable.thuban")
388 save_session(session, filename)
389
390 file = open(filename)
391 written_contents = file.read()
392 file.close()
393 expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
394 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
395 <session title="a DBF Table session"
396 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
397 <filetable id="D1" filename="../../Data/iceland/political.dbf"
398 filetype="DBF" title="political"/>
399 </session>'''
400
401 self.compare_xml(written_contents, expected_contents)
402 self.validate_data(written_contents)
403
404 def test_joined_table(self):
405 """Test saving a session with joined table"""
406 # Create a simple table to use in the join
407 dbffile = self.temp_file_name("save_joinedtable.dbf")
408 dbf = dbflib.create(dbffile)
409 dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
410 dbf.add_field("TEXT", dbflib.FTString, 10, 0)
411 dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
412 dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
413 dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
414 dbf.close()
415
416 # Create the session and a map
417 session = Session("A Joined Table session")
418 try:
419 map = Map("Test Map")
420 session.AddMap(map)
421
422 # Add the dbf file to the session
423 dbftable = session.AddTable(DBFTable(dbffile))
424
425 # Create a layer with the shapefile to use in the join
426 shpfile = os.path.join(os.path.abspath(os.path.dirname(__file__)),
427 os.pardir, "Data", "iceland",
428 "roads-line.shp")
429 layer = Layer("My Layer", session.OpenShapefile(shpfile))
430 map.AddLayer(layer)
431
432 # Do the join
433 store = layer.ShapeStore()
434 #for col in store.Table().Columns():
435 # print col.name
436 joined = TransientJoinedTable(session.TransientDB(),
437 store.Table(), "RDLNTYPE",
438 dbftable, "RDTYPE",
439 outer_join = True)
440 store = session.AddShapeStore(DerivedShapeStore(store, joined))
441 layer.SetShapeStore(store)
442
443 # Save the session
444 filename = self.temp_file_name("save_joinedtable.thuban")
445 save_session(session, filename)
446
447 # Read it back and compare
448 file = open(filename)
449 written_contents = file.read()
450 file.close()
451 expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
452 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
453 <session title="A Joined Table session"
454 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
455 <fileshapesource filename="../../Data/iceland/roads-line.shp"
456 filetype="shapefile" id="D142197204"/>
457 <filetable filename="save_joinedtable.dbf"
458 title="save_joinedtable"
459 filetype="DBF" id="D141881756"/>
460 <jointable id="D142180284"
461 title="Join of roads-line and save_joinedtable"
462 leftcolumn="RDLNTYPE" left="D142197204"
463 rightcolumn="RDTYPE" right="D141881756"
464 jointype="LEFT OUTER" />
465 <derivedshapesource id="D141915644"
466 table="D142180284"
467 shapesource="D142197204"/>
468 <map title="Test Map">
469 <layer title="My Layer"
470 shapestore="D141915644" visible="true"
471 stroke="#000000" stroke_width="1" fill="None"/>
472 </map>
473 </session>'''
474
475 self.compare_xml(written_contents, expected_contents)
476 self.validate_data(written_contents)
477 finally:
478 session.Destroy()
479 session = None
480
481
482 def test_save_postgis(self):
483 """Test saving a session with a postgis connection"""
484
485 class NonConnection(PostGISConnection):
486 """connection class that doesn't actually connect """
487 def connect(self):
488 pass
489
490 class NonConnectionStore(PostGISShapeStore):
491 """Shapestore that doesn't try to access the server"""
492 def _fetch_table_information(self):
493 # pretend that we've found a geometry column
494 self.geometry_column = "the_geom"
495 def IDColumn(self):
496 """Return an object with a name attribute with value 'gid'"""
497 class dummycol:
498 name = "gid"
499 return dummycol
500
501 session = Session("A PostGIS Session")
502 try:
503 dbconn = NonConnection(dbname="plugh", host="xyzzy", port="42",
504 user="grue")
505 session.AddDBConnection(dbconn)
506 map = Map("Test Map")
507 session.AddMap(map)
508 store = NonConnectionStore(dbconn, "roads")
509 session.AddShapeStore(store)
510 layer = Layer("Roads to Nowhere", store)
511 map.AddLayer(layer)
512
513 # Save the session
514 filename = self.temp_file_name(self.id() + ".thuban")
515 save_session(session, filename)
516
517 # Read it back and compare
518 file = open(filename)
519 written = file.read()
520 file.close()
521 expected = '''<?xml version="1.0" encoding="UTF-8"?>
522 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
523 <session title="A PostGIS Session"
524 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
525 <dbconnection id="DB"
526 dbtype="postgis" dbname="plugh"
527 host="xyzzy" port="42"
528 user="grue"/>
529 <dbshapesource id="roads" dbconn="DB" tablename="roads"
530 id_column="gid" geometry_column="the_geom"/>
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