maposmatic-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Maposmatic-dev] [PATCH ocitysmap] Use psycopg2 instead of pygresql (aka


From: David Decotigny
Subject: [Maposmatic-dev] [PATCH ocitysmap] Use psycopg2 instead of pygresql (aka. pgdb)
Date: Tue, 12 Jan 2010 00:15:46 +0100

From: David Decotigny <address@hidden>

Django relies on psycopg2 for its postgres backend, whereas ocitysmap
was using another (pgdb). This patch addresses task #9666: it removes
the pygresql dependency and changes it for psycopg2.

The major part of the patch deals with unicode issues, because
psycopg2 can handle unicode strings directly. Actual;ly, that's what
it does when it is being used along django. So we force this same
behavior as well when we run ocitysmap in plain "command line" mode.
---
 INSTALL                   |    4 +-
 ocitysmap/street_index.py |   99 +++++++++++++++++++++++++-------------------
 2 files changed, 58 insertions(+), 45 deletions(-)

diff --git a/INSTALL b/INSTALL
index 5bed944..965f42b 100644
--- a/INSTALL
+++ b/INSTALL
@@ -96,7 +96,7 @@ are using (here respectively Lenny and Intrepid or Jaunty).
     it like:
 
     ln -s /path/to/osm2pgsql/osm2pgsql /usr/local/bin/osm2pgsql
-    
+
  6. Import the Google spatial referential system
 
     The osm2pgsql tool creates data in the PostGIS database relative
@@ -214,7 +214,7 @@ are using (here respectively Lenny and Intrepid or Jaunty).
 
     c. Install dependencies
 
-    sudo aptitude install python-pygresql python-gdal
+    sudo aptitude install python-psycopg2 python-gdal
 
     d. Configuration file
 
diff --git a/ocitysmap/street_index.py b/ocitysmap/street_index.py
index 1f79d4c..af4bfa0 100644
--- a/ocitysmap/street_index.py
+++ b/ocitysmap/street_index.py
@@ -22,7 +22,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import logging, traceback
-import sys, os, tempfile, pgdb, re, math, cairo, locale, gzip, csv
+import sys, os, tempfile, psycopg2, re, math, cairo, locale, gzip, csv
 import ConfigParser
 import i18n
 from coords import BoundingBox
@@ -31,6 +31,12 @@ import map_canvas, grid, utils
 
 from draw_utils import enclose_in_frame
 
+import psycopg2.extensions
+# compatibility with django: see http://code.djangoproject.com/ticket/5996
+psycopg2.extensions.register_type(psycopg2.extensions.UNICODE)
+# SQL string escaping routine
+sql_escape_unicode = lambda s: psycopg2.extensions.adapt(s.encode('utf-8'))
+
 LOG = logging.getLogger('ocitysmap')
 STATEMENT_TIMEOUT_MINUTES = 18
 
@@ -96,7 +102,8 @@ class IndexPageGenerator:
         self.i18n = i18n
 
     def _get_font_parameters(self, cr, fontsize):
-        cr.select_font_face("DejaVu", cairo.FONT_SLANT_NORMAL, 
cairo.FONT_WEIGHT_NORMAL)
+        cr.select_font_face("DejaVu", cairo.FONT_SLANT_NORMAL,
+                            cairo.FONT_WEIGHT_NORMAL)
         cr.set_font_size(fontsize * 1.2)
         heading_fascent, heading_fdescent, heading_fheight = 
cr.font_extents()[:3]
 
@@ -105,7 +112,6 @@ class IndexPageGenerator:
         fascent, fdescent, fheight, fxadvance, fyadvance = cr.font_extents()
 
         em = cr.text_extents("m")[2]
-
         widths = map(lambda x: cr.text_extents(x[1])[2] + 
cr.text_extents(x[2])[2], self.streets)
         maxwidth = max(widths)
         colwidth = maxwidth + 3 * em
@@ -294,10 +300,14 @@ class OCitySMap:
 
         LOG.info('Connecting to database %s at %s (user: %s)...' %
                  (datasource['dbname'], datasource['host'], 
datasource['user']))
-        db = pgdb.connect(user=datasource['user'],
-                          password=datasource['password'],
-                          host=datasource['host'],
-                          database=datasource['dbname'])
+        db = psycopg2.connect(user=datasource['user'],
+                              password=datasource['password'],
+                              host=datasource['host'],
+                              database=datasource['dbname'])
+
+        # Force everything to be unicode-encoded, in case we run along
+        # django (which loads the unicode extensions for psycopg2)
+        db.set_client_encoding('utf8')
 
         # Set session timeout parameter (18mn)
         cursor = db.cursor()
@@ -355,8 +365,8 @@ class OCitySMap:
                           from planet_osm_line
                           where boundary='administrative' and
                                 admin_level='8' and
-                                name='%s';""" % \
-                           pgdb.escape_string(name.encode('utf-8')))
+                                name=%s;""" % \
+                           sql_escape_unicode(name))
         records = cursor.fetchall()
         if not records:
             raise UnsufficientDataError, "Wrong city name (%s) or missing 
