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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2096 - (show annotations)
Thu Mar 11 13:50:53 2004 UTC (20 years, 11 months ago) by bh
Original Path: trunk/thuban/test/postgissupport.py
File MIME type: text/x-python
File size: 25586 byte(s)
* Thuban/Model/postgisdb.py (PostGISTable.__init__): New parameter
id_column to specify which column to use to identify rows.  Also
new instance variables id_column and quoted_id_column
(PostGISTable.RowIdToOrdinal, PostGISTable.RowOrdinalToId)
(PostGISTable.ReadRowAsDict, PostGISTable.ReadValue)
(PostGISTable.SimpleQuery): Use the id column name provided to the
constructor instead of "gid"
(PostGISShapeStore.__init__): New parameter id_column analogously
to PostGISTable.__init__.  This parameter is simply passed through
to the base class constructor
(PostGISShapeStore._create_col_from_description): Fix typo in
doc-string
(PostGISShapeStore.Shape, PostGISShapeStore.AllShapes)
(PostGISShapeStore.ShapesInRegion): Use the id column name
provided to the constructor instead of "gid"

* test/postgissupport.py
(PostgreSQLServer.get_default_static_data_db): New static table
landmarks_point_id with an id column != "gid.  Update the comments
a bit.
(skip_if_addgeometrycolumn_does_not_use_quote_ident): Fix typo in
doc-
(upload_shapefile): New parameter gid_column to use a name other
than "gid" for the column to store the shape ids

* test/test_postgis_db.py (TableTests): New.  Mixin-class
containing all tests previously in TestPostGISTable.  The actual
tests are the same but the code is a bit more configurable to
allow for different id columns etc.
(TestPostGISTable): Derive from TableTests now for the actual
tests.
(TestPostGISTableExplicitGIDColumn): New. Like TestPostGISTable
except that it the landmarks_point_id table to test the id_column
parameter
(PointTests): Extend the doc-string
(TestPostGISShapestorePointExplicitGIDColumn)
(TestPostGISShapestorePointOIDAsGIDColumn): New classes derived
from PointTests to test the explicit id_column parameter.  One
tests with the name of the column holding the shape ids, the other
uses PostgreSQL's OID column.  For the latter a number of methods
have to be overwritten to make them independent of the actual id
values.

