/[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 1605 by bh, Tue Aug 19 11:00:40 2003 UTC revision 1656 by bh, Mon Aug 25 18:26:54 2003 UTC
# Line 115  class PostgreSQLServer: Line 115  class PostgreSQLServer:
115          self.socket_dir = socket_dir          self.socket_dir = socket_dir
116    
117          # For the client side the socket directory can be used as the          # For the client side the socket directory can be used as the
118          # host the name starts with a slash.          # host if the name starts with a slash.
119          self.host = os.path.abspath(socket_dir)          self.host = os.path.abspath(socket_dir)
120    
121            # name and password for the admin and an unprivileged user
122            self.admin_name = "postgres"
123            self.admin_password = "postgres"
124            self.user_name = "observer"
125            self.user_password = "telescope"
126    
127          # Map db names to db objects          # Map db names to db objects
128          self.known_dbs = {}          self.known_dbs = {}
129    
# Line 135  class PostgreSQLServer: Line 141  class PostgreSQLServer:
141              shutil.rmtree(self.dbdir)              shutil.rmtree(self.dbdir)
142          os.mkdir(self.dbdir)          os.mkdir(self.dbdir)
143    
144          run_command(["initdb", self.dbdir],          run_command(["initdb", "-D", self.dbdir, "-U", self.admin_name],
145                      os.path.join(self.dbdir, "initdb.log"))                      os.path.join(self.dbdir, "initdb.log"))
146    
147          extra_opts = "-p %d" % self.port          extra_opts = "-p %d" % self.port
# Line 150  class PostgreSQLServer: Line 156  class PostgreSQLServer:
156          # server ourselves          # server ourselves
157          self.wait_for_postmaster()          self.wait_for_postmaster()
158    
159            self.alter_user(self.admin_name, self.admin_password)
160            self.create_user(self.user_name, self.user_password)
161    
162      def wait_for_postmaster(self):      def wait_for_postmaster(self):
163          """Return when the database server is running          """Return when the database server is running
164    
# Line 161  class PostgreSQLServer: Line 170  class PostgreSQLServer:
170          while count < max_count:          while count < max_count:
171              try:              try:
172                  run_command(["psql", "-l", "-p", str(self.port),                  run_command(["psql", "-l", "-p", str(self.port),
173                               "-h", self.host],                               "-h", self.host, "-U", self.admin_name],
174                              os.path.join(self.dbdir, "psql-%d.log" % count))                              os.path.join(self.dbdir, "psql-%d.log" % count))
175              except:              except RuntimeError:
176                  pass                  pass
177                except:
178                    traceback.print_exc()
179              else:              else:
180                  break                  break
181              time.sleep(0.5)              time.sleep(0.5)
# Line 222  class PostgreSQLServer: Line 233  class PostgreSQLServer:
233                                               "cultural_landmark-point.shp")),                                               "cultural_landmark-point.shp")),
234                    ("political", os.path.join("..", "Data", "iceland",                    ("political", os.path.join("..", "Data", "iceland",
235                                               "political.shp")),                                               "political.shp")),
236    
237                      # The polygon data as a MULTIPOLYGON geometry type
238                      ("political_multi", os.path.join("..", "Data", "iceland",
239                                                 "political.shp"),
240                       "MULTIPOLYGON"),
241    
242                    ("roads", os.path.join("..", "Data", "iceland",                    ("roads", os.path.join("..", "Data", "iceland",
243                                           "roads-line.shp"))]                                           "roads-line.shp"))]
244          return self.get_static_data_db(dbname, tables)          return self.get_static_data_db(dbname, tables)
245    
246        def connection_params(self, user):
247            """Return the connection parameters for the given user
248    
249            The return value is a dictionary suitable as keyword argument
250            list to PostGISConnection. The user parameter may be either
251            'admin' to connect as admin or 'user' to connect as an
252            unprivileged user.
253            """
254            return {"host": self.host, "port": self.port,
255                    "user": getattr(self, user + "_name"),
256                    "password": getattr(self, user + "_password")}
257    
258        def connection_string(self, user):
259            """Return (part of) the connection string to pass to psycopg.connect
260    
261            The string contains host, port, user and password. The user
262            parameter must be either 'admin' or 'user', as for
263            connection_params.
264            """
265            params = []
266            for key, value in self.connection_params(user).items():
267                # FIXME: this doesn't do quiting correctly but that
268                # shouldn't be much of a problem (people shouldn't be using
269                # single quotes in filenames anyway :) )
270                params.append("%s='%s'" % (key, value))
271            return " ".join(params)
272    
273        def execute_sql(self, dbname, user, sql):
274            """Execute the sql statament
275    
276            The user parameter us used as in connection_params. The dbname
277            parameter must be the name of a database in the cluster.
278            """
279            conn = psycopg.connect("dbname=%s " % dbname
280                                   + self.connection_string(user))
281            cursor = conn.cursor()
282            cursor.execute(sql)
283            conn.commit()
284            conn.close()
285    
286        def require_authentication(self, required):
287            """Switch authentication requirements on or off
288    
289            When started for the first time no passwords are required. Some
290            tests want to explicitly test whether Thuban's password
291            infrastructure works and switch password authentication on
292            explicitly. When switching it on, there should be a
293            corresponding call to switch it off again in the test case'
294            tearDown method or in a finally: block.
295            """
296            if required:
297                contents = "local all password\n"
298            else:
299                contents = "local all trust\n"
300            f = open(os.path.join(self.dbdir, "pg_hba.conf"), "w")
301            f.write(contents)
302            f.close()
303            run_command(["pg_ctl", "-D", self.dbdir, "reload"],
304                        os.path.join(self.dbdir, "pg_ctl-reload.log"))
305    
306    
307        def create_user(self, username, password):
308            """Create user username with password in the database"""
309            self.execute_sql("template1", "admin",
310                             "CREATE USER %s PASSWORD '%s';" % (username,password))
311    
312        def alter_user(self, username, password):
313            """Change the user username's password in the database"""
314            self.execute_sql("template1", "admin",
315                             "ALTER USER %s PASSWORD '%s';" % (username,password))
316    
317    
318  class PostGISDatabase:  class PostGISDatabase:
# Line 243  class PostGISDatabase: Line 329  class PostGISDatabase:
329          """Remove the old db directory and create and initialize a new database          """Remove the old db directory and create and initialize a new database
330          """          """
331          run_command(["createdb", "-p", str(self.server.port),          run_command(["createdb", "-p", str(self.server.port),
332                       "-h", self.server.host, self.dbname],                       "-h", self.server.host, "-U", self.server.admin_name,
333                         self.dbname],
334                      os.path.join(self.server.dbdir, "createdb.log"))                      os.path.join(self.server.dbdir, "createdb.log"))
335          run_command(["createlang", "-p", str(self.server.port),          run_command(["createlang", "-p", str(self.server.port),
336                       "-h", self.server.host, "plpgsql", self.dbname],                       "-h", self.server.host,  "-U", self.server.admin_name,
337                         "plpgsql", self.dbname],
338                      os.path.join(self.server.dbdir, "createlang.log"))                      os.path.join(self.server.dbdir, "createlang.log"))
339          # for some reason psql doesn't exit with an error code if the          # for some reason psql doesn't exit with an error code if the
340          # file given as -f doesn't exist, so we check manually by trying          # file given as -f doesn't exist, so we check manually by trying
# Line 255  class PostGISDatabase: Line 343  class PostGISDatabase:
343          f.close()          f.close()
344          del f          del f
345          run_command(["psql", "-f", self.postgis_sql, "-d", self.dbname,          run_command(["psql", "-f", self.postgis_sql, "-d", self.dbname,
346                       "-p", str(self.server.port), "-h", self.server.host],                       "-p", str(self.server.port), "-h", self.server.host,
347                         "-U", self.server.admin_name],
348                       os.path.join(self.server.dbdir, "psql.log"))                       os.path.join(self.server.dbdir, "psql.log"))
349    
350            self.server.execute_sql(self.dbname, "admin",
351                                    "GRANT SELECT ON geometry_columns TO PUBLIC;")
352    
353          if self.tables is not None:          if self.tables is not None:
354              for tablename, shapefile in self.tables:              for info  in self.tables:
355                  upload_shapefile(shapefile, self, tablename)                  if len(info) == 2:
356                        tablename, shapefile = info
357                        wkt_type = None
358                    else:
359                        tablename, shapefile, wkt_type = info
360                    upload_shapefile(shapefile, self, tablename,
361                                     force_wkt_type = wkt_type)
362    
363      def has_data(self, tables):      def has_data(self, tables):
364          return self.tables == tables          return self.tables == tables
# Line 354  def skip_if_no_postgis(): Line 452  def skip_if_no_postgis():
452      if _cannot_run_postgis_tests:      if _cannot_run_postgis_tests:
453          raise support.SkipTest(_cannot_run_postgis_tests)          raise support.SkipTest(_cannot_run_postgis_tests)
454    
455  def point_to_wkt(coords):  def coords_to_point(coords):
456      """Return string with a WKT representation of the point in coords"""      """Return string with a WKT representation of the point in coords"""
457      x, y = coords[0]      x, y = coords[0]
458      return "POINT(%r %r)" % (x, y)      return "POINT(%r %r)" % (x, y)
459    
460  def polygon_to_wkt(coords):  def coords_to_polygon(coords):
461      """Return string with a WKT representation of the polygon in coords"""      """Return string with a WKT representation of the polygon in coords"""
462      poly = []      poly = []
463      for ring in coords:      for ring in coords:
464          poly.append(", ".join(["%r %r" % p for p in ring]))          poly.append(", ".join(["%r %r" % p for p in ring]))
465      return "POLYGON((%s))" % "), (".join(poly)      return "POLYGON((%s))" % "), (".join(poly)
466    
467  def arc_to_wkt(coords):  def coords_to_multilinestring(coords):
468      """Return string with a WKT representation of the arc in coords"""      """Return string with a WKT representation of the arc in coords"""
469      poly = []      poly = []
470      for ring in coords:      for ring in coords:
471          poly.append(", ".join(["%r %r" % p for p in ring]))          poly.append(", ".join(["%r %r" % p for p in ring]))
472      return "MULTILINESTRING((%s))" % "), (".join(poly)      return "MULTILINESTRING((%s))" % "), (".join(poly)
473    
474  def upload_shapefile(filename, db, tablename):  def coords_to_multipolygon(coords):
475        """Return string with a WKT representation of the polygon in coords"""
476        poly = []
477        for ring in coords:
478            poly.append(", ".join(["%r %r" % p for p in ring]))
479        return "MULTIPOLYGON(((%s)))" % ")), ((".join(poly)
480    
481    wkt_converter = {
482        "POINT": coords_to_point,
483        "MULTILINESTRING": coords_to_multilinestring,
484        "POLYGON": coords_to_polygon,
485        "MULTIPOLYGON": coords_to_multipolygon,
486        }
487    
488    def upload_shapefile(filename, db, tablename, force_wkt_type = None):
489      import dbflib, shapelib      import dbflib, shapelib
490    
491        # We build this map here because we need shapelib which can only be
492        # imported after support.initthuban has been called which we can't
493        # easily do in this module because it's imported by support.
494        shp_to_wkt = {
495            shapelib.SHPT_POINT: "POINT",
496            shapelib.SHPT_ARC: "MULTILINESTRING",
497            shapelib.SHPT_POLYGON: "POLYGON",
498            }
499    
500      server = db.server      server = db.server
501      dbname = db.dbname      dbname = db.dbname
502      conn = psycopg.connect("host=%s port=%s dbname=%s"      conn = psycopg.connect("dbname=%s " % dbname
503                             % (server.host, server.port, dbname))                             + db.server.connection_string("admin"))
504      cursor = conn.cursor()      cursor = conn.cursor()
505    
506      shp = shapelib.ShapeFile(filename)      shp = shapelib.ShapeFile(filename)
# Line 400  def upload_shapefile(filename, db, table Line 521  def upload_shapefile(filename, db, table
521      #print stmt      #print stmt
522    
523      numshapes, shapetype, mins, maxs = shp.info()      numshapes, shapetype, mins, maxs = shp.info()
524      if shapetype == shapelib.SHPT_POINT:      wkttype =  shp_to_wkt[shapetype]
525          convert = point_to_wkt      if force_wkt_type:
526          wkttype = "POINT"          wkttype = force_wkt_type
527      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)  
528    
529      cursor.execute("select AddGeometryColumn('%(dbname)s',"      cursor.execute("select AddGeometryColumn('%(dbname)s',"
530                     "'%(tablename)s', 'the_geom', '-1', '%(wkttype)s', 2);"                     "'%(tablename)s', 'the_geom', '-1', '%(wkttype)s', 2);"
# Line 429  def upload_shapefile(filename, db, table Line 543  def upload_shapefile(filename, db, table
543          #print insert % data          #print insert % data
544          cursor.execute(insert, data)          cursor.execute(insert, data)
545    
546        cursor.execute("GRANT SELECT ON %s TO PUBLIC;" % tablename)
547    
548      conn.commit()      conn.commit()

Legend:
Removed from v.1605  
changed lines
  Added in v.1656

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26