administrative boundary in database!" % (repr(name))
@@ -451,8 +461,8 @@ class OCitySMap:
                                                   st_buildarea(way)), 4002))
                               from planet_osm_line
                               where boundary='administrative'
-                                 and admin_level='8' and name='%s';""" % \
-                               pgdb.escape_string(city.encode('utf-8')))
+                                 and admin_level='8' and name=%s;""" % \
+                               sql_escape_unicode(city))
         contour = cursor.fetchall()
         LOG.debug('Got contour.')
         return self.parse_city_contour(contour)
@@ -520,7 +530,7 @@ class OCitySMap:
     def humanize_street_list(self, sl):
         # We transform the string representing the squares list into a
         # Python list
-        sl = [( unicode(street[0].decode("utf-8")),
+        sl = [( street[0],
                 [ map(int, x.split(',')) for x in street[1].split(';')[:-1] ] )
               for street in sl]
 
@@ -597,7 +607,7 @@ class OCitySMap:
                                 from planet_osm_line
                                 join %s
                                 on st_intersects(way, st_transform(geom, 
900913))
-                                left join cities_area_by_name on city='%s'
+                                left join cities_area_by_name on city=%s
                                 where trim(name) != '' and highway is not null
                                 and case when cities_area_by_name.area is null
                                 then
@@ -609,10 +619,9 @@ class OCitySMap:
                           group by name
                           order by name;""" % \
                            (self._map_areas_table_name,
-                            pgdb.escape_string(city.encode('utf-8'))))
+                            sql_escape_unicode(city)))
 
         sl = cursor.fetchall()
-
        LOG.debug("Got %d streets." % len(sl))
         return self.humanize_street_list(sl)
 
@@ -675,6 +684,7 @@ class OCitySMap:
         sl = cursor.fetchall()
 
        LOG.debug("Got %d streets." % len(sl))
+        print "STREETS", repr(sl)
         return self.humanize_street_list(sl)
 
     # Given a list of amenities and their corresponding squares, do some
@@ -684,8 +694,7 @@ class OCitySMap:
     def humanize_amenity_list(self, am):
         # We transform the string representing the squares list into a
         # Python list
-        am = [( unicode(amenity[0].decode("utf-8")),
-                unicode(amenity[1].decode("utf-8")),
+        am = [( amenity[0], amenity[1],
                 [ map(int, x.split(',')) for x in amenity[2].split(';')[:-1] ] 
)
               for amenity in am]
 
@@ -748,12 +757,12 @@ class OCitySMap:
         al = []
         for cat, amenity, human in self.SELECTED_AMENITIES:
            LOG.info("Get amenities %s for %s..." % (repr(amenity), repr(city)))
-            cursor.execute("""select '%(category)s', name, textcat_all(x || 
',' || y || ';')
+            cursor.execute("""select %(category)s, name, textcat_all(x || ',' 
|| y || ';')
                               from (select distinct amenity, name, x, y, osm_id
                                     from planet_osm_point join %(tmp_tblname)s
                                     on st_intersects(way, st_transform(geom, 
900913))
-                                    left join cities_area_by_name on 
city='%(city)s'
-                                    where amenity = '%(amenity)s' and
+                                    left join cities_area_by_name on 
city=%(city)s
+                                    where amenity = %(amenity)s and
                                     case when cities_area_by_name.area is null
                                     then
                                       true
@@ -764,8 +773,8 @@ class OCitySMap:
                                     select distinct amenity, name, x, y, osm_id
                                     from planet_osm_polygon join 
%(tmp_tblname)s
                                     on st_intersects(way, st_transform(geom, 
900913))
-                                    left join cities_area_by_name on 
city='%(city)s'
-                                    where amenity = '%(amenity)s' and
+                                    left join cities_area_by_name on 
city=%(city)s
+                                    where amenity = %(amenity)s and
                                     case when cities_area_by_name.area is null
                                     then
                                       true
@@ -775,15 +784,12 @@ class OCitySMap:
                               as foo
                               group by amenity, osm_id, name
                               order by amenity, name
-                              """ % 
dict(category=pgdb.escape_string(cat.encode('utf-8')),
+                              """ % dict(category=sql_escape_unicode(cat),
                                          
tmp_tblname=self._map_areas_table_name,
-                                         amenity=amenity,
-                                         
city=pgdb.escape_string(city.encode('utf-8'))))
+                                         amenity=sql_escape_unicode(amenity),
+                                         city=sql_escape_unicode(city)))
            LOG.debug("Got amenities.")
-            sub_al = cursor.fetchall()
-            for a in sub_al:
-                if a[1] == None:
-                    a[1] = human.encode('utf-8')
+            sub_al = [(c,a or human,h) for c,a,h in cursor.fetchall()]
             sub_al = self.humanize_amenity_list(sub_al)
             al.extend(sub_al)
         return al
@@ -828,12 +834,12 @@ class OCitySMap:
         al = []
         for cat, amenity, human in self.SELECTED_AMENITIES:
            LOG.info("Get amenities %s for %s..." % (repr(amenity), 
repr(osmid)))
-            cursor.execute("""select '%(category)s', name, textcat_all(x || 
',' || y || ';')
+            cursor.execute("""select %(category)s, name, textcat_all(x || ',' 
|| y || ';')
                               from (select distinct amenity, name, x, y, 
planet_osm_point.osm_id
                                     from planet_osm_point join %(tmp_tblname)s
                                     on st_intersects(way, st_transform(geom, 
900913))
                                     left join cities_area_by_osmid on 
cities_area_by_osmid.osm_id=%(osm_id)d
-                                    where amenity = '%(amenity)s' and
+                                    where amenity = %(amenity)s and
                                     case when cities_area_by_osmid.area is null
                                     then
                                       true
@@ -845,7 +851,7 @@ class OCitySMap:
                                     from planet_osm_polygon join 
%(tmp_tblname)s
                                     on st_intersects(way, st_transform(geom, 
900913))
                                     left join cities_area_by_osmid on 
cities_area_by_osmid.osm_id=%(osm_id)d
-                                    where amenity = '%(amenity)s' and
+                                    where amenity = %(amenity)s and
                                     case when cities_area_by_osmid.area is null
                                     then
                                       true
@@ -855,15 +861,12 @@ class OCitySMap:
                               as foo
                               group by amenity, osm_id, name
                               order by amenity, name
-                              """ % 
dict(category=pgdb.escape_string(cat.encode('utf-8')),
+                              """ % dict(category=sql_escape_unicode(cat),
                                          
tmp_tblname=self._map_areas_table_name,
-                                         amenity=amenity,
+                                         amenity=sql_escape_unicode(amenity),
                                          osm_id=osmid))
            LOG.debug("Got amenities.")
-            sub_al = cursor.fetchall()
-            for a in sub_al:
-                if a[1] == None:
-                    a[1] = human.encode('utf-8')
+            sub_al = sub_al = [(c,a or human,h) for c,a,h in cursor.fetchall()]
             sub_al = self.humanize_amenity_list(sub_al)
             al.extend(sub_al)
 
@@ -890,16 +893,26 @@ class OCitySMap:
                 LOG.warning('error while opening destination file %s: %s'
                           % (output_filename, ex))
             else:
+                # Try to treat indifferently unicode and str in CSV rows
+                def csv_writerow(row):
+                    _r = []
+                    for e in row:
+                        if type(e) is unicode:
+                            _r.append(e.encode('UTF-8'))
+                        else:
+                            _r.append(e)
+                    return writer.writerow(_r)
+
                 copyright_notice = (u'© 2009 MapOSMatic/ocitysmap authors. '
                                     u'Map data © 2009 OpenStreetMap.org '
-                                    u'and contributors 
(CC-BY-SA)').encode('UTF-8')
+                                    u'and contributors (CC-BY-SA)')
                 if title is not None:
-                    writer.writerow(['# (UTF-8)', title.encode('UTF-8'), 
copyright_notice])
+                    csv_writerow(['# (UTF-8)', title, copyright_notice])
                 else:
-                    writer.writerow(['# (UTF-8)', '', copyright_notice])
+                    csv_writerow(['# (UTF-8)', '', copyright_notice])
 
-                for street in self.streets + self.amenities:
-                    writer.writerow([e.encode('UTF-8') for e in street])
+                for entry in self.streets + self.amenities:
+                    csv_writerow(entry)
             return
 
         if file_type in ('png', 'png24'):
-- 
1.6.4.4





reply via email to

[Prev in Thread] Current Thread [Next in Thread]