/[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 1417 - (show annotations)
Tue Jul 15 08:43:53 2003 UTC (21 years, 7 months ago) by bh
Original Path: trunk/thuban/test/test_save.py
File MIME type: text/x-python
File size: 21148 byte(s)
* Thuban/Model/save.py (SessionSaver.write_classification): Encode
string values (in addition to the labels) as UTF 8

* Thuban/Model/load.py (SessionLoader.start_clpoint): Decode the
values if the field type is string

* test/test_save.py (SaveSessionTest.testClassifiedLayer): Test
saving a session with non-ascii string classification values.

* test/test_load.py (TestClassification.file_contents)
(TestClassification.test): Check for non-ascii values in string
classifications

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