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

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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1245 by bh, Thu Jun 19 19:29:23 2003 UTC revision 1599 by bh, Mon Aug 18 12:45:28 2003 UTC
# Line 26  import xmlsupport Line 26  import xmlsupport
26  import support  import support
27  support.initthuban()  support.initthuban()
28    
29  from Thuban.Model.save import XMLWriter, save_session  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  from Thuban.Model.session import Session
34  from Thuban.Model.map import Map  from Thuban.Model.map import Map
35  from Thuban.Model.layer import Layer, RasterLayer  from Thuban.Model.layer import Layer, RasterLayer
36  from Thuban.Model.proj import Projection  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, \  from Thuban.Model.classification import ClassGroupSingleton, ClassGroupRange, \
42      ClassGroupProperties      ClassGroupProperties
# Line 38  from Thuban.Model.classification import Line 44  from Thuban.Model.classification import
44  from Thuban.Model.range import Range  from Thuban.Model.range import Range
45    
46    
 class SaxEventLister(xml.sax.handler.ContentHandler):  
   
     def __init__(self):  
         self.eventlist = []  
   
     def startElementNS(self, name, qname, attrs):  
         items = attrs.items()  
         items.sort()  
         self.eventlist.append(("start", name, qname, items))  
   
     def endElementNS(self, name, qname):  
         self.eventlist.append(("end", name, qname))  
   
   
 def sax_eventlist(data):  
     """Return a list of SAX event generated for the XML data.  
     """  
     handler = SaxEventLister()  
     parser = make_parser()  
     parser.setContentHandler(handler)  
     parser.setErrorHandler(ErrorHandler())  
     parser.setFeature(xml.sax.handler.feature_namespaces, 1)  
   
     #  
     # see comment at the end of Thuban/Model/load.py  
     #  
     try:  
         parser.setFeature(xml.sax.handler.feature_validation, 0)  
         parser.setFeature(xml.sax.handler.feature_external_ges, 0)  
         parser.setFeature(xml.sax.handler.feature_external_pes, 0)  
     except SAXNotRecognizedException:  
         pass  
   
     inpsrc = xml.sax.InputSource()  
     inpsrc.setByteStream(StringIO(data))  
     parser.parse(inpsrc)  
   
     return handler.eventlist  
   
