/[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 2552 - (show annotations)
Fri Jan 28 15:54:00 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: 24077 byte(s)
Make layer's use_mask flag default to true. Support a bit array describing
the mask to use. Improve error handling in ProjectRasterFile (also addresses
RT #2947).

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 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.1.dtd">
256 <session title="single map&amp;layer"
257 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
258 <map title="Test Map">
259 <rasterlayer title="My RasterLayer"
260 filename="../../Data/iceland/island.tif"
261 visible="true">
262 </rasterlayer>
263 </map>
264 </session>'''
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_contents = '''<?xml version="1.0" encoding="UTF-8"?>
322 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
323 <session title="Map with Classifications"
324 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
325 <fileshapesource id="D1"
326 filename="../../Data/iceland/political.shp"
327 filetype="shapefile"/>
328 <map title="Test Map">
329 <projection name="Unknown">
330 <parameter value="zone=26"/>
331 <parameter value="proj=utm"/>
332 <parameter value="ellps=clrk66"/>
333 </projection>
334 <layer title="My Layer" shapestore="D1"
335 fill="None" stroke="#000000" stroke_width="1" visible="true">
336 <classification field="AREA" field_type="double">
337 <clnull label="">
338 <cldata fill="None" stroke="#000000" stroke_width="1"/>
339 </clnull>
340 <clpoint value="42" label="single">
341 <cldata fill="None" stroke="#000000" stroke_width="1"/>
342 </clpoint>
343 <clpoint value="text" label="single-text">
344 <cldata fill="None" stroke="#000000" stroke_width="1"/>
345 </clpoint>
346 <clrange range="[0;42[" label="range">
347 <cldata fill="None" stroke="#000000" stroke_width="1"/>
348 </clrange>
349 <clrange range="[0;42]" label="new-range">
350 <cldata fill="None" stroke="#000000" stroke_width="1"/>
351 </clrange>
352 </classification>
353 </layer>
354 <layer title="My Layer" shapestore="D1"
355 fill="None" stroke="#000000" stroke_width="1" visible="true">
356 <classification field="POPYCOUN" field_type="string">
357 <clnull label="">
358 <cldata fill="None" stroke="#000000" stroke_width="1"/>
359 </clnull>
360 <clpoint value="\xc3\xa4\xc3\xb6\xc3\xbc"
361 label="\xc3\x9cml\xc3\xa4uts">
362 <cldata fill="None" stroke="#000000" stroke_width="1"/>
363 </clpoint>
364 </classification>
365 </layer>
366 </map>
367 </session>'''
368
369 #print written_contents
370 #print "********************************************"
371 #print expected_contents
372 self.compare_xml(written_contents, expected_contents)
373
374 self.validate_data(written_contents)
375
376 session.Destroy()
377
378 def test_dbf_table(self):
379 """Test saving a session with a dbf table link"""
380 session = self.session = Session("a DBF Table session")
381 # use shapefile from the example data
382 dbffile = os.path.join(os.path.dirname(__file__),
383 os.pardir, "Data", "iceland", "political.dbf")
384 table = session.AddTable(DBFTable(dbffile))
385
386 filename = self.temp_file_name("save_singletable.thuban")
387 save_session(session, filename)
388
389 file = open(filename)
390 written_contents = file.read()
391 file.close()
392 expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
393 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
394 <session title="a DBF Table session"
395 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
396 <filetable id="D1" filename="../../Data/iceland/political.dbf"
397 filetype="DBF" title="political"/>
398 </session>'''
399
400 self.compare_xml(written_contents, expected_contents)
401 self.validate_data(written_contents)
402
403 def test_joined_table(self):
404 """Test saving a session with joined table"""
405 # Create a simple table to use in the join
406 dbffile = self.temp_file_name("save_joinedtable.dbf")
407 dbf = dbflib.create(dbffile)
408 dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
409 dbf.add_field("TEXT", dbflib.FTString, 10, 0)
410 dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
411 dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
412 dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
413 dbf.close()
414
415 # Create the session and a map
416 session = Session("A Joined Table session")
417 try:
418 map = Map("Test Map")
419 session.AddMap(map)
420
421 # Add the dbf file to the session
422 dbftable = session.AddTable(DBFTable(dbffile))
423
424 # Create a layer with the shapefile to use in the join
425 shpfile = os.path.join(os.path.abspath(os.path.dirname(__file__)),
426 os.pardir, "Data", "iceland",
427 "roads-line.shp")
428 layer = Layer("My Layer", session.OpenShapefile(shpfile))
429 map.AddLayer(layer)
430
431 # Do the join
432 store = layer.ShapeStore()
433 #for col in store.Table().Columns():
434 # print col.name
435 joined = TransientJoinedTable(session.TransientDB(),
436 store.Table(), "RDLNTYPE",
437 dbftable, "RDTYPE",
438 outer_join = True)
439 store = session.AddShapeStore(DerivedShapeStore(store, joined))
440 layer.SetShapeStore(store)
441
442 # Save the session
443 filename = self.temp_file_name("save_joinedtable.thuban")
444 save_session(session, filename)
445
446 # Read it back and compare
447 file = open(filename)
448 written_contents = file.read()
449 file.close()
450 expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
451 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
452 <session title="A Joined Table session"
453 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
454 <fileshapesource filename="../../Data/iceland/roads-line.shp"
455 filetype="shapefile" id="D142197204"/>
456 <filetable filename="save_joinedtable.dbf"
457 title="save_joinedtable"
458 filetype="DBF" id="D141881756"/>
459 <jointable id="D142180284"
460 title="Join of roads-line and save_joinedtable"
461 leftcolumn="RDLNTYPE" left="D142197204"
462 rightcolumn="RDTYPE" right="D141881756"
463 jointype="LEFT OUTER" />
464 <derivedshapesource id="D141915644"
465 table="D142180284"
466 shapesource="D142197204"/>
467 <map title="Test Map">
468 <layer title="My Layer"
469 shapestore="D141915644" visible="true"
470 stroke="#000000" stroke_width="1" fill="None"/>
471 </map>
472 </session>'''
473
474 self.compare_xml(written_contents, expected_contents)
475 self.validate_data(written_contents)
476 finally:
477 session.Destroy()
478 session = None
479
480
481 def test_save_postgis(self):
482 """Test saving a session with a postgis connection"""
483
484 class NonConnection(PostGISConnection):
485 """connection class that doesn't actually connect """
486 def connect(self):
487 pass
488
489 class NonConnectionStore(PostGISShapeStore):
490 """Shapestore that doesn't try to access the server"""
491 def _fetch_table_information(self):
492 # pretend that we've found a geometry column
493 self.geometry_column = "the_geom"
494 def IDColumn(self):
495 """Return an object with a name attribute with value 'gid'"""
496 class dummycol:
497 name = "gid"
498 return dummycol
499
500 session = Session("A PostGIS Session")
501 try:
502 dbconn = NonConnection(dbname="plugh", host="xyzzy", port="42",
503 user="grue")
504 session.AddDBConnection(dbconn)
505 map = Map("Test Map")
506 session.AddMap(map)
507 store = NonConnectionStore(dbconn, "roads")
508 session.AddShapeStore(store)
509 layer = Layer("Roads to Nowhere", store)
510 map.AddLayer(layer)
511
512 # Save the session
513 filename = self.temp_file_name(self.id() + ".thuban")
514 save_session(session, filename)
515
516 # Read it back and compare
517 file = open(filename)
518 written = file.read()
519 file.close()
520 expected = '''<?xml version="1.0" encoding="UTF-8"?>
521 <!DOCTYPE session SYSTEM "thuban-1.1.dtd">
522 <session title="A PostGIS Session"
523 xmlns="http://thuban.intevation.org/dtds/thuban-1.1-dev.dtd">
524 <dbconnection id="DB"
525 dbtype="postgis" dbname="plugh"
526 host="xyzzy" port="42"
527 user="grue"/>
528 <dbshapesource id="roads" dbconn="DB" tablename="roads"
529 id_column="gid" geometry_column="the_geom"/>
530 <map title="Test Map">
531 <layer title="Roads to Nowhere"
532 shapestore="roads" visible="true"
533 stroke="#000000" stroke_width="1" fill="None"/>
534 </map>
535 </session>'''
536 self.compare_xml(written, expected)
537 self.validate_data(written)
538 finally:
539 session.Destroy()
540
541
542 class MockDataStore:
543
544 """A very simple data store that only has dependencies"""
545
546 def __init__(self, name, *dependencies):
547 self.name = name
548 self.dependencies = dependencies
549
550 def __repr__(self):
551 return self.name
552
553 def Dependencies(self):
554 return self.dependencies
555
556
557 class TestStoreSort(unittest.TestCase):
558
559 def check_sort(self, containers, sorted):
560 """Check whether the list of data containers is sorted"""
561 # check whether sorted is in the right order
562 seen = {}
563 for container in sorted:
564 self.failIf(id(container) in seen,
565 "Container %r at least twice in %r" % (container,
566 sorted))
567 for dep in container.Dependencies():
568 self.assert_(id(dep) in seen,
569 "Dependency %r of %r not yet seen" % (dep,
570 container))
571 seen[id(container)] = 1
572 # check whether all of containers is in sorted
573 for container in containers:
574 self.assert_(id(container) in seen,
575 "Container %r in containers but not in sorted")
576 self.assertEquals(len(containers), len(sorted))
577
578 def test_sort_data_stores(self):
579 """Test Thuban.Model.save.sort_data_stores"""
580 d1 = MockDataStore("d1")
581 d2 = MockDataStore("d2")
582 d3 = MockDataStore("d3", d1)
583 d4 = MockDataStore("d4", d1, d3)
584
585 containers = [d4, d1, d2, d3]
586 self.check_sort(containers, sort_data_stores(containers))
587 containers = [d1, d3, d2, d4]
588 self.check_sort(containers, sort_data_stores(containers))
589
590
591
592 if __name__ == "__main__":
593 # Fake the __file__ global because it's needed by a test
594 import sys
595 __file__ = sys.argv[0]
596 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