1 # Copyright (C) 2003, 2004 by Intevation GmbH
2 # Authors:
3 # Bernhard Herzog <[email protected]>
4 #
5 # This program is free software under the GPL (>=v2)
6 # Read the file COPYING coming with the software for details.
7
8 """Support module for tests that use a live PostGIS database"""
9
10 __version__ = "$Revision$"
11 # $Source$
12 # $Id$
13
14 import sys
15 import os
16 import time
17 import popen2
18 import shutil
19 import traceback
20
21 import support
22
23 try:
24 import psycopg
25 except ImportError:
26 psycopg = None
27
28 #
29 # Helper code
30 #
31
32 def run_config_script(cmdline):
33 """Run command cmdline and return its stdout or none in case of errors"""
34 pipe = os.popen(cmdline)
35 result = pipe.read()
36 if pipe.close() is not None:
37 raise RuntimeError('Command %r failed' % cmdline)
38 return result
39
40 def run_command(command, outfilename = None):
41 """Run command as a subprocess and send its stdout and stderr to outfile
42
43 The subprocess is run synchroneously so the function returns once
44 the subprocess has termninated. If the process' exit code is not
45 zero raise a RuntimeError.
46
47 If outfilename is None stdout and stderr are still captured but they
48 are ignored and not written to any file.
49 """
50 proc = popen2.Popen4(command)
51 proc.tochild.close()
52 output = proc.fromchild.read()
53 status = proc.wait()
54 if outfilename is not None:
55 outfile = open(outfilename, "w")
56 outfile.write(output)
57 outfile.close()
58 if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
59 if outfilename:
60 message = "see %s" % outfilename
61 else:
62 message = output
63 raise RuntimeError("command %r exited with code %d.\n%s"
64 % (command, status, message))
65
66
67 def run_boolean_command(command):
68 """
69 Run command as a subprocess silently and return whether it ran successfully
70
71 Silently means that all output is captured and ignored. The exit
72 status is true if the command ran successfull, i.e. it terminated by
73 exiting and returned as zero exit code and false other wise
74 """
75 try:
76 run_command(command, None)
77 return 1
78 except RuntimeError:
79 pass
80 return 0
81
82
83 #
84 # PostgreSQL and database
85 #
86
87 class PostgreSQLServer:
88
89 """A PostgreSQL server
90
91 Instances of this class represent a PostgreSQL server with postgis
92 extensions run explicitly for the test cases. Such a server has its
93 own database directory and its own directory for the unix sockets so
94 that it doesn't interfere with any other PostgreSQL server already
95 running on the system.
96 """
97
98 def __init__(self, dbdir, port, postgis_sql, socket_dir):
99 """Initialize the PostgreSQLServer object
100
101 Parameters:
102
103 dbdir -- The directory for the databases
104 port -- The port to use
105 postgis_sql -- The name of the file with the SQL statements to
106 initialize a database for postgis.
107 socket_dir -- The directory for the socket files.
108
109 When connecting to the database server use the port and host
110 instance variables.
111 """
112 self.dbdir = dbdir
113 self.port = port
114 self.postgis_sql = postgis_sql
115 self.socket_dir = socket_dir
116
117 # For the client side the socket directory can be used as the
118 # host if the name starts with a slash.
119 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
128 self.known_dbs = {}
129
130 def createdb(self):
131 """Create the database in dbdir and start the server.
132
133 First check whether the dbdir already exists and if necessary
134 stop an already running postmaster and remove the dbdir
135 directory completely. Then create a new database cluster in the
136 dbdir and start a postmaster.
137 """
138 if os.path.isdir(self.dbdir):
139 if self.is_running():
140 self.shutdown()
141 shutil.rmtree(self.dbdir)
142 os.mkdir(self.dbdir)
143
144 run_command(["initdb", "-D", self.dbdir, "-U", self.admin_name],
145 os.path.join(self.dbdir, "initdb.log"))
146
147 extra_opts = "-p %d" % self.port
148 if self.socket_dir is not None:
149 extra_opts += " -k %s" % self.socket_dir
150 run_command(["pg_ctl", "-D", self.dbdir,
151 "-l", os.path.join(self.dbdir, "logfile"),
152 "-o", extra_opts, "start"],
153 os.path.join(self.dbdir, "pg_ctl-start.log"))
154 # the -w option of pg_ctl doesn't work properly when the port is
155 # not the default port, so we have to implement waiting for the
156 # server ourselves
157 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):
163 """Return when the database server is running
164
165 Internal method to wait until the postmaster process has been
166 started and is ready for client connections.
167 """
168 max_count = 60
169 count = 0
170 while count < max_count:
171 try:
172 run_command(["psql", "-l", "-p", str(self.port),
173 "-h", self.host, "-U", self.admin_name],
174 os.path.join(self.dbdir, "psql-%d.log" % count))
175 except RuntimeError:
176 pass
177 except:
178 traceback.print_exc()
179 else:
180 break
181 time.sleep(0.5)
182 count += 1
183 else:
184 raise RuntimeError("postmaster didn't start")
185
186 def is_running(self):
187 """Return true a postmaster process is running on self.dbdir
188
189 This method runs pg_ctl status on the dbdir so even if the
190 object has just been created it is possible that this method
191 returns true if there's still a postmaster process running for
192 self.dbdir.
193 """
194 return run_boolean_command(["pg_ctl", "-D", self.dbdir, "status"])
195
196 def shutdown(self):
197 """Stop the postmaster running for self.dbdir"""
198 run_command(["pg_ctl", "-m", "fast", "-D", self.dbdir, "stop"],
199 os.path.join(self.dbdir, "pg_ctl-stop.log"))
200
201 def new_postgis_db(self, dbname, tables = None, reference_systems = None):
202 """Create and return a new PostGISDatabase object using self as server
203 """
204 db = PostGISDatabase(self, self.postgis_sql, dbname, tables = tables,
205 reference_systems = reference_systems)
206 db.initdb()
207 self.known_dbs[dbname] = db
208 return db
209
210 def get_static_data_db(self, dbname, tables, reference_systems):
211 """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
214 new_postgis_db and upload the data.
215
216 If a database of the name dbname already exists and uses the
217 indicated data, return that. If the already existing db uses
218 different data raise a value error.
219
220 If the database doesn't exist, create a new one via
221 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)
227 if db is not None:
228 if db.has_data(tables, reference_systems):
229 return db
230 raise ValueError("PostGISDatabase named %r doesn't have tables %r"
231 % (dbname, tables))
232 return self.new_postgis_db(dbname, tables, reference_systems)
233
234 def get_default_static_data_db(self):
235 dbname = "PostGISStaticTests"
236 srids = [(1, "proj=longlat datum=WGS84")]
237 tables = [
238 # Direct copies of the shapefiles. The shapeids are exactly
239 # the same, except where changed with "gid_offset", of
240 # course. Note that the test implementation requires that
241 # all the landmard tables use an gid_offset of 1000.
242 ("landmarks", os.path.join("..", "Data", "iceland",
243 "cultural_landmark-point.shp"),
244 [("gid_offset", 1000)]),
245 ("political", os.path.join("..", "Data", "iceland",
246 "political.shp")),
247 ("roads", os.path.join("..", "Data", "iceland",
248 "roads-line.shp")),
249
250 # The polygon data as a MULTIPOLYGON geometry type
251 ("political_multi", os.path.join("..", "Data", "iceland",
252 "political.shp"),
253 [("force_wkt_type", "MULTIPOLYGON")]),
254
255 # Copy of landmarks but using an srid != -1
256 ("landmarks_srid", os.path.join("..", "Data", "iceland",
257 "cultural_landmark-point.shp"),
258 [("gid_offset", 1000),
259 ("srid", 1)]),
260
261 # Copy of landmarks with a gid column called "point_id" instead
262 # of "gid" and using an srid != -1.
263 ("landmarks_point_id", os.path.join("..", "Data", "iceland",
264 "cultural_landmark-point.shp"),
265 [("gid_offset", 1000),
266 ("srid", 1),
267 ("gid_column", "point_id")]),
268 ]
269 return self.get_static_data_db(dbname, tables, srids)
270
271 def connection_params(self, user):
272 """Return the connection parameters for the given user
273
274 The return value is a dictionary suitable as keyword argument
275 list to PostGISConnection. The user parameter may be either
276 'admin' to connect as admin or 'user' to connect as an
277 unprivileged user.
278 """
279 return {"host": self.host, "port": self.port,
280 "user": getattr(self, user + "_name"),
281 "password": getattr(self, user + "_password")}
282
283 def connection_string(self, user):
284 """Return (part of) the connection string to pass to psycopg.connect
285
286 The string contains host, port, user and password. The user
287 parameter must be either 'admin' or 'user', as for
288 connection_params.
289 """
290 params = []
291 for key, value in self.connection_params(user).items():
292 # FIXME: this doesn't do quiting correctly but that
293 # shouldn't be much of a problem (people shouldn't be using
294 # single quotes in filenames anyway :) )
295 params.append("%s='%s'" % (key, value))
296 return " ".join(params)
297
298 def execute_sql(self, dbname, user, sql):
299 """Execute the sql statament
300
301 The user parameter us used as in connection_params. The dbname
302 parameter must be the name of a database in the cluster.
303 """
304 conn = psycopg.connect("dbname=%s " % dbname
305 + self.connection_string(user))
306 cursor = conn.cursor()
307 cursor.execute(sql)
308 conn.commit()
309 conn.close()
310
311 def require_authentication(self, required):
312 """Switch authentication requirements on or off
313
314 When started for the first time no passwords are required. Some
315 tests want to explicitly test whether Thuban's password
316 infrastructure works and switch password authentication on
317 explicitly. When switching it on, there should be a
318 corresponding call to switch it off again in the test case'
319 tearDown method or in a finally: block.
320 """
321 if required:
322 contents = "local all password\n"
323 else:
324 contents = "local all trust\n"
325 f = open(os.path.join(self.dbdir, "pg_hba.conf"), "w")
326 f.write(contents)
327 f.close()
328 run_command(["pg_ctl", "-D", self.dbdir, "reload"],
329 os.path.join(self.dbdir, "pg_ctl-reload.log"))
330
331
332 def create_user(self, username, password):
333 """Create user username with password in the database"""
334 self.execute_sql("template1", "admin",
335 "CREATE USER %s PASSWORD '%s';" % (username,password))
336
337 def alter_user(self, username, password):
338 """Change the user username's password in the database"""
339 self.execute_sql("template1", "admin",
340 "ALTER USER %s PASSWORD '%s';" % (username,password))
341
342
343 class PostGISDatabase:
344
345 """A PostGIS database in a PostgreSQLServer"""
346
347 def __init__(self, server, postgis_sql, dbname, tables = None,
348 reference_systems = ()):
349 """Initialize the PostGISDatabase
350
351 Parameters:
352
353 server -- The PostgreSQLServer instance containing the
354 database
355
356 postgis_sql -- Filename of the postgis.sql file with the
357 postgis initialization code
358
359 dbname -- The name of the database
360
361 tables -- Optional description of tables to create in the
362 new database. If given it should be a list of
363 (tablename, shapefilename) pairs meaning that a table
364 tablename will be created with the contents of the given
365 shapefile or (tablename, shapefilename, extraargs)
366 triples. The extraargs should be a list of key, value
367 pairs to use as keyword arguments to upload_shapefile.
368
369 reference_systems -- Optional description of spatial
370 reference systems. If given, it should be a sequence of
371 (srid, params) pairs where srid is the srid defined by
372 the proj4 paramter string params. The srid can be given
373 as an extra parameter in the tables list.
374 """
375 self.server = server
376 self.postgis_sql = postgis_sql
377 self.dbname = dbname
378 self.tables = tables
379 if reference_systems:
380 self.reference_systems = reference_systems
381 else:
382 # Make sure that it's a sequence we can iterate over even if
383 # the parameter's None
384 self.reference_systems = ()
385
386 def initdb(self):
387 """Remove the old db directory and create and initialize a new database
388 """
389 run_command(["createdb", "-p", str(self.server.port),
390 "-h", self.server.host, "-U", self.server.admin_name,
391 self.dbname],
392 os.path.join(self.server.dbdir, "createdb.log"))
393 run_command(["createlang", "-p", str(self.server.port),
394 "-h", self.server.host, "-U", self.server.admin_name,
395 "plpgsql", self.dbname],
396 os.path.join(self.server.dbdir, "createlang.log"))
397 # for some reason psql doesn't exit with an error code if the
398 # file given as -f doesn't exist, so we check manually by trying
399 # to open it before we run psql
400 f = open(self.postgis_sql)
401 f.close()
402 del f
403 run_command(["psql", "-f", self.postgis_sql, "-d", self.dbname,
404 "-p", str(self.server.port), "-h", self.server.host,
405 "-U", self.server.admin_name],
406 os.path.join(self.server.dbdir, "psql.log"))
407
408 self.server.execute_sql(self.dbname, "admin",
409 "GRANT SELECT ON geometry_columns TO PUBLIC;")
410 self.server.execute_sql(self.dbname, "admin",
411 "GRANT SELECT ON spatial_ref_sys TO PUBLIC;")
412
413 for srid, params in self.reference_systems:
414 self.server.execute_sql(self.dbname, "admin",
415 "INSERT INTO spatial_ref_sys VALUES"
416 " (%d, '', %d, '', '%s');"
417 % (srid, srid, params))
418 if self.tables is not None:
419 def unpack(item):
420 extra = {"force_wkt_type": None, "gid_offset": 0,
421 "srid": -1}
422 if len(info) == 2:
423 tablename, shapefile = info
424 else:
425 tablename, shapefile, kw = info
426 for key, val in kw:
427 extra[key] = val
428 return tablename, shapefile, extra
429
430 for info in self.tables:
431 tablename, shapefile, kw = unpack(info)
432 upload_shapefile(shapefile, self, tablename, **kw)
433
434 def has_data(self, tables, reference_systems):
435 return (self.tables == tables
436 and self.reference_systems == reference_systems)
437
438
439 def find_postgis_sql():
440 """Return the name of the postgis_sql file
441
442 A postgis installation usually has the postgis_sql file in
443 PostgreSQL's datadir (i.e. the directory where PostgreSQL keeps
444 static files, not the directory containing the databases).
445 Unfortunately there's no way to determine the name of this directory
446 with pg_config so we assume here that it's
447 $bindir/../share/postgresql/.
448 """
449 bindir = run_config_script("pg_config --bindir").strip()
450 return os.path.join(bindir, "..", "share", "postgresql",
451 "contrib", "postgis.sql")
452
453 _postgres_server = None
454 def get_test_server():
455 """Return the test database server object.
456
457 If it doesn't exist yet, create it first.
458
459 The server will use the directory postgis under the temp dir (as
460 defined by support.create_temp_dir()) for the database cluster.
461 Sockets will be created in tempdir.
462 """
463 global _postgres_server
464 if _postgres_server is None:
465 tempdir = support.create_temp_dir()
466 dbdir = os.path.join(tempdir, "postgis")
467 socket_dir = tempdir
468
469 _postgres_server = PostgreSQLServer(dbdir, 6543, find_postgis_sql(),
470 socket_dir = socket_dir)
471 _postgres_server.createdb()
472
473 return _postgres_server
474
475 def shutdown_test_server():
476 """Shutdown the test server if it is running"""
477 global _postgres_server
478 if _postgres_server is not None:
479 _postgres_server.shutdown()
480 _postgres_server = None
481
482
483 def reason_for_not_running_tests():
484 """
485 Determine whether postgis tests can be run and return a reason they can't
486
487 There's no fool-proof way to reliably determine this short of
488 actually running the tests but we try the following here:
489
490 - test whether pg_ctl --help can be run successfully
491 - test whether the postgis_sql can be opened
492 The name of the postgis_sql file is determined by find_postgis_sql()
493 - psycopg can be imported successfully.
494 """
495 # run_command currently uses Popen4 which is not available under
496 # Windows, for example.
497 if not hasattr(popen2, "Popen4"):
498 return "Can't run PostGIS test because popen2.Popen4 does not exist"
499
500 try:
501 run_command(["pg_ctl", "--help"], None)
502 except RuntimeError:
503 return "Can't run PostGIS tests because pg_ctl fails"
504
505 try:
506 postgis_sql = find_postgis_sql()
507 except:
508 return "Can't run PostGIS tests because postgis.sql can't be found"
509
510 try:
511 f = open(postgis_sql)
512 f.close()
513 except:
514 return "Can't run PostGIS tests because postgis.sql can't be opened"
515
516 # The test for psycopg was already done when this module was
517 # imported so we only have to check whether it was successful
518 if psycopg is None:
519 return "Can't run PostGIS tests because psycopg can't be imported"
520
521 return ""
522
523
524 _cannot_run_postgis_tests = None
525 def skip_if_no_postgis():
526 global _cannot_run_postgis_tests
527 if _cannot_run_postgis_tests is None:
528 _cannot_run_postgis_tests = reason_for_not_running_tests()
529 if _cannot_run_postgis_tests:
530 raise support.SkipTest(_cannot_run_postgis_tests)
531
532 def skip_if_addgeometrycolumn_does_not_use_quote_ident():
533 """Skip a test if the AddGeometryColumn function doesn't use quote_ident
534
535 If the AddGeometryColumn function doesn't use quote_ident it doesn't
536 support unusual table or column names properly, that is, it will
537 fail with errors for names that contain spaces or double quotes.
538
539 The test performed by this function is a bit simplistic because it
540 only tests whether the string 'quote_ident' occurs anywhere in the
541 postgis.sql file. This will hopefully work because when this was
542 fixed in postgis CVS AddGeometryColumn was the first function to use
543 quote_ident.
544 """
545 f = file(find_postgis_sql())
546 content = f.read()
547 f.close()
548 if content.find("quote_ident") < 0:
549 raise support.SkipTest("AddGeometryColumn doesn't use quote_ident")
550
551 def coords_to_point(coords):
552 """Return string with a WKT representation of the point in coords"""
553 x, y = coords[0]
554 return "POINT(%r %r)" % (x, y)
555
556 def coords_to_polygon(coords):
557 """Return string with a WKT representation of the polygon in coords"""
558 poly = []
559 for ring in coords:
560 poly.append(", ".join(["%r %r" % p for p in ring]))
561 return "POLYGON((%s))" % "), (".join(poly)
562
563 def coords_to_multilinestring(coords):
564 """Return string with a WKT representation of the arc in coords"""
565 poly = []
566 for ring in coords:
567 poly.append(", ".join(["%r %r" % p for p in ring]))
568 return "MULTILINESTRING((%s))" % "), (".join(poly)
569
570 def coords_to_multipolygon(coords):
571 """Return string with a WKT representation of the polygon in coords"""
572 poly = []
573 for ring in coords:
574 poly.append(", ".join(["%r %r" % p for p in ring]))
575 return "MULTIPOLYGON(((%s)))" % ")), ((".join(poly)
576
577 wkt_converter = {
578 "POINT": coords_to_point,
579 "MULTILINESTRING": coords_to_multilinestring,
580 "POLYGON": coords_to_polygon,
581 "MULTIPOLYGON": coords_to_multipolygon,
582 }
583
584 def upload_shapefile(filename, db, tablename, force_wkt_type = None,
585 gid_offset = 0, gid_column = "gid", srid = -1):
586 """Upload a shapefile into a new database table
587
588 Parameters:
589
590 filename -- The name of the shapefile
591
592 db -- The PostGISDatabase instance representing the database
593
594 tablename -- The name of the table to create and into which the data
595 is to be inserted
596
597 force_wkt_type -- If given the real WKT geometry type to use instead
598 of the default that would be chosen based on the type of
599 the shapefile
600
601 gid_offset -- A number to add to the shapeid to get the value for
602 the gid column (default 0)
603
604 gid_column -- The name of the column with the shape ids. Default
605 'gid'. If None, no gid column will be created. The
606 name is directly used in SQL statements, so if it
607 contains unusualy characters the caller should provide
608 a suitable quoted string.
609
610 srid -- The srid of the spatial references system used by the table
611 and the data
612 """
613 import dbflib, shapelib
614
615 # We build this map here because we need shapelib which can only be
616 # imported after support.initthuban has been called which we can't
617 # easily do in this module because it's imported by support.
618 shp_to_wkt = {
619 shapelib.SHPT_POINT: "POINT",
620 shapelib.SHPT_ARC: "MULTILINESTRING",
621 shapelib.SHPT_POLYGON: "POLYGON",
622 }
623
624 server = db.server
625 dbname = db.dbname
626 conn = psycopg.connect("dbname=%s " % dbname
627 + db.server.connection_string("admin"))
628 cursor = conn.cursor()
629
630 shp = shapelib.ShapeFile(filename)
631 dbf = dbflib.DBFFile(filename)
632 typemap = {dbflib.FTString: "VARCHAR",
633 dbflib.FTInteger: "INTEGER",
634 dbflib.FTDouble: "DOUBLE PRECISION"}
635
636 insert_formats = []
637 if gid_column:
638 insert_formats.append("%(gid)s")
639
640 fields = []
641 fields_decl = []
642 if gid_column:
643 fields.append(gid_column)
644 fields_decl.append("%s INT" % gid_column)
645 for i in range(dbf.field_count()):
646 ftype, name, width, prec = dbf.field_info(i)
647 fields.append(name)
648 fields_decl.append("%s %s" % (name, typemap[ftype]))
649 insert_formats.append("%%(%s)s" % name)
650 stmt = "CREATE TABLE %s (\n %s\n);" % (tablename,
651 ",\n ".join(fields_decl))
652 cursor.execute(stmt)
653 #print stmt
654
655 numshapes, shapetype, mins, maxs = shp.info()
656 wkttype = shp_to_wkt[shapetype]
657 if force_wkt_type:
658 wkttype = force_wkt_type
659 convert = wkt_converter[wkttype]
660
661 cursor.execute("select AddGeometryColumn('%(dbname)s',"
662 "'%(tablename)s', 'the_geom', %(srid)d, '%(wkttype)s', 2);"
663 % locals())
664 fields.append("the_geom")
665 insert_formats.append("GeometryFromText(%(the_geom)s, %(srid)d)")
666
667 insert = ("INSERT INTO %s (%s) VALUES (%s)"
668 % (tablename, ", ".join(fields), ", ".join(insert_formats)))
669
670 for i in range(numshapes):
671 data = dbf.read_record(i)
672 data["tablename"] = tablename
673 if gid_column:
674 data["gid"] = i + gid_offset
675 data["srid"] = srid
676 data["the_geom"] = convert(shp.read_object(i).vertices())
677 #print insert % data
678 cursor.execute(insert, data)
679
680 cursor.execute("GRANT SELECT ON %s TO PUBLIC;" % tablename)
681
682 conn.commit()

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26