47  class XMLWriterTest(unittest.TestCase):  class XMLWriterTest(unittest.TestCase):
48    
49      def testEncode(self):      def testEncode(self):
# Line 99  class XMLWriterTest(unittest.TestCase): Line 66  class XMLWriterTest(unittest.TestCase):
66  class SaveSessionTest(unittest.TestCase, support.FileTestMixin,  class SaveSessionTest(unittest.TestCase, support.FileTestMixin,
67                        xmlsupport.ValidationTest):                        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):      def compare_xml(self, xml1, xml2):
82          self.assertEquals(sax_eventlist(xml1), sax_eventlist(xml2))          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):      def testEmptySession(self):
93          """Save an empty session"""          """Save an empty session"""
# Line 114  class SaveSessionTest(unittest.TestCase, Line 101  class SaveSessionTest(unittest.TestCase,
101          file.close()          file.close()
102          self.compare_xml(written_contents,          self.compare_xml(written_contents,
103                           '<?xml version="1.0" encoding="UTF-8"?>\n'                           '<?xml version="1.0" encoding="UTF-8"?>\n'
104                           '<!DOCTYPE session SYSTEM "thuban.dtd">\n'                           '<!DOCTYPE session SYSTEM "thuban-0.9.dtd">\n'
105                           '<session title="empty session">\n</session>\n')                           '<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)          self.validate_data(written_contents)
110    
# Line 139  class SaveSessionTest(unittest.TestCase, Line 128  class SaveSessionTest(unittest.TestCase,
128          written_contents = file.read()          written_contents = file.read()
129          file.close()          file.close()
130          expected_template = '''<?xml version="1.0" encoding="UTF-8"?>          expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
131          <!DOCTYPE session SYSTEM "thuban.dtd">          <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
132          <session title="single map&amp;layer">          <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">              <map title="Test Map">
136                  <projection name="Unknown">                  <projection name="Unknown">
137                      <parameter value="zone=26"/>                      <parameter value="zone=26"/>
138                      <parameter value="proj=utm"/>                      <parameter value="proj=utm"/>
139                      <parameter value="ellps=clrk66"/>                      <parameter value="ellps=clrk66"/>
140                  </projection>                  </projection>
141                  <layer title="My Layer" filename="%s"                  <layer title="My Layer" shapestore="D1"
142                  fill="None" stroke="#000000" stroke_width="1" visible="%s"/>                  fill="None" stroke="#000000" stroke_width="1" visible="%s"/>
143              </map>              </map>
144          </session>'''          </session>'''
145            
146          expected_contents = expected_template % \          expected_contents = expected_template % \
147              (os.path.join("..", "..", "Data", "iceland", "political.shp"),              (os.path.join("..", "..", "Data", "iceland", "political.shp"),
148               "true")               "true")
149    
         #print written_contents  
         #print "********************************************"  
         #print expected_contents  
150          self.compare_xml(written_contents, expected_contents)          self.compare_xml(written_contents, expected_contents)
151    
152          self.validate_data(written_contents)          self.validate_data(written_contents)
# Line 172  class SaveSessionTest(unittest.TestCase, Line 160  class SaveSessionTest(unittest.TestCase,
160          expected_contents = expected_template % \          expected_contents = expected_template % \
161              (os.path.join("..", "..", "Data", "iceland", "political.shp"),              (os.path.join("..", "..", "Data", "iceland", "political.shp"),
162               "false")               "false")
   
         #print written_contents  
         #print "********************************************"  
         #print expected_contents  
163          self.compare_xml(written_contents, expected_contents)          self.compare_xml(written_contents, expected_contents)
164          self.validate_data(written_contents)          self.validate_data(written_contents)
165    
166          session.Destroy()          session.Destroy()
167    
168      def testLayerProjection(self):      def testLayerProjection(self):
169            """Test saving layers with projections"""
170          # deliberately put an apersand in the title :)          # deliberately put an apersand in the title :)
171          session = Session("single map&layer")          session = Session("single map&layer")
172          proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])          proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
# Line 195  class SaveSessionTest(unittest.TestCase, Line 180  class SaveSessionTest(unittest.TestCase,
180          layer.SetProjection(proj)          layer.SetProjection(proj)
181          map.AddLayer(layer)          map.AddLayer(layer)
182    
183          filename = self.temp_file_name("save_singlemap.thuban")          filename = self.temp_file_name("save_layerproj.thuban")
184          save_session(session, filename)          save_session(session, filename)
185          session.Destroy()          session.Destroy()
186    
# Line 203  class SaveSessionTest(unittest.TestCase, Line 188  class SaveSessionTest(unittest.TestCase,
188          written_contents = file.read()          written_contents = file.read()
189          file.close()          file.close()
190          expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>          expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
191          <!DOCTYPE session SYSTEM "thuban.dtd">          <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
192          <session title="single map&amp;layer">          <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">              <map title="Test Map">
196                  <projection name="Unknown">                  <projection name="Unknown">
197                      <parameter value="zone=26"/>                      <parameter value="zone=26"/>
198                      <parameter value="proj=utm"/>                      <parameter value="proj=utm"/>
199                      <parameter value="ellps=clrk66"/>                      <parameter value="ellps=clrk66"/>
200                  </projection>                  </projection>
201                  <layer title="My Layer" filename="%s"                  <layer title="My Layer" shapestore="D1"
202                  fill="None" stroke="#000000" stroke_width="1" visible="true">                  fill="None" stroke="#000000" stroke_width="1" visible="true">
203                      <projection name="Layer Projection">                      <projection name="Layer Projection">
204                          <parameter value="proj=lcc"/>                          <parameter value="proj=lcc"/>
# Line 239  class SaveSessionTest(unittest.TestCase, Line 226  class SaveSessionTest(unittest.TestCase,
226          layer = RasterLayer("My RasterLayer", imgfile)          layer = RasterLayer("My RasterLayer", imgfile)
227          map.AddLayer(layer)          map.AddLayer(layer)
228    
229          filename = self.temp_file_name("save_singlemap.thuban")          filename = self.temp_file_name("%s.thuban" % self.id())
230          save_session(session, filename)          save_session(session, filename)
231          session.Destroy()          session.Destroy()
232    
# Line 247  class SaveSessionTest(unittest.TestCase, Line 234  class SaveSessionTest(unittest.TestCase,
234          written_contents = file.read()          written_contents = file.read()
235          file.close()          file.close()
236          expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>          expected_contents = '''<?xml version="1.0" encoding="UTF-8"?>
237          <!DOCTYPE session SYSTEM "thuban.dtd">          <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
238          <session title="single map&amp;layer">          <session title="single map&amp;layer"
239               xmlns="http://thuban.intevation.org/dtds/thuban-0.9-dev.dtd">
240              <map title="Test Map">              <map title="Test Map">
241                  <rasterlayer title="My RasterLayer" filename="%s"                  <rasterlayer title="My RasterLayer" filename="%s"
242                               visible="true">                               visible="true">
243                  </rasterlayer>                  </rasterlayer>
244              </map>              </map>
245          </session>''' % os.path.join(os.path.dirname(__file__),          </session>''' % os.path.join(os.pardir, os.pardir, "Data", "iceland",
                                      os.pardir, "Data", "iceland",  
246                                       "island.tif")                                       "island.tif")
247          #print written_contents          #print written_contents
248          #print "********************************************"          #print "********************************************"
# Line 265  class SaveSessionTest(unittest.TestCase, Line 252  class SaveSessionTest(unittest.TestCase,
252          self.validate_data(written_contents)          self.validate_data(written_contents)
253    
254      def testClassifiedLayer(self):      def testClassifiedLayer(self):
255          """Save a session with a single map with a single layer          """Save a session with a single map with classifications"""
            with a classificaton.  
         """  
