/[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 1339 by jonathan, Tue Jul 1 16:10:14 2003 UTC revision 1646 by bh, Mon Aug 25 13:43:56 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              for key, value in dispatchers.items():
146                    dispatchers[(xmlns, key)] = value
147    
148          XMLReader.AddDispatchers(self, dispatchers)          XMLReader.AddDispatchers(self, dispatchers)
149    
# Line 172  class SessionLoader(XMLReader): Line 192  class SessionLoader(XMLReader):
192                        defined earlier in the .thuban file. Look it up                        defined earlier in the .thuban file. Look it up
193                        self.idmap. If it's the ID of a shapestore the                        self.idmap. If it's the ID of a shapestore the
194                        value will be the table of the shapestore.                        value will be the table of the shapestore.
195    
196               'idref' -- The attribute is the id of an object defined
197                          earlier in the .thuban file. Look it up self.idmap
198    
199               'ascii' -- The attribute is converted to a bytestring with
200                          ascii encoding.
201          """          """
202          normalized = {}          normalized = {}
203    
204          for d in descr:          for d in descr:
205              if d.required and not attrs.has_key(d.fullname):              if d.required and not attrs.has_key(d.fullname):
206                  pass                  raise LoadError("Element %s requires an attribute %r"
207              #raise LoadError("Element %s requires an attribute %r"                                  % (element, d.name))
             #                    % (element, d.name))  
208              value = attrs.get(d.fullname, d.default)              value = attrs.get(d.fullname, d.default)
209    
210              if d.conversion == "shapesource":              if d.conversion in ("idref", "shapesource"):
211                  if value in self.idmap:                  if value in self.idmap:
212                      value = self.idmap[value]                      value = self.idmap[value]
213                  else:                  else:
# Line 201  class SessionLoader(XMLReader): Line 226  class SessionLoader(XMLReader):
226              elif d.conversion == "filename":              elif d.conversion == "filename":
227                  value = os.path.abspath(os.path.join(self.GetDirectory(),                  value = os.path.abspath(os.path.join(self.GetDirectory(),
228                                                       value))                                                       value))
229                elif d.conversion == "ascii":
230                    value = value.encode("ascii")
231                else:
232                    if d.conversion:
233                        raise ValueError("Unknown attribute conversion %r"
234                                         % d.conversion)
235    
236              normalized[d.name] = value              normalized[d.name] = value
237          return normalized          return normalized
238    
239        def start_dbconnection(self, name, qname, attrs):
240            attrs = self.check_attrs(name, attrs,
241                                     [AttrDesc("id", True),
242                                      AttrDesc("dbtype", True),
243                                      AttrDesc("host", False, ""),
244                                      AttrDesc("port", False, ""),
245                                      AttrDesc("user", False, ""),
246                                      AttrDesc("dbname", True)])
247            ID = attrs["id"]
248            dbtype = attrs["dbtype"]
249            if dbtype != "postgis":
250                raise LoadError("dbtype %r not supported" % filetype)
251    
252            del attrs["id"]
253            del attrs["dbtype"]
254    
255            # Try to open the connection and if it fails ask the user for
256            # the correct parameters repeatedly.
257            # FIXME: it would be better not to insist on getting a
258            # connection here. We should handle this more like the raster
259            # images where the layers etc still are created but are not
260            # drawn in case Thuban can't use the data for various reasons
261            while 1:
262                try:
263                    conn = postgisdb.PostGISConnection(**attrs)
264                    break
265                except postgisdb.ConnectionError, val:
266                    if self.db_connection_callback is not None:
267                        attrs = self.db_connection_callback(attrs, str(val))
268                        if attrs is None:
269                            raise LoadCancelled
270                    else:
271                        raise
272    
273            self.idmap[ID] = conn
274            self.theSession.AddDBConnection(conn)
275    
276        def start_dbshapesource(self, name, qname, attrs):
277            attrs = self.check_attrs(name, attrs,
278                                     [AttrDesc("id", True),
279                                      AttrDesc("dbconn", True,
280                                               conversion = "idref"),
281                                      AttrDesc("tablename", True,
282                                               conversion = "ascii")])
283            ID = attrs["id"]
284            db = attrs["dbconn"]
285            tablename = attrs["tablename"]
286            self.idmap[ID] = self.theSession.OpenDBShapeStore(db, tablename)
287    
288      def start_fileshapesource(self, name, qname, attrs):      def start_fileshapesource(self, name, qname, attrs):
289          attrs = self.check_attrs(name, attrs,          attrs = self.check_attrs(name, attrs,
290                                    [AttrDesc("id", True),                                    [AttrDesc("id", True),
# Line 249  class SessionLoader(XMLReader): Line 329  class SessionLoader(XMLReader):
329                                    AttrDesc("left", True, conversion="table"),                                    AttrDesc("left", True, conversion="table"),
330                                    AttrDesc("leftcolumn", True),                                    AttrDesc("leftcolumn", True),
331                                    AttrDesc("right", True, conversion="table"),                                    AttrDesc("right", True, conversion="table"),
332                                    AttrDesc("rightcolumn")])                                    AttrDesc("rightcolumn", True),
333    
334                                      # jointype is required for file
335                                      # version 0.9 but this attribute
336                                      # wasn't in the 0.8 version because of
337                                      # an oversight so we assume it's
338                                      # optional since we want to handle
339                                      # both file format versions here.
340                                      AttrDesc("jointype", False,
341                                               default="INNER")])
342    
343            jointype = attrs["jointype"]
344            if jointype == "LEFT OUTER":
345                outer_join = True
346            elif jointype == "INNER":
347                outer_join = False
348            else:
349                raise LoadError("jointype %r not supported" % jointype )
350          table = TransientJoinedTable(self.theSession.TransientDB(),          table = TransientJoinedTable(self.theSession.TransientDB(),
351                                       attrs["left"], attrs["leftcolumn"],                                       attrs["left"], attrs["leftcolumn"],
352                                       attrs["right"], attrs["rightcolumn"])                                       attrs["right"], attrs["rightcolumn"],
353                                         outer_join = outer_join)
354          table.SetTitle(attrs["title"])          table.SetTitle(attrs["title"])
355          self.idmap[attrs["id"]] = self.theSession.AddTable(table)          self.idmap[attrs["id"]] = self.theSession.AddTable(table)
356    
357      def start_map(self, name, qname, attrs):      def start_map(self, name, qname, attrs):
358          """Start a map."""          """Start a map."""
359          self.aMap = Map(attrs.get((None, 'title'), None))          self.aMap = Map(self.encode(attrs.get((None, 'title'), None)))
360    
361      def end_map(self, name, qname):      def end_map(self, name, qname):
362          self.theSession.AddMap(self.aMap)          self.theSession.AddMap(self.aMap)
# Line 344  class SessionLoader(XMLReader): Line 442  class SessionLoader(XMLReader):
442          elif fieldType == FIELDTYPE_DOUBLE:          elif fieldType == FIELDTYPE_DOUBLE:
443              self.conv = float              self.conv = float
444    
445          self.aLayer.GetClassification().SetFieldInfo(field, fieldType)          self.aLayer.SetClassificationColumn(field)
446    
447      def end_classification(self, name, qname):      def end_classification(self, name, qname):
448          pass          pass
# Line 362  class SessionLoader(XMLReader): Line 460  class SessionLoader(XMLReader):
460      def start_clpoint(self, name, qname, attrs):      def start_clpoint(self, name, qname, attrs):
461          attrib_value = attrs.get((None, 'value'), "0")          attrib_value = attrs.get((None, 'value'), "0")
462    
463          value = self.conv(attrib_value)          field = self.aLayer.GetClassificationColumn()
464            if self.aLayer.GetFieldType(field) == FIELDTYPE_STRING:
465                value = self.encode(attrib_value)
466            else:
467                value = self.conv(attrib_value)
468          self.cl_group = ClassGroupSingleton(value)          self.cl_group = ClassGroupSingleton(value)
469          self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))          self.cl_group.SetLabel(self.encode(attrs.get((None, 'label'), "")))
470          self.cl_prop = ClassGroupProperties()          self.cl_prop = ClassGroupProperties()
# Line 385  class SessionLoader(XMLReader): Line 486  class SessionLoader(XMLReader):
486              if range is not None:              if range is not None:
487                  self.cl_group = ClassGroupRange(Range(range))                  self.cl_group = ClassGroupRange(Range(range))
488              elif min is not None and max is not None:              elif min is not None and max is not None:
489                  self.cl_group = ClassGroupRange(self.conv(min), self.conv(max))                  self.cl_group = ClassGroupRange((self.conv(min),
490                                                     self.conv(max)))
491              else:              else:
492                  self.cl_group = ClassGroupRange(Range(None))                  self.cl_group = ClassGroupRange(Range(None))
493    
# Line 426  class SessionLoader(XMLReader): Line 528  class SessionLoader(XMLReader):
528          pass          pass
529    
530    
531  def load_session(filename):  def load_session(filename, db_connection_callback = None):
532      """Load a Thuban session from the file object file"""      """Load a Thuban session from the file object file
533    
534      handler = SessionLoader()      The db_connection_callback, if given should be a callable object
535        that can be called like this:
536           db_connection_callback(params, message)
537    
538        where params is a dictionary containing the known connection
539        parameters and message is a string with a message why the connection
540        failed. db_connection_callback should return a new dictionary with
541        corrected and perhaps additional parameters like a password or None
542        to indicate that the user cancelled.
543        """
544        handler = SessionLoader(db_connection_callback)
545      handler.read(filename)      handler.read(filename)
546    
547      session = handler.theSession      session = handler.theSession

Legend:
Removed from v.1339  
changed lines
  Added in v.1646

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26