/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/Model/load.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/Thuban/Model/load.py

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

revision 1354 by jonathan, Wed Jul 2 09:37:07 2003 UTC revision 1664 by bh, Wed Aug 27 15:20:54 2003 UTC
# Line 38  from Thuban.Model.data import DerivedSha Line 38  from Thuban.Model.data import DerivedSha
38  from Thuban.Model.table import DBFTable  from Thuban.Model.table import DBFTable
39  from Thuban.Model.transientdb import TransientJoinedTable  from Thuban.Model.transientdb import TransientJoinedTable
40    
41    from Thuban.Model.xmlreader import XMLReader
42    import resource
43    
44    import postgisdb
45    
46  class LoadError(Exception):  class LoadError(Exception):
     pass  
47    
48  from Thuban.Model.xmlreader import XMLReader      """Exception raised when the thuban file is corrupted
49  import resource  
50        Not all cases of corrupted thuban files will lead to this exception
51        but those that are found by checks in the loading code itself are.
52        """
53    
54    
55    class LoadCancelled(Exception):
56    
57        """Exception raised to indicate that loading was interrupted by the user"""
58    
59    
60  def parse_color(color):  def parse_color(color):
61      """Return the color object for the string color.      """Return the color object for the string color.
# Line 87  class AttrDesc: Line 100  class AttrDesc:
100    
101  class SessionLoader(XMLReader):  class SessionLoader(XMLReader):
102    
103      def __init__(self):      def __init__(self, db_connection_callback = None):
104          """Inititialize the Sax handler."""          """Inititialize the Sax handler."""
105          XMLReader.__init__(self)          XMLReader.__init__(self)
106    
107            self.db_connection_callback = db_connection_callback
108    
109          self.theSession = None          self.theSession = None
110          self.aMap = None          self.aMap = None
111          self.aLayer = None          self.aLayer = None
# Line 101  class SessionLoader(XMLReader): Line 116  class SessionLoader(XMLReader):
116    
117          dispatchers = {          dispatchers = {
118              'session'       : ("start_session",        "end_session"),              'session'       : ("start_session",        "end_session"),
119    
120                'dbconnection': ("start_dbconnection", None),
121    
122                'dbshapesource': ("start_dbshapesource", None),
123              'fileshapesource': ("start_fileshapesource", None),              'fileshapesource': ("start_fileshapesource", None),
124              'derivedshapesource': ("start_derivedshapesource", None),              'derivedshapesource': ("start_derivedshapesource", None),
125              'filetable': ("start_filetable", None),              'filetable': ("start_filetable", None),
# Line 120  class SessionLoader(XMLReader): Line 139  class SessionLoader(XMLReader):
139              'labellayer'    : ("start_labellayer",     None),              'labellayer'    : ("start_labellayer",     None),
140              'label'         : ("start_label",          None)}              'label'         : ("start_label",          None)}
141    
142          # all dispatchers should be used for the 0.8 namespace          # all dispatchers should be used for the 0.8 and 0.9 namespaces too
143          xmlns = "http://thuban.intevation.org/dtds/thuban-0.8.dtd"          for xmlns in ("http://thuban.intevation.org/dtds/thuban-0.8.dtd",
144          for key, value in dispatchers.items():                        "http://thuban.intevation.org/dtds/thuban-0.9-dev.dtd",
145              dispatchers[(xmlns, key)] = value                        "http://thuban.intevation.org/dtds/thuban-0.9.dtd"):
146                for key, value in dispatchers.items():
147                    dispatchers[(xmlns, key)] = value
148    
149          XMLReader.AddDispatchers(self, dispatchers)          XMLReader.AddDispatchers(self, dispatchers)
150    
# Line 172  class SessionLoader(XMLReader): Line 193  class SessionLoader(XMLReader):
193                        defined earlier in the .thuban file. Look it up                        defined earlier in the .thuban file. Look it up
194                        self.idmap. If it's the ID of a shapestore the                        self.idmap. If it's the ID of a shapestore the
195                        value will be the table of the shapestore.                        value will be the table of the shapestore.
196    
197               'idref' -- The attribute is the id of an object defined
198                          earlier in the .thuban file. Look it up self.idmap
199    
200               'ascii' -- The attribute is converted to a bytestring with
201                          ascii encoding.
202          """          """
203          normalized = {}          normalized = {}
204    
205          for d in descr:          for d in descr:
206              if d.required and not attrs.has_key(d.fullname):              if d.required and not attrs.has_key(d.fullname):
207                  pass                  raise LoadError("Element %s requires an attribute %r"
208              #raise LoadError("Element %s requires an attribute %r"                                  % (element, d.name))
             #                    % (element, d.name))  
209              value = attrs.get(d.fullname, d.default)              value = attrs.get(d.fullname, d.default)
210    
211              if d.conversion == "shapesource":              if d.conversion in ("idref", "shapesource"):
212                  if value in self.idmap:                  if value in self.idmap:
213                      value = self.idmap[value]                      value = self.idmap[value]
214                  else:                  else:
# Line 201  class SessionLoader(XMLReader): Line 227  class SessionLoader(XMLReader):
227              elif d.conversion == "filename":              elif d.conversion == "filename":
228                  value = os.path.abspath(os.path.join(self.GetDirectory(),                  value = os.path.abspath(os.path.join(self.GetDirectory(),
229                                                       value))                                                       value))
230                elif d.conversion == "ascii":
231                    value = value.encode("ascii")
232                else:
233                    if d.conversion:
234                        raise ValueError("Unknown attribute conversion %r"
235                                         % d.conversion)
236    
237              normalized[d.name] = value              normalized[d.name] = value
238          return normalized          return normalized
239    
240        def start_dbconnection(self, name, qname, attrs):
241            attrs = self.check_attrs(name, attrs,
242                                     [AttrDesc("id", True),
243                                      AttrDesc("dbtype", True),
244                                      AttrDesc("host", False, ""),
245                                      AttrDesc("port", False, ""),
246                                      AttrDesc("user", False, ""),
247                                      AttrDesc("dbname", True)])
248            ID = attrs["id"]
249            dbtype = attrs["dbtype"]
250            if dbtype != "postgis":
251                raise LoadError("dbtype %r not supported" % filetype)
252    
253            del attrs["id"]
254            del attrs["dbtype"]
255    
256            # Try to open the connection and if it fails ask the user for
257            # the correct parameters repeatedly.
258            # FIXME: it would be better not to insist on getting a
259            # connection here. We should handle this more like the raster
260            # images where the layers etc still are created but are not
261            # drawn in case Thuban can't use the data for various reasons
262            while 1:
263                try:
264                    conn = postgisdb.PostGISConnection(**attrs)
265                    break
266                except postgisdb.ConnectionError, val:
267                    if self.db_connection_callback is not None:
268                        attrs = self.db_connection_callback(attrs, str(val))
269                        if attrs is None:
270                            raise LoadCancelled
271                    else:
272                        raise
273    
274            self.idmap[ID] = conn
275            self.theSession.AddDBConnection(conn)
276    
277        def start_dbshapesource(self, name, qname, attrs):
278            attrs = self.check_attrs(name, attrs,
279                                     [AttrDesc("id", True),
280                                      AttrDesc("dbconn", True,
281                                               conversion = "idref"),
282                                      AttrDesc("tablename", True,
283                                               conversion = "ascii")])
284            ID = attrs["id"]
285            db = attrs["dbconn"]
286            tablename = attrs["tablename"]
287            self.idmap[ID] = self.theSession.OpenDBShapeStore(db, tablename)
288    
289      def start_fileshapesource(self, name, qname, attrs):      def start_fileshapesource(self, name, qname, attrs):
290          attrs = self.check_attrs(name, attrs,          attrs = self.check_attrs(name, attrs,
291                                    [AttrDesc("id", True),                                    [AttrDesc("id", True),
# Line 249  class SessionLoader(XMLReader): Line 330  class SessionLoader(XMLReader):
330                                    AttrDesc("left", True, conversion="table"),                                    AttrDesc("left", True, conversion="table"),
331                                    AttrDesc("leftcolumn", True),                                    AttrDesc("leftcolumn", True),
332                                    AttrDesc("right", True, conversion="table"),                                    AttrDesc("right", True, conversion="table"),
333                                    AttrDesc("rightcolumn")])                                    AttrDesc("rightcolumn", True),
334    
335                                      # jointype is required for file
336                                      # version 0.9 but this attribute
337                                      # wasn't in the 0.8 version because of
338                                      # an oversight so we assume it's
339                                      # optional since we want to handle
340                                      # both file format versions here.
341                                      AttrDesc("jointype", False,
342                                               default="INNER")])
343    
344            jointype = attrs["jointype"]
345            if jointype == "LEFT OUTER":
346                outer_join = True
347            elif jointype == "INNER":
348                outer_join = False
349            else:
350                raise LoadError("jointype %r not supported" % jointype )
351          table = TransientJoinedTable(self.theSession.TransientDB(),          table = TransientJoinedTable(self.theSession.TransientDB(),
352                                       attrs["left"], attrs["leftcolumn"],                                       attrs["left"], attrs["leftcolumn"],
353                                       attrs["right"], attrs["rightcolumn"])                                       attrs["right"], attrs["rightcolumn"],
354                                         outer_join = outer_join)
355          table.SetTitle(attrs["title"])          table.SetTitle(attrs["title"])
356          self.idmap[attrs["id"]] = self.theSession.AddTable(table)          self.idmap[attrs["id"]] = self.theSession.AddTable(table)
357    
358      def start_map(self, name, qname, attrs):      def start_map(self, name, qname, attrs):
359          """Start a map."""          """Start a map."""
360          self.aMap = Map(attrs.get((None, 'title'), None))          self.aMap = Map(self.encode(attrs.get((None, 'title'), None)))
361    
362      def end_map(self, name, qname):      def end_map(self, name, qname):
363          self.theSession.AddMap(self.aMap)          self.theSession.AddMap(self.aMap)
# Line 344  class SessionLoader(XMLReader): Line 443  class SessionLoader(XMLReader):
443          elif fieldType == FIELDTYPE_DOUBLE:          elif fieldType == FIELDTYPE_DOUBLE:
444              self.conv = float              self.conv = float
445    
446          self.aLayer.GetClassification().SetFieldInfo(field, fieldType)          self.aLayer.SetClassificationColumn(field)
447    
448      def end_classification(self, name, qname):      def end_classification(self, name, qname):
449          pass          pass
# Line 362  class SessionLoader(XMLReader): Line 461  class SessionLoader(XMLReader):
461      def start_clpoint(self, name, qname, attrs):      def start_clpoint(self, name, qname, attrs):
462          attrib_value = attrs.get((None, 'value'), "0")          attrib_value = attrs.get((None, 'value'), "0")
463    
464          value = self.conv(attrib_value)          field = self.aLayer.GetClassificationColumn()
465            if self.aLayer.GetFieldType(field) == FIELDTYPE_STRING:
466                value = self.encode(attrib_value)
467            else:
468                value = self.conv(attrib_value)
469          self.cl_group = ClassGroupSingleton(value)          self.cl_group = ClassGroupSingleton(value)
470          self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))          self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
471          self.cl_prop = ClassGroupProperties()          self.cl_prop = ClassGroupProperties()
# Line 427  class SessionLoader(XMLReader): Line 529  class SessionLoader(XMLReader):
529          pass          pass
530    
531    
532  def load_session(filename):  def load_session(filename, db_connection_callback = None):
533      """Load a Thuban session from the file object file"""      """Load a Thuban session from the file object file
534    
535      handler = SessionLoader()      The db_connection_callback, if given should be a callable object
536        that can be called like this:
537           db_connection_callback(params, message)
538    
539        where params is a dictionary containing the known connection
540        parameters and message is a string with a message why the connection
541        failed. db_connection_callback should return a new dictionary with
542        corrected and perhaps additional parameters like a password or None
543        to indicate that the user cancelled.
544        """
545        handler = SessionLoader(db_connection_callback)
546      handler.read(filename)      handler.read(filename)
547    
548      session = handler.theSession      session = handler.theSession

Legend:
Removed from v.1354  
changed lines
  Added in v.1664

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26