256          # deliberately put an apersand in the title :)          # deliberately put an apersand in the title :)
257          session = Session("single map&layer")          session = Session("Map with Classifications")
258          proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])          proj = Projection(["zone=26", "proj=utm", "ellps=clrk66"])
259          map = Map("Test Map", projection = proj)          map = Map("Test Map", projection = proj)
260          session.AddMap(map)          session.AddMap(map)
# Line 278  class SaveSessionTest(unittest.TestCase, Line 263  class SaveSessionTest(unittest.TestCase,
263                                 os.pardir, "Data", "iceland", "political.shp")                                 os.pardir, "Data", "iceland", "political.shp")
264          layer = Layer("My Layer", session.OpenShapefile(shpfile))          layer = Layer("My Layer", session.OpenShapefile(shpfile))
265          map.AddLayer(layer)          map.AddLayer(layer)
266            layer2 = Layer("My Layer", layer.ShapeStore())
267            map.AddLayer(layer2)
268    
269          clazz = layer.GetClassification()          clazz = layer.GetClassification()
270    
271          clazz.SetField("AREA")          layer.SetClassificationColumn("AREA")
272    
273          clazz.AppendGroup(ClassGroupSingleton(42,          clazz.AppendGroup(ClassGroupSingleton(42, ClassGroupProperties(),
274                                             ClassGroupProperties(),                                                "single"))
275                                             "single"))          clazz.AppendGroup(ClassGroupSingleton("text", ClassGroupProperties(),
276          clazz.AppendGroup(ClassGroupSingleton("text",                                                "single-text"))
                                            ClassGroupProperties(),  
                                            "single-text"))  
277    
278          clazz.AppendGroup(ClassGroupRange(0, 42,          clazz.AppendGroup(ClassGroupRange((0, 42),
279                                             ClassGroupProperties(),                                             ClassGroupProperties(),
280                                             "range"))                                             "range"))
281    
# Line 299  class SaveSessionTest(unittest.TestCase, Line 284  class SaveSessionTest(unittest.TestCase,
284          range.SetLabel("new-range")          range.SetLabel("new-range")
285          clazz.AppendGroup(range)          clazz.AppendGroup(range)
286    
287          filename = self.temp_file_name("save_singlemap.thuban")  
288            clazz = layer2.GetClassification()
289            layer2.SetClassificationColumn("POPYCOUN")
290    
291            # Classification with Latin 1 text
292            clazz.AppendGroup(ClassGroupSingleton('\xe4\xf6\xfc', # ae, oe, ue
293                                                  ClassGroupProperties(),
294                                                  '\xdcml\xe4uts')) # Uemlaeuts
295    
296    
297            filename = self.temp_file_name("%s.thuban" % self.id())
298          save_session(session, filename)          save_session(session, filename)
299    
300          file = open(filename)          file = open(filename)
301          written_contents = file.read()          written_contents = file.read()
302          file.close()          file.close()
303          expected_template = '''<?xml version="1.0" encoding="UTF-8"?>          expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
304          <!DOCTYPE session SYSTEM "thuban.dtd">          <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
305          <session title="single map&amp;layer">          <session title="Map with Classifications"
306               xmlns="http://thuban.intevation.org/dtds/thuban-0.9-dev.dtd">
307                <fileshapesource id="D1" filename="%s" filetype="shapefile"/>
308              <map title="Test Map">              <map title="Test Map">
309                  <projection name="Unknown">                  <projection name="Unknown">
310                      <parameter value="zone=26"/>                      <parameter value="zone=26"/>
311                      <parameter value="proj=utm"/>                      <parameter value="proj=utm"/>
312                      <parameter value="ellps=clrk66"/>                      <parameter value="ellps=clrk66"/>
313                  </projection>                  </projection>
314                  <layer title="My Layer" filename="%s"                  <layer title="My Layer" shapestore="D1"
315                  fill="None" stroke="#000000" stroke_width="1" visible="%s">                  fill="None" stroke="#000000" stroke_width="1" visible="%s">
316                      <classification field="AREA" field_type="double">                      <classification field="AREA" field_type="double">
317                          <clnull label="">                          <clnull label="">
# Line 334  class SaveSessionTest(unittest.TestCase, Line 331  class SaveSessionTest(unittest.TestCase,
331                          </clrange>                          </clrange>
332                      </classification>                      </classification>
333                  </layer>                  </layer>
334                    <layer title="My Layer" shapestore="D1"
335                    fill="None" stroke="#000000" stroke_width="1" visible="true">
336                        <classification field="POPYCOUN" field_type="string">
337                            <clnull label="">
338                                <cldata fill="None" stroke="#000000" stroke_width="1"/>
339                            </clnull>
340                            <clpoint value="\xc3\xa4\xc3\xb6\xc3\xbc"
341                                 label="\xc3\x9cml\xc3\xa4uts">
342                                <cldata fill="None" stroke="#000000" stroke_width="1"/>
343                            </clpoint>
344                        </classification>
345                    </layer>
346              </map>              </map>
347          </session>'''          </session>'''
348    
# Line 350  class SaveSessionTest(unittest.TestCase, Line 359  class SaveSessionTest(unittest.TestCase,
359    
360          session.Destroy()          session.Destroy()
361    
362        def test_dbf_table(self):
363            """Test saving a session with a dbf table link"""
364            session = Session("a DBF Table session")
365            # use shapefile from the example data
366            dbffile = os.path.join(os.path.dirname(__file__),
367                                   os.pardir, "Data", "iceland", "political.dbf")
368            table = session.AddTable(DBFTable(dbffile))
369    
370            filename = self.temp_file_name("save_singletable.thuban")
371            save_session(session, filename)
372    
373            file = open(filename)
374            written_contents = file.read()
375            file.close()
376            expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
377            <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
378            <session title="a DBF Table session"
379               xmlns="http://thuban.intevation.org/dtds/thuban-0.9-dev.dtd">
380                <filetable id="D1" filename="%s" filetype="DBF" title="political"/>
381            </session>'''
382    
383            expected_contents = (expected_template
384                                 % os.path.join(os.pardir, os.pardir, "Data",
385                                                "iceland", "political.dbf"))
386            self.compare_xml(written_contents, expected_contents)
387    
388        def test_joined_table(self):
389            """Test saving a session with joined table"""
390            # Create a simple table to use in the join
391            dbffile = self.temp_file_name("save_joinedtable.dbf")
392            dbf = dbflib.create(dbffile)
393            dbf.add_field("RDTYPE", dbflib.FTInteger, 10, 0)
394            dbf.add_field("TEXT", dbflib.FTString, 10, 0)
395            dbf.write_record(0, {'RDTYPE': 8, "TEXT": "foo"})
396            dbf.write_record(1, {'RDTYPE': 2, "TEXT": "bar"})
397            dbf.write_record(2, {'RDTYPE': 3, "TEXT": "baz"})
398            dbf.close()
399    
400            # Create the session and a map
401            session = Session("A Joined Table session")
402            try:
403                map = Map("Test Map")
404                session.AddMap(map)
405    
406                # Add the dbf file to the session
407                dbftable = session.AddTable(DBFTable(dbffile))
408    
409                # Create a layer with the shapefile to use in the join
410                shpfile = os.path.join(os.path.abspath(os.path.dirname(__file__)),
411                                       os.pardir, "Data", "iceland",
412                                       "roads-line.shp")
413                layer = Layer("My Layer", session.OpenShapefile(shpfile))
414                map.AddLayer(layer)
415    
416                # Do the join
417                store = layer.ShapeStore()
418                #for col in store.Table().Columns():
419                #    print col.name
420                joined = TransientJoinedTable(session.TransientDB(),
421                                              store.Table(), "RDLNTYPE",
422                                              dbftable, "RDTYPE",
423                                              outer_join = True)
424                store = session.AddShapeStore(DerivedShapeStore(store, joined))
425                layer.SetShapeStore(store)
426    
427                # Save the session
428                filename = self.temp_file_name("save_joinedtable.thuban")
429                save_session(session, filename)
430    
431                # Read it back and compare
432                file = open(filename)
433                written_contents = file.read()
434                file.close()
435                expected_template = '''<?xml version="1.0" encoding="UTF-8"?>
436                <!DOCTYPE session SYSTEM "thuban-0.9.dtd">
437                <session title="A Joined Table session"
438                 xmlns="http://thuban.intevation.org/dtds/thuban-0.9-dev.dtd">
439                    <fileshapesource filename="%(shpfile)s"
440                                     filetype="shapefile" id="D142197204"/>
441                    <filetable filename="%(dbffile)s"
442                               title="save_joinedtable"
443                               filetype="DBF" id="D141881756"/>
444                    <jointable id="D142180284"
445                               title="Join of roads-line and save_joinedtable"
446                               leftcolumn="RDLNTYPE" left="D142197204"
447                               rightcolumn="RDTYPE" right="D141881756"
448                               jointype="LEFT OUTER" />
449                    <derivedshapesource id="D141915644"
450                                        table="D142180284"
451                                        shapesource="D142197204"/>
452                    <map title="Test Map">
453                        <layer title="My Layer"
454                               shapestore="D141915644" visible="true"
455                               stroke="#000000" stroke_width="1" fill="None"/>
456                    </map>
457                </session>'''
458    
459                expected_contents = expected_template % {
460                    "dbffile": relative_filename(self.temp_dir(), dbffile),
461                    "shpfile": relative_filename(self.temp_dir(), shpfile)
462                    }
463                self.compare_xml(written_contents, expected_contents)
464            finally:
465                session.Destroy()
466                session = None
467    
468    
469    class MockDataStore:
470    
471        """A very simple data store that only has dependencies"""
472    
473        def __init__(self, name, *dependencies):
474            self.name = name
475            self.dependencies = dependencies
476    
477        def __repr__(self):
478            return self.name
479    
480        def Dependencies(self):
481            return self.dependencies
482    
483    
484    class TestStoreSort(unittest.TestCase):
485    
486        def check_sort(self, containers, sorted):
487            """Check whether the list of data containers is sorted"""
488            # check whether sorted is in the right order
489            seen = {}
490            for container in sorted:
491                self.failIf(id(container) in seen,
492                            "Container %r at least twice in %r" % (container,
493                                                                   sorted))
494                for dep in container.Dependencies():
495                    self.assert_(id(dep) in seen,
496                                 "Dependency %r of %r not yet seen" % (dep,
497                                                                       container))
498                seen[id(container)] = 1
499            # check whether all of containers is in sorted
500            for container in containers:
501                self.assert_(id(container) in seen,
502                             "Container %r in containers but not in sorted")
503            self.assertEquals(len(containers), len(sorted))
504    
505        def test_sort_data_stores(self):
506            """Test Thuban.Model.save.sort_data_stores"""
507            d1 = MockDataStore("d1")
508            d2 = MockDataStore("d2")
509            d3 = MockDataStore("d3", d1)
510            d4 = MockDataStore("d4", d1, d3)
511    
512            containers = [d4, d1, d2, d3]
513            self.check_sort(containers, sort_data_stores(containers))
514            containers = [d1, d3, d2, d4]
515            self.check_sort(containers, sort_data_stores(containers))
516    
517    
518    
519  if __name__ == "__main__":  if __name__ == "__main__":
520      # Fake the __file__ global because it's needed by a test      # Fake the __file__ global because it's needed by a test

Legend:
Removed from v.1245  
changed lines
  Added in v.1599

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26