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

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

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

revision 1634 by bh, Fri Aug 22 16:55:19 2003 UTC revision 2057 by bh, Tue Feb 10 15:51:57 2004 UTC
# Line 1  Line 1 
1  # Copyright (C) 2003 by Intevation GmbH  # Copyright (C) 2003, 2004 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  #  #
# Line 198  class PostgreSQLServer: Line 198  class PostgreSQLServer:
198          run_command(["pg_ctl", "-m", "fast", "-D", self.dbdir, "stop"],          run_command(["pg_ctl", "-m", "fast", "-D", self.dbdir, "stop"],
199                      os.path.join(self.dbdir, "pg_ctl-stop.log"))                      os.path.join(self.dbdir, "pg_ctl-stop.log"))
200    
201      def new_postgis_db(self, dbname, tables = None):      def new_postgis_db(self, dbname, tables = None, reference_systems = None):
202          """Create and return a new PostGISDatabase object using self as server          """Create and return a new PostGISDatabase object using self as server
203          """          """
204          db = PostGISDatabase(self, self.postgis_sql, dbname, tables = tables)          db = PostGISDatabase(self, self.postgis_sql, dbname, tables = tables,
205                                 reference_systems = reference_systems)
206          db.initdb()          db.initdb()
207          self.known_dbs[dbname] = db          self.known_dbs[dbname] = db
208          return db          return db
209    
210      def get_static_data_db(self, dbname, tables):      def get_static_data_db(self, dbname, tables, reference_systems):
211          """Return a PostGISDatabase for a database with the given static data          """Return a PostGISDatabase for a database with the given static data
212    
213          If no databasse of the name dbname exists, create a new one via          If no databasse of the name dbname exists, create a new one via
# Line 216  class PostgreSQLServer: Line 217  class PostgreSQLServer:
217          indicated data, return that. If the already existing db uses          indicated data, return that. If the already existing db uses
218          different data raise a value error.          different data raise a value error.
219    
220          The tables argument should be a sequence of table specifications          If the database doesn't exist, create a new one via
221          where each specifications is a (tablename, shapefilename) pair.          self.new_postgis_db.
222    
223            The parameters tables and reference_systems have the same
224            meaning as for new_postgis_db.
225          """          """
226          db = self.known_dbs.get(dbname)          db = self.known_dbs.get(dbname)
227          if db is not None:          if db is not None:
228              if db.has_data(tables):              if db.has_data(tables, reference_systems):
229                  return db                  return db
230              raise ValueError("PostGISDatabase named %r doesn't have tables %r"              raise ValueError("PostGISDatabase named %r doesn't have tables %r"
231                               % (dbname, tables))                               % (dbname, tables))
232          return self.new_postgis_db(dbname, tables)          return self.new_postgis_db(dbname, tables, reference_systems)
233    
234      def get_default_static_data_db(self):      def get_default_static_data_db(self):
235          dbname = "PostGISStaticTests"          dbname = "PostGISStaticTests"
236          tables = [("landmarks", os.path.join("..", "Data", "iceland",          srids = [(1, "proj=longlat datum=WGS84")]
237                                               "cultural_landmark-point.shp")),          tables = [
238                    ("political", os.path.join("..", "Data", "iceland",              # Direct copies of the shapefiles. The shapeids are exactly
239                # the same, except where changed with "gid_offset", of
240                # course
241                ("landmarks", os.path.join("..", "Data", "iceland",
242                                           "cultural_landmark-point.shp"),
243                 [("gid_offset", 1000)]),
244                ("political", os.path.join("..", "Data", "iceland",
245                                               "political.shp")),                                               "political.shp")),
246                    ("roads", os.path.join("..", "Data", "iceland",              ("roads", os.path.join("..", "Data", "iceland",
247                                           "roads-line.shp"))]                                           "roads-line.shp")),
248          return self.get_static_data_db(dbname, tables)  
249                # The polygon data as a MULTIPOLYGON geometry type
250                ("political_multi", os.path.join("..", "Data", "iceland",
251                                                 "political.shp"),
252                 [("force_wkt_type", "MULTIPOLYGON")]),
253    
254                # Copy of landmarks but using an srid
255                ("landmarks_srid", os.path.join("..", "Data", "iceland",
256                                           "cultural_landmark-point.shp"),
257                 [("gid_offset", 1000),
258                  ("srid", 1)]),
259                ]
260            return self.get_static_data_db(dbname, tables, srids)
261    
262      def connection_params(self, user):      def connection_params(self, user):
263          """Return the connection parameters for the given user          """Return the connection parameters for the given user
# Line 313  class PostGISDatabase: Line 335  class PostGISDatabase:
335    
336      """A PostGIS database in a PostgreSQLServer"""      """A PostGIS database in a PostgreSQLServer"""
337    
338      def __init__(self, server, postgis_sql, dbname, tables = None):      def __init__(self, server, postgis_sql, dbname, tables = None,
339                     reference_systems = ()):
340            """Initialize the PostGISDatabase
341    
342            Parameters:
343    
344                server -- The PostgreSQLServer instance containing the
345                    database
346    
347                postgis_sql -- Filename of the postgis.sql file with the
348                    postgis initialization code
349    
350                dbname -- The name of the database
351    
352                tables -- Optional description of tables to create in the
353                    new database. If given it should be a list of
354                    (tablename, shapefilename) pairs meaning that a table
355                    tablename will be created with the contents of the given
356                    shapefile or (tablename, shapefilename, extraargs)
357                    triples. The extraargs should be a list of key, value
358                    pairs to use as keyword arguments to upload_shapefile.
359    
360                reference_systems -- Optional description of spatial
361                    reference systems.  If given, it should be a sequence of
362                    (srid, params) pairs where srid is the srid defined by
363                    the proj4 paramter string params.  The srid can be given
364                    as an extra parameter in the tables list.
365            """
366          self.server = server          self.server = server
367          self.postgis_sql = postgis_sql          self.postgis_sql = postgis_sql
368          self.dbname = dbname          self.dbname = dbname
369          self.tables = tables          self.tables = tables
370            if reference_systems:
371                self.reference_systems = reference_systems
372            else:
373                # Make sure that it's a sequence we can iterate over even if
374                # the parameter's None
375                self.reference_systems = ()
376    
377      def initdb(self):      def initdb(self):
378          """Remove the old db directory and create and initialize a new database          """Remove the old db directory and create and initialize a new database
# Line 343  class PostGISDatabase: Line 398  class PostGISDatabase:
398    
399          self.server.execute_sql(self.dbname, "admin",          self.server.execute_sql(self.dbname, "admin",
400                                  "GRANT SELECT ON geometry_columns TO PUBLIC;")                                  "GRANT SELECT ON geometry_columns TO PUBLIC;")
401            self.server.execute_sql(self.dbname, "admin",
402                                    "GRANT SELECT ON spatial_ref_sys TO PUBLIC;")
403    
404            for srid, params in self.reference_systems:
405                self.server.execute_sql(self.dbname, "admin",
406                                        "INSERT INTO spatial_ref_sys VALUES"
407                                        " (%d, '', %d, '', '%s');"
408                                        % (srid, srid, params))
409          if self.tables is not None:          if self.tables is not None:
410              for tablename, shapefile in self.tables:              def unpack(item):
411                  upload_shapefile(shapefile, self, tablename)                  extra = {"force_wkt_type": None, "gid_offset": 0,
412                             "srid": -1}
413      def has_data(self, tables):                  if len(info) == 2:
414          return self.tables == tables                      tablename, shapefile = info
415                    else:
416                        tablename, shapefile, kw = info
417                        for key, val in kw:
418                            extra[key] = val
419                    return tablename, shapefile, extra
420    
421                for info in self.tables:
422                    tablename, shapefile, kw = unpack(info)
423                    upload_shapefile(shapefile, self, tablename, **kw)
424    
425        def has_data(self, tables, reference_systems):
426            return (self.tables == tables
427                    and self.reference_systems == reference_systems)
428    
429    
430  def find_postgis_sql():  def find_postgis_sql():
# Line 408  def reason_for_not_running_tests(): Line 483  def reason_for_not_running_tests():
483         The name of the postgis_sql file is determined by find_postgis_sql()         The name of the postgis_sql file is determined by find_postgis_sql()
484       - psycopg can be imported successfully.       - psycopg can be imported successfully.
485      """      """
486        # run_command currently uses Popen4 which is not available under
487        # Windows, for example.
488        if not hasattr(popen2, "Popen4"):
489            return "Can't run PostGIS test because popen2.Popen4 does not exist"
490    
491      try:      try:
492          run_command(["pg_ctl", "--help"], None)          run_command(["pg_ctl", "--help"], None)
493      except RuntimeError:      except RuntimeError:
# Line 440  def skip_if_no_postgis(): Line 520  def skip_if_no_postgis():
520      if _cannot_run_postgis_tests:      if _cannot_run_postgis_tests:
521          raise support.SkipTest(_cannot_run_postgis_tests)          raise support.SkipTest(_cannot_run_postgis_tests)
522    
523  def point_to_wkt(coords):  def skip_if_addgeometrycolumn_does_not_use_quote_ident():
524        """Skip a test if the AddGeometryColumn function doesn't use quote_ident
525    
526        If the AddGeometryColumn function doesn't use quote_ident it doesn't
527        support unusual table or column names properly, that is, it will
528        fail with errors for names that contain spaces or double quotes.
529    
530        The test performed by this function is a bit simplistic because it
531        only tests whether the string 'quote_ident' occurs anywhere in the
532        postgis.sql file. This will hopefully works because when this was
533        fixed in postgis CVS AddGeometryColumn was the first function to use
534        quote_ident.
535        """
536        f = file(find_postgis_sql())
537        content = f.read()
538        f.close()
539        if content.find("quote_ident") < 0:
540            raise support.SkipTest("AddGeometryColumn doesn't use quote_ident")
541    
542    def coords_to_point(coords):
543      """Return string with a WKT representation of the point in coords"""      """Return string with a WKT representation of the point in coords"""
544      x, y = coords[0]      x, y = coords[0]
545      return "POINT(%r %r)" % (x, y)      return "POINT(%r %r)" % (x, y)
546    
547  def polygon_to_wkt(coords):  def coords_to_polygon(coords):
548      """Return string with a WKT representation of the polygon in coords"""      """Return string with a WKT representation of the polygon in coords"""
549      poly = []      poly = []
550      for ring in coords:      for ring in coords:
551          poly.append(", ".join(["%r %r" % p for p in ring]))          poly.append(", ".join(["%r %r" % p for p in ring]))
552      return "POLYGON((%s))" % "), (".join(poly)      return "POLYGON((%s))" % "), (".join(poly)
553    
554  def arc_to_wkt(coords):  def coords_to_multilinestring(coords):
555      """Return string with a WKT representation of the arc in coords"""      """Return string with a WKT representation of the arc in coords"""
556      poly = []      poly = []
557      for ring in coords:      for ring in coords:
558          poly.append(", ".join(["%r %r" % p for p in ring]))          poly.append(", ".join(["%r %r" % p for p in ring]))
559      return "MULTILINESTRING((%s))" % "), (".join(poly)      return "MULTILINESTRING((%s))" % "), (".join(poly)
560    
561  def upload_shapefile(filename, db, tablename):  def coords_to_multipolygon(coords):
562        """Return string with a WKT representation of the polygon in coords"""
563        poly = []
564        for ring in coords:
565            poly.append(", ".join(["%r %r" % p for p in ring]))
566        return "MULTIPOLYGON(((%s)))" % ")), ((".join(poly)
567    
568    wkt_converter = {
569        "POINT": coords_to_point,
570        "MULTILINESTRING": coords_to_multilinestring,
571        "POLYGON": coords_to_polygon,
572        "MULTIPOLYGON": coords_to_multipolygon,
573        }
574    
575    def upload_shapefile(filename, db, tablename, force_wkt_type = None,
576                         gid_offset = 0, srid = -1):
577        """Upload a shapefile into a new database table
578    
579        Parameters:
580    
581        filename -- The name of the shapefile
582    
583        db -- The PostGISDatabase instance representing the database
584    
585        tablename -- The name of the table to create and into which the data
586                    is to be inserted
587    
588        force_wkt_type -- If given the real WKT geometry type to use instead
589                    of the default that would be chosen based on the type of
590                    the shapefile
591    
592        gid_offset -- A number to add to the shapeid to get the value for
593                    the gid column (default 0)
594    
595        srid -- The srid of the spatial references system used by the table
596                and the data
597        """
598      import dbflib, shapelib      import dbflib, shapelib
599    
600        # We build this map here because we need shapelib which can only be
601        # imported after support.initthuban has been called which we can't
602        # easily do in this module because it's imported by support.
603        shp_to_wkt = {
604            shapelib.SHPT_POINT: "POINT",
605            shapelib.SHPT_ARC: "MULTILINESTRING",
606            shapelib.SHPT_POLYGON: "POLYGON",
607            }
608    
609      server = db.server      server = db.server
610      dbname = db.dbname      dbname = db.dbname
611      conn = psycopg.connect("dbname=%s " % dbname      conn = psycopg.connect("dbname=%s " % dbname
# Line 486  def upload_shapefile(filename, db, table Line 630  def upload_shapefile(filename, db, table
630      #print stmt      #print stmt
631    
632      numshapes, shapetype, mins, maxs = shp.info()      numshapes, shapetype, mins, maxs = shp.info()
633      if shapetype == shapelib.SHPT_POINT:      wkttype =  shp_to_wkt[shapetype]
634          convert = point_to_wkt      if force_wkt_type:
635          wkttype = "POINT"          wkttype = force_wkt_type
636      elif shapetype == shapelib.SHPT_POLYGON:      convert = wkt_converter[wkttype]
         convert = polygon_to_wkt  
         wkttype = "POLYGON"  
     elif shapetype == shapelib.SHPT_ARC:  
         convert = arc_to_wkt  
         wkttype = "MULTILINESTRING"  
     else:  
         raise ValueError("Unsupported Shapetype %r" % shapetype)  
637    
638      cursor.execute("select AddGeometryColumn('%(dbname)s',"      cursor.execute("select AddGeometryColumn('%(dbname)s',"
639                     "'%(tablename)s', 'the_geom', '-1', '%(wkttype)s', 2);"                     "'%(tablename)s', 'the_geom', %(srid)d, '%(wkttype)s', 2);"
640                     % locals())                     % locals())
641    
642      insert_formats.append("GeometryFromText(%(the_geom)s, -1)")      insert_formats.append("GeometryFromText(%(the_geom)s, %(srid)d)")
643    
644      insert = ("INSERT INTO %s VALUES (%s)"      insert = ("INSERT INTO %s VALUES (%s)"
645                % (tablename, ", ".join(insert_formats)))                % (tablename, ", ".join(insert_formats)))
# Line 510  def upload_shapefile(filename, db, table Line 647  def upload_shapefile(filename, db, table
647      for i in range(numshapes):      for i in range(numshapes):
648          data = dbf.read_record(i)          data = dbf.read_record(i)
649          data["tablename"] = tablename          data["tablename"] = tablename
650          data["gid"] = i          data["gid"] = i + gid_offset
651            data["srid"] = srid
652          data["the_geom"] = convert(shp.read_object(i).vertices())          data["the_geom"] = convert(shp.read_object(i).vertices())
653          #print insert % data          #print insert % data
654          cursor.execute(insert, data)          cursor.execute(insert, data)

Legend:
Removed from v.1634  
changed lines
  Added in v.2057

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26