[tilestache] 01/05: Imported Upstream version 1.51.5
Bas Couwenberg
sebastic at debian.org
Wed Jan 25 20:37:48 UTC 2017
This is an automated email from the git hooks/post-receive script.
sebastic pushed a commit to branch master
in repository tilestache.
commit 35c6dd9ae5497ecda62dc2a501afdc5ce364b794
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date: Wed Jan 25 21:23:16 2017 +0100
Imported Upstream version 1.51.5
---
.travis.yml | 3 +-
CHANGELOG | 5 +++
README.md | 2 +-
TileStache/Caches.py | 14 +++----
TileStache/Config.py | 70 +++++++++------------------------
TileStache/Core.py | 67 +++++++++++++++++++++++++++----
TileStache/Geography.py | 7 ++--
TileStache/Goodies/VecTiles/client.py | 20 ++++++++--
TileStache/Goodies/VecTiles/geojson.py | 25 ++++++------
TileStache/Goodies/VecTiles/mvt.py | 6 ++-
TileStache/Goodies/VecTiles/server.py | 19 +++++++--
TileStache/Goodies/VecTiles/topojson.py | 6 +--
TileStache/Goodies/VecTiles/wkb.py | 6 ++-
TileStache/Mapnik.py | 5 ++-
TileStache/Memcache.py | 9 ++++-
TileStache/Pixels.py | 6 ++-
TileStache/Providers.py | 16 ++++++--
TileStache/VERSION | 2 +-
TileStache/Vector/Arc.py | 2 +-
TileStache/Vector/__init__.py | 17 +++++---
TileStache/__init__.py | 46 ++++++++++++++++------
requirements.txt | 3 +-
setup.py | 2 +-
tests/cache_tests.py | 17 +++++---
tests/provider_tests.py | 11 +++---
tests/servers/dummy-response-server.py | 5 ++-
tests/utils.py | 15 ++++---
tests/vectiles_tests.py | 47 +++++++++++-----------
tests/vector_tests.py | 10 ++---
29 files changed, 287 insertions(+), 176 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index 4300763..75450f2 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,12 +8,13 @@ dist: trusty
python:
- "2.7"
+ - "3.4"
addons:
postgresql: "9.4"
apt:
packages:
- - postgresql-9.4-postgis-2.2
+ - postgresql-9.4-postgis-2.3
- python-dev
- libgdal1-dev
- python-werkzeug
diff --git a/CHANGELOG b/CHANGELOG
index 360a1e7..236e613 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,8 @@
+2017-01-25: 1.51.5
+- Fix to be compliant with mapnik 3 grid renderer
+- Fix of preview protocol
+- Moving towards python 3 compliance
+
2016-12-21: 1.51.4
- Support for GDAL 2.x types OFTInteger64 and OFTInteger64 on Vector Tiles
diff --git a/README.md b/README.md
index d23aa28..8c893e5 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
_a stylish alternative for caching your map tiles_
-[](https://travis-ci.org/TileStache/TileStache)
+[](https://travis-ci.org/TileStache/TileStache)
**TileStache** is a Python-based server application that can serve up map tiles
based on rendered geographic data. You might be familiar with [TileCache](http://tilecache.org),
diff --git a/TileStache/Caches.py b/TileStache/Caches.py
index ffd113b..eae4e5b 100644
--- a/TileStache/Caches.py
+++ b/TileStache/Caches.py
@@ -183,7 +183,7 @@ class Disk:
"http://example.com/tilestache.cfg", the path *must* be an unambiguous
filesystem path, e.g. "file:///tmp/cache"
"""
- def __init__(self, path, umask=0022, dirs='safe', gzip='txt text json xml'.split()):
+ def __init__(self, path, umask=0o022, dirs='safe', gzip='txt text json xml'.split()):
self.cachepath = path
self.umask = int(umask)
self.dirs = dirs
@@ -271,9 +271,9 @@ class Disk:
# Oh - no they didn't.
pass
- os.makedirs(lockpath, 0777&~self.umask)
+ os.makedirs(lockpath, 0o777&~self.umask)
break
- except OSError, e:
+ except OSError as e:
if e.errno != 17:
raise
time.sleep(.2)
@@ -300,7 +300,7 @@ class Disk:
try:
os.remove(fullpath)
- except OSError, e:
+ except OSError as e:
# errno=2 means that the file does not exist, which is fine
if e.errno != 2:
raise
@@ -332,8 +332,8 @@ class Disk:
try:
umask_old = os.umask(self.umask)
- os.makedirs(dirname(fullpath), 0777&~self.umask)
- except OSError, e:
+ os.makedirs(dirname(fullpath), 0o777&~self.umask)
+ except OSError as e:
if e.errno != 17:
raise
finally:
@@ -359,7 +359,7 @@ class Disk:
os.unlink(fullpath)
os.rename(tmp_path, fullpath)
- os.chmod(fullpath, 0666&~self.umask)
+ os.chmod(fullpath, 0o666&~self.umask)
class Multi:
""" Caches tiles to multiple, ordered caches.
diff --git a/TileStache/Config.py b/TileStache/Config.py
index 18c91ef..2dfa6f6 100644
--- a/TileStache/Config.py
+++ b/TileStache/Config.py
@@ -60,11 +60,19 @@ documentation for TileStache.Providers, TileStache.Core, and TileStache.Geograph
import sys
import logging
-from sys import stderr, modules
+from sys import modules
from os.path import realpath, join as pathjoin
-from urlparse import urljoin, urlparse
+try:
+ from urllib.parse import urljoin, urlparse
+except ImportError:
+ # Python 2
+ from urlparse import urljoin, urlparse
from mimetypes import guess_type
-from urllib import urlopen
+try:
+ from urllib.request import urlopen
+except ImportError:
+ # Python 2
+ from urllib import urlopen
from json import dumps
try:
@@ -75,11 +83,11 @@ except ImportError:
from ModestMaps.Geo import Location
from ModestMaps.Core import Coordinate
-import Core
-import Caches
-import Providers
-import Geography
-import PixelEffects
+from . import Core
+from . import Caches
+from . import Providers
+from . import Geography
+from . import PixelEffects
class Configuration:
""" A complete site configuration, with a collection of Layer objects.
@@ -315,7 +323,7 @@ def _parseConfigCache(cache_dict, dirpath):
raise Exception('Unknown cache: %s' % cache_dict['name'])
elif 'class' in cache_dict:
- _class = loadClassPath(cache_dict['class'])
+ _class = Core.loadClassPath(cache_dict['class'])
kwargs = cache_dict.get('kwargs', {})
kwargs = dict( [(str(k), v) for (k, v) in kwargs.items()] )
@@ -449,7 +457,7 @@ def _parseConfigLayer(layer_dict, config, dirpath):
provider_kwargs = _class.prepareKeywordArgs(provider_dict)
elif 'class' in provider_dict:
- _class = loadClassPath(provider_dict['class'])
+ _class = Core.loadClassPath(provider_dict['class'])
provider_kwargs = provider_dict.get('kwargs', {})
provider_kwargs = dict( [(str(k), v) for (k, v) in provider_kwargs.items()] )
@@ -467,45 +475,3 @@ def _parseConfigLayer(layer_dict, config, dirpath):
layer.pixel_effect = pixel_effect
return layer
-
-def loadClassPath(classpath):
- """ Load external class based on a path.
-
- Example classpath: "Module.Submodule:Classname".
-
- Equivalent soon-to-be-deprecated classpath: "Module.Submodule.Classname".
- """
- if ':' in classpath:
- #
- # Just-added support for "foo:blah"-style classpaths.
- #
- modname, objname = classpath.split(':', 1)
-
- try:
- __import__(modname)
- module = modules[modname]
- _class = eval(objname, module.__dict__)
-
- if _class is None:
- raise Exception('eval(%(objname)s) in %(modname)s came up None' % locals())
-
- except Exception, e:
- raise Core.KnownUnknown('Tried to import %s, but: %s' % (classpath, e))
-
- else:
- #
- # Support for "foo.blah"-style classpaths, TODO: deprecate this in v2.
- #
- classpath = classpath.split('.')
-
- try:
- module = __import__('.'.join(classpath[:-1]), fromlist=str(classpath[-1]))
- except ImportError, e:
- raise Core.KnownUnknown('Tried to import %s, but: %s' % ('.'.join(classpath), e))
-
- try:
- _class = getattr(module, classpath[-1])
- except AttributeError, e:
- raise Core.KnownUnknown('Tried to import %s, but: %s' % ('.'.join(classpath), e))
-
- return _class
diff --git a/TileStache/Core.py b/TileStache/Core.py
index 2b60e6c..163da22 100644
--- a/TileStache/Core.py
+++ b/TileStache/Core.py
@@ -144,12 +144,21 @@ The preview can be accessed through a URL like /<layer name>/preview.html:
"""
import logging
+from sys import modules
from wsgiref.headers import Headers
-from StringIO import StringIO
-from urlparse import urljoin
+try:
+ from io import BytesIO
+except ImportError:
+ # Python 2
+ from StringIO import StringIO as BytesIO
+try:
+ from urllib.parse import urljoin
+except ImportError:
+ # Python 2
+ from urlparse import urljoin
from time import time
-from Pixels import load_palette, apply_palette, apply_palette256
+from .Pixels import load_palette, apply_palette, apply_palette256
try:
from PIL import Image
@@ -382,7 +391,7 @@ class Layer:
# Start by checking for a tile in the cache.
try:
body = cache.read(self, coord, format)
- except TheTileLeftANote, e:
+ except TheTileLeftANote as e:
headers = e.headers
status_code = e.status_code
body = e.content
@@ -417,12 +426,12 @@ class Layer:
if body is None:
# No one else wrote the tile, do it here.
- buff = StringIO()
+ buff = BytesIO()
try:
tile = self.render(coord, format)
save = True
- except NoTileLeftBehind, e:
+ except NoTileLeftBehind as e:
tile = e.tile
save = False
status_code = 404
@@ -445,7 +454,7 @@ class Layer:
tile_from = 'layer.render()'
- except TheTileLeftANote, e:
+ except TheTileLeftANote as e:
headers = e.headers
status_code = e.status_code
body = e.content
@@ -733,7 +742,7 @@ def _preview(layer):
<html>
<head>
<title>TileStache Preview: %(layername)s</title>
- <script src="http://cdn.rawgit.com/stamen/modestmaps-js/v1.0.0-beta1/modestmaps.min.js" type="text/javascript"></script>
+ <script src="//cdn.rawgit.com/stamen/modestmaps-js/v1.0.0-beta1/modestmaps.min.js" type="text/javascript"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<style type="text/css">
html, body, #map {
@@ -818,3 +827,45 @@ def _rummy():
'##Mh at M . ...:;;,:@A#@@@@@@@@@@@#@@@@@@#MMHAB@@@@#G#@@#: i@@ r@@#MMM#######@@@@#@@@@@@#####M#####@@',
'#H3#@3. ,. ... :@@&@@@@@@@@@@@@@#@@#@@@MMBHGA at H&;:@@i :B@@@B .@@#MM####@@@##@@@#@@@@@#######M##M#@@@',
'M&AM5i;.,. ..,,rA@@MH@@@@@@@@@@@@@##@@@@@MMMBB#@h9hH#s;3######, .A@#MMM#####@@@@@##@@@#@@#####M#####M39B']
+
+def loadClassPath(classpath):
+ """ Load external class based on a path.
+
+ Example classpath: "Module.Submodule:Classname".
+
+ Equivalent soon-to-be-deprecated classpath: "Module.Submodule.Classname".
+ """
+ if ':' in classpath:
+ #
+ # Just-added support for "foo:blah"-style classpaths.
+ #
+ modname, objname = classpath.split(':', 1)
+
+ try:
+ __import__(modname)
+ module = modules[modname]
+ _class = eval(objname, module.__dict__)
+
+ if _class is None:
+ raise Exception('eval(%(objname)s) in %(modname)s came up None' % locals())
+
+ except Exception as e:
+ raise KnownUnknown('Tried to import %s, but: %s' % (classpath, e))
+
+ else:
+ #
+ # Support for "foo.blah"-style classpaths, TODO: deprecate this in v2.
+ #
+ classpath = classpath.split('.')
+
+ try:
+ module = __import__('.'.join(classpath[:-1]), fromlist=str(classpath[-1]))
+ except ImportError as e:
+ raise KnownUnknown('Tried to import %s, but: %s' % ('.'.join(classpath), e))
+
+ try:
+ _class = getattr(module, classpath[-1])
+ except AttributeError as e:
+ raise KnownUnknown('Tried to import %s, but: %s' % ('.'.join(classpath), e))
+
+ return _class
diff --git a/TileStache/Geography.py b/TileStache/Geography.py
index 62160b3..366ecb3 100644
--- a/TileStache/Geography.py
+++ b/TileStache/Geography.py
@@ -36,8 +36,7 @@ from ModestMaps.Core import Point, Coordinate
from ModestMaps.Geo import deriveTransformation, MercatorProjection, LinearProjection, Location
from math import log as _log, pi as _pi
-import Core
-import Config
+from . import Core
class SphericalMercator(MercatorProjection):
""" Spherical mercator projection for most commonly-used web map tile scheme.
@@ -143,6 +142,6 @@ def getProjectionByName(name):
else:
try:
- return Config.loadClassPath(name)
- except Exception, e:
+ return Core.loadClassPath(name)
+ except Exception as e:
raise Core.KnownUnknown('Failed projection in configuration: "%s" - %s' % (name, e))
diff --git a/TileStache/Goodies/VecTiles/client.py b/TileStache/Goodies/VecTiles/client.py
index 49e16ea..efde249 100644
--- a/TileStache/Goodies/VecTiles/client.py
+++ b/TileStache/Goodies/VecTiles/client.py
@@ -32,10 +32,22 @@ See also:
'''
from math import pi, log as _log
from threading import Thread, Lock as _Lock
-from httplib import HTTPConnection
+try:
+ from http.client import HTTPConnection
+except ImportError:
+ # Python 2
+ from httplib import HTTPConnection
from itertools import product
-from StringIO import StringIO
-from urlparse import urlparse
+try:
+ from io import StringIO
+except ImportError:
+ # Python 2
+ from StringIO import StringIO
+try:
+ from urllib.parse import urlparse
+except ImportError:
+ # Python 2
+ from urlparse import urlparse
from gzip import GzipFile
import logging
@@ -259,7 +271,7 @@ class Datasource (PythonDatasource):
if self.sort:
logging.debug('Sorting by %s %s' % (self.sort, 'descending' if self.reverse else 'ascending'))
- key_func = lambda (wkb, props): props.get(self.sort, None)
+ key_func = lambda wkb_props: wkb_props[1].get(self.sort, None)
features.sort(reverse=self.reverse, key=key_func)
if len(features) == 0:
diff --git a/TileStache/Goodies/VecTiles/geojson.py b/TileStache/Goodies/VecTiles/geojson.py
index 6638388..6bbde69 100644
--- a/TileStache/Goodies/VecTiles/geojson.py
+++ b/TileStache/Goodies/VecTiles/geojson.py
@@ -34,7 +34,7 @@ def get_tiles(names, config, coord):
if bad_mimes:
raise KnownUnknown('%s.get_tiles encountered a non-JSON mime-type in %s sub-layer: "%s"' % ((__name__, ) + bad_mimes[0]))
- geojsons = map(json.loads, bodies)
+ geojsons = [json.loads(body.decode('utf8')) for body in bodies]
bad_types = [(name, topo['type']) for (topo, name) in zip(geojsons, names) if topo['type'] != 'FeatureCollection']
if bad_types:
@@ -42,10 +42,11 @@ def get_tiles(names, config, coord):
return geojsons
-def mercator((x, y)):
+def mercator(xy):
''' Project an (x, y) tuple to spherical mercator.
'''
- x, y = pi * x/180, pi * y/180
+ _x, _y = xy
+ x, y = pi * _x/180, pi * _y/180
y = log(tan(0.25 * pi + 0.5 * y))
return 6378137 * x, 6378137 * y
@@ -98,14 +99,13 @@ def encode(file, features, zoom, is_clipped):
for token in encoded:
if charfloat_pat.match(token):
# in python 2.7, we see a character followed by a float literal
- file.write(token[0] + flt_fmt % float(token[1:]))
-
+ piece = token[0] + flt_fmt % float(token[1:])
elif float_pat.match(token):
# in python 2.6, we see a simple float literal
- file.write(flt_fmt % float(token))
-
+ piece = flt_fmt % float(token)
else:
- file.write(token)
+ piece = token
+ file.write(piece.encode('utf8'))
def merge(file, names, config, coord):
''' Retrieve a list of GeoJSON tile responses and merge them into one.
@@ -122,11 +122,10 @@ def merge(file, names, config, coord):
for token in encoded:
if charfloat_pat.match(token):
# in python 2.7, we see a character followed by a float literal
- file.write(token[0] + flt_fmt % float(token[1:]))
-
+ piece = token[0] + flt_fmt % float(token[1:])
elif float_pat.match(token):
# in python 2.6, we see a simple float literal
- file.write(flt_fmt % float(token))
-
+ piece = flt_fmt % float(token)
else:
- file.write(token)
+ piece = token
+ file.write(piece.encode('utf8'))
diff --git a/TileStache/Goodies/VecTiles/mvt.py b/TileStache/Goodies/VecTiles/mvt.py
index 73dc62c..88fc952 100644
--- a/TileStache/Goodies/VecTiles/mvt.py
+++ b/TileStache/Goodies/VecTiles/mvt.py
@@ -36,7 +36,11 @@ By default, encode() approximates the floating point precision of WKB geometry
to 26 bits for a significant compression improvement and no visible impact on
rendering at zoom 18 and lower.
'''
-from StringIO import StringIO
+try:
+ from io import StringIO
+except ImportError:
+ # Python 2
+ from StringIO import StringIO
from zlib import decompress as _decompress, compress as _compress
from struct import unpack as _unpack, pack as _pack
import json
diff --git a/TileStache/Goodies/VecTiles/server.py b/TileStache/Goodies/VecTiles/server.py
index 9326239..afc5288 100644
--- a/TileStache/Goodies/VecTiles/server.py
+++ b/TileStache/Goodies/VecTiles/server.py
@@ -8,8 +8,16 @@ For a more general implementation, try the Vector provider:
http://tilestache.org/doc/#vector-provider
'''
from math import pi
-from urlparse import urljoin, urlparse
-from urllib import urlopen
+try:
+ from urllib.parse import urljoin, urlparse
+except ImportError:
+ # Python 2
+ from urlparse import urljoin, urlparse
+try:
+ from urllib.request import urlopen
+except ImportError:
+ # Python 2
+ from urllib import urlopen
from os.path import exists
try:
@@ -17,7 +25,7 @@ try:
from psycopg2 import connect
from psycopg2.extensions import TransactionRollbackError
-except ImportError, err:
+except ImportError as err:
# Still possible to build the documentation without psycopg2
def connect(*args, **kwargs):
@@ -182,7 +190,10 @@ class Provider:
if query not in self.columns:
self.columns[query] = query_columns(self.dbinfo, self.srid, query, bounds)
-
+
+ if not self.columns[query]:
+ return EmptyResponse(bounds)
+
tolerance = self.simplify * tolerances[coord.zoom] if coord.zoom < self.simplify_until else None
return Response(self.dbinfo, self.srid, query, self.columns[query], bounds, tolerance, coord.zoom, self.clip, coord, self.layer.name(), self.padding)
diff --git a/TileStache/Goodies/VecTiles/topojson.py b/TileStache/Goodies/VecTiles/topojson.py
index 04c775b..9bcd13b 100644
--- a/TileStache/Goodies/VecTiles/topojson.py
+++ b/TileStache/Goodies/VecTiles/topojson.py
@@ -23,7 +23,7 @@ def get_tiles(names, config, coord):
if bad_mimes:
raise KnownUnknown('%s.get_tiles encountered a non-JSON mime-type in %s sub-layer: "%s"' % ((__name__, ) + bad_mimes[0]))
- topojsons = map(json.loads, bodies)
+ topojsons = [json.loads(body.decode('utf8')) for body in bodies]
bad_types = [(name, topo['type']) for (topo, name) in zip(topojsons, names) if topo['type'] != 'Topology']
if bad_types:
@@ -188,7 +188,7 @@ def encode(file, features, bounds, is_clipped):
'arcs': arcs
}
- json.dump(result, file, separators=(',', ':'))
+ file.write(json.dumps(result, separators=(',', ':')).encode('utf8'))
def merge(file, names, config, coord):
''' Retrieve a list of TopoJSON tile responses and merge them into one.
@@ -214,4 +214,4 @@ def merge(file, names, config, coord):
for geometry in object['geometries']:
update_arc_indexes(geometry, output['arcs'], input['arcs'])
- json.dump(output, file, separators=(',', ':'))
+ file.write(json.dumps(output, separators=(',', ':')).encode('utf8'))
diff --git a/TileStache/Goodies/VecTiles/wkb.py b/TileStache/Goodies/VecTiles/wkb.py
index 51c5d97..0ec954d 100644
--- a/TileStache/Goodies/VecTiles/wkb.py
+++ b/TileStache/Goodies/VecTiles/wkb.py
@@ -14,7 +14,11 @@ See also:
'''
from struct import unpack
-from StringIO import StringIO
+try:
+ from io import StringIO
+except ImportError:
+ # Python 2
+ from StringIO import StringIO
#
# wkbByteOrder
diff --git a/TileStache/Mapnik.py b/TileStache/Mapnik.py
index 8c14299..ef762b2 100644
--- a/TileStache/Mapnik.py
+++ b/TileStache/Mapnik.py
@@ -285,8 +285,9 @@ class GridProvider:
for (index, fields) in self.layers:
datasource = self.mapnik.layers[index].datasource
fields = (type(fields) is list) and map(str, fields) or datasource.fields()
-
- grid = mapnik.render_grid(self.mapnik, index, resolution=self.scale, fields=fields)
+ grid = mapnik.Grid(width, height)
+ mapnik.render_layer(self.mapnik, grid, layer=index, fields=fields)
+ grid = grid.encode('utf', resolution=self.scale, features=True)
for key in grid['data']:
grid['data'][key][self.layer_id_key] = self.mapnik.layers[index].name
diff --git a/TileStache/Memcache.py b/TileStache/Memcache.py
index 43f5494..e1455a9 100644
--- a/TileStache/Memcache.py
+++ b/TileStache/Memcache.py
@@ -33,6 +33,7 @@ Memcache cache parameters:
"""
from __future__ import absolute_import
from time import time as _time, sleep as _sleep
+from base64 import b64encode, b64decode
# We enabled absolute_import because case insensitive filesystems
# cause this file to be loaded twice (the name of this file
@@ -109,7 +110,10 @@ class Cache:
value = mem.get(key)
mem.disconnect_all()
- return value
+ if value is None:
+ return None
+
+ return b64decode(value.encode('ascii'))
def save(self, body, layer, coord, format):
""" Save a cached tile.
@@ -117,5 +121,8 @@ class Cache:
mem = Client(self.servers)
key = tile_key(layer, coord, format, self.revision, self.key_prefix)
+ if body is not None:
+ body = b64encode(body).decode('ascii')
+
mem.set(key, body, layer.cache_lifespan or 0)
mem.disconnect_all()
diff --git a/TileStache/Pixels.py b/TileStache/Pixels.py
index 399d0d3..dc652e7 100644
--- a/TileStache/Pixels.py
+++ b/TileStache/Pixels.py
@@ -23,7 +23,11 @@ in the lookup table. If the final byte is 0xFFFF, there is no transparency.
"""
from struct import unpack, pack
from math import sqrt, ceil, log
-from urllib import urlopen
+try:
+ from urllib.request import urlopen
+except ImportError:
+ # Python 2
+ from urllib import urlopen
from operator import add
try:
diff --git a/TileStache/Providers.py b/TileStache/Providers.py
index 30139fa..ca669c4 100644
--- a/TileStache/Providers.py
+++ b/TileStache/Providers.py
@@ -73,9 +73,17 @@ For an example of a non-image provider, see TileStache.Vector.Provider.
import os
import logging
-from StringIO import StringIO
+try:
+ from io import BytesIO
+except ImportError:
+ # Python 2
+ from StringIO import StringIO as BytesIO
from string import Template
-import urllib2
+try:
+ import urllib.request as urllib2
+except ImportError:
+ # Python 2
+ import urllib2
import urllib
try:
@@ -87,7 +95,7 @@ except ImportError:
import ModestMaps
from ModestMaps.Core import Point, Coordinate
-import Geography
+from . import Geography
# This import should happen inside getProviderByName(), but when testing
# on Mac OS X features are missing from output. Wierd-ass C libraries...
@@ -140,7 +148,7 @@ class Verbatim:
''' Wrapper for PIL.Image that saves raw input bytes if modes and formats match.
'''
def __init__(self, bytes):
- self.buffer = StringIO(bytes)
+ self.buffer = BytesIO(bytes)
self.format = None
self._image = None
diff --git a/TileStache/VERSION b/TileStache/VERSION
index 858461d..9d343dd 100644
--- a/TileStache/VERSION
+++ b/TileStache/VERSION
@@ -1 +1 @@
-1.51.4
+1.51.5
diff --git a/TileStache/Vector/Arc.py b/TileStache/Vector/Arc.py
index 958a62e..ae7364c 100644
--- a/TileStache/Vector/Arc.py
+++ b/TileStache/Vector/Arc.py
@@ -2,7 +2,7 @@
"""
from operator import add
-from TileStache.Core import KnownUnknown
+from ..Core import KnownUnknown
geometry_types = {
'Point': 'esriGeometryPoint',
diff --git a/TileStache/Vector/__init__.py b/TileStache/Vector/__init__.py
index d64681f..0a53348 100644
--- a/TileStache/Vector/__init__.py
+++ b/TileStache/Vector/__init__.py
@@ -154,7 +154,11 @@ you can save yourself a world of trouble by using this definition:
"""
from re import compile
-from urlparse import urlparse, urljoin
+try:
+ from urllib.parse import urljoin, urlparse
+except ImportError:
+ # Python 2
+ from urlparse import urljoin, urlparse
try:
from json import JSONEncoder, loads as json_loads
@@ -163,9 +167,9 @@ except ImportError:
from osgeo import ogr, osr
-from TileStache.Core import KnownUnknown
-from TileStache.Geography import getProjectionByName
-from Arc import reserialize_to_arc, pyamf_classes
+from ..Core import KnownUnknown
+from ..Geography import getProjectionByName
+from .Arc import reserialize_to_arc, pyamf_classes
class VectorResponse:
""" Wrapper class for Vector response that makes it behave like a PIL.Image object.
@@ -220,9 +224,10 @@ class VectorResponse:
for atom in encoded:
if float_pat.match(atom):
- out.write(('%%.%if' % self.precision) % float(atom))
+ piece = ('%%.%if' % self.precision) % float(atom)
else:
- out.write(atom)
+ piece = atom
+ out.write(piece.encode('utf8'))
elif format in ('GeoBSON', 'ArcBSON'):
import bson
diff --git a/TileStache/__init__.py b/TileStache/__init__.py
index fb9374c..ef0a501 100644
--- a/TileStache/__init__.py
+++ b/TileStache/__init__.py
@@ -8,6 +8,7 @@ designers and cartographers.
Documentation available at http://tilestache.org/doc/
"""
+from __future__ import print_function
import os.path
__version__ = open(os.path.join(os.path.dirname(__file__), 'VERSION')).read().strip()
@@ -19,16 +20,32 @@ try:
from urlparse import parse_qs
except ImportError:
from cgi import parse_qs
-from StringIO import StringIO
+try:
+ from io import StringIO
+except ImportError:
+ # Python 2
+ from StringIO import StringIO
from os.path import dirname, join as pathjoin, realpath
from datetime import datetime, timedelta
-from urlparse import urljoin, urlparse
+try:
+ from urllib.parse import urljoin, urlparse
+except ImportError:
+ # Python 2
+ from urlparse import urljoin, urlparse
from wsgiref.headers import Headers
-from urllib import urlopen
+try:
+ from urllib.request import urlopen
+except ImportError:
+ # Python 2
+ from urllib import urlopen
from os import getcwd
from time import time
-import httplib
+try:
+ import http.client as httplib
+except ImportError:
+ # Python 2
+ import httplib
import logging
try:
@@ -43,8 +60,8 @@ from ModestMaps.Core import Coordinate
# dictionary of configuration objects for requestLayer().
_previous_configs = {}
-import Core
-import Config
+from . import Core
+from . import Config
# regular expression for PATH_INFO
_pathinfo_pat = re.compile(r'^/?(?P<l>\w.+)/(?P<z>\d+)/(?P<x>-?\d+)/(?P<y>-?\d+)\.(?P<e>\w+)$')
@@ -102,13 +119,18 @@ def parseConfig(configHandle):
config_dict = configHandle
dirpath = '.'
else:
- config_dict = json_load(urlopen(configHandle))
scheme, host, path, p, q, f = urlparse(configHandle)
-
+
if scheme == '':
scheme = 'file'
path = realpath(path)
+ if scheme == 'file':
+ with open(path) as file:
+ config_dict = json_load(file)
+ else:
+ config_dict = json_load(urlopen(configHandle))
+
dirpath = '%s://%s%s' % (scheme, host, dirname(path).rstrip('/') + '/')
return Config.buildConfiguration(config_dict, dirpath)
@@ -275,7 +297,7 @@ def requestHandler2(config_hint, path_info, query_string=None, script_name=''):
headers.setdefault('Expires', expires.strftime('%a, %d %b %Y %H:%M:%S GMT'))
headers.setdefault('Cache-Control', 'public, max-age=%d' % layer.max_cache_age)
- except Core.KnownUnknown, e:
+ except Core.KnownUnknown as e:
out = StringIO()
print >> out, 'Known unknown!'
@@ -351,7 +373,7 @@ class WSGITileServer:
try:
self.config = parseConfig(config)
except:
- print "Error loading Tilestache config:"
+ print("Error loading Tilestache config:")
raise
else:
@@ -369,12 +391,12 @@ class WSGITileServer:
if self.autoreload: # re-parse the config file on every request
try:
self.config = parseConfig(self.config_path)
- except Exception, e:
+ except Exception as e:
raise Core.KnownUnknown("Error loading Tilestache config file:\n%s" % str(e))
try:
layer, coord, ext = splitPathInfo(environ['PATH_INFO'])
- except Core.KnownUnknown, e:
+ except Core.KnownUnknown as e:
return self._response(start_response, 400, str(e))
#
diff --git a/requirements.txt b/requirements.txt
index 370c8da..fe6f600 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,8 @@
-ModestMaps
+ModestMaps==1.4.7
simplejson
shapely
pillow
psycopg2
python-memcached
mapbox-vector-tile==0.5.0
+Werkzeug==0.11.13
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 385984f..8fe24aa 100644
--- a/setup.py
+++ b/setup.py
@@ -20,7 +20,7 @@ def is_installed(name):
return False
-requires = ['ModestMaps >=1.3.0','simplejson', 'Werkzeug', 'Pillow']
+requires = ['ModestMaps >=1.3.0','simplejson', 'Werkzeug == 0.11.13', 'Pillow']
setup(name='TileStache',
diff --git a/tests/cache_tests.py b/tests/cache_tests.py
index 66e2e68..fda08f9 100644
--- a/tests/cache_tests.py
+++ b/tests/cache_tests.py
@@ -1,5 +1,6 @@
import os
from unittest import TestCase, skipIf
+from base64 import b64decode
import memcache
from . import utils
@@ -36,8 +37,10 @@ class CacheTests(TestCase):
tile_mimetype, tile_content = utils.request(config_file_content, "memcache_osm", "png", 0, 0, 0)
self.assertEqual(tile_mimetype, "image/png")
- self.assertEqual(self.mc.get('/4/memcache_osm/0/0/0.PNG'), tile_content,
- 'Contents of memcached and value returned from TileStache do not match')
+ memcache_content = b64decode(self.mc.get('/4/memcache_osm/0/0/0.PNG').encode('ascii'))
+
+ self.assertEqual(memcache_content, tile_content,
+ 'Contents of memcached and value returned from TileStache should match')
def test_memcache_keyprefix(self):
'''Fetch tile and check the existence of key with prefix in memcached'''
@@ -64,8 +67,10 @@ class CacheTests(TestCase):
tile_mimetype, tile_content = utils.request(config_file_content, "memcache_osm", "png", 0, 0, 0)
self.assertEqual(tile_mimetype, "image/png")
- self.assertEqual(self.mc.get('cool_prefix/1/memcache_osm/0/0/0.PNG'), tile_content,
- 'Contents of memcached and value returned from TileStache do not match')
+ memcache_content = b64decode(self.mc.get('cool_prefix/1/memcache_osm/0/0/0.PNG').encode('ascii'))
+
+ self.assertEqual(memcache_content, tile_content,
+ 'Contents of memcached and value returned from TileStache should match')
- self.assertEqual(self.mc.get('/1/memcache_osm/0/0/0.PNG'), None,
- 'Memcache returned a value even though it should have been empty')
+ self.assertIsNone(self.mc.get('/1/memcache_osm/0/0/0.PNG'),
+ 'Memcache value should be empty')
diff --git a/tests/provider_tests.py b/tests/provider_tests.py
index 181f271..130b552 100644
--- a/tests/provider_tests.py
+++ b/tests/provider_tests.py
@@ -30,7 +30,7 @@ class ProviderTests(TestCase):
tile_mimetype, tile_content = utils.request(config_file_content, "osm", "png", 0, 0, 0)
self.assertEqual(tile_mimetype, "image/png")
- self.assertTrue(tile_content[:4] in '\x89\x50\x4e\x47') #check it is a png based on png magic number
+ self.assertTrue(tile_content[:4] in b'\x89\x50\x4e\x47') #check it is a png based on png magic number
def test_url_template_wgs84(self):
@@ -55,12 +55,12 @@ class ProviderTests(TestCase):
tile_mimetype, tile_content = utils.request(config_file_content, "osgeo_wms", "png", 0, 0, 0)
self.assertEqual(tile_mimetype, "image/png")
- self.assertTrue(tile_content[:4] in '\x89\x50\x4e\x47') #check it is a png based on png magic number
+ self.assertTrue(tile_content[:4] in b'\x89\x50\x4e\x47') #check it is a png based on png magic number
#in WGS84 we typically have two tiles at zoom level 0. Get the second tile
tile_mimetype, tile_content = utils.request(config_file_content, "osgeo_wms", "png", 0, 1, 0)
self.assertEqual(tile_mimetype, "image/png")
- self.assertTrue(tile_content[:4] in '\x89\x50\x4e\x47') #check it is a png based on png magic number
+ self.assertTrue(tile_content[:4] in b'\x89\x50\x4e\x47') #check it is a png based on png magic number
class ProviderWithDummyResponseServer(TestCase):
@@ -71,8 +71,9 @@ class ProviderWithDummyResponseServer(TestCase):
'''
def setUp(self):
- #create custom binary file that pretends to be a png and a server that always returns the same response
- self.response_content = '\x89\x50\x4e\x47Meh, I am a custom file that loves utf8 chars like éøæ®!!!'
+ # Create custom binary file that pretends to be a png and a server that always returns the same response
+ # Smallest PNG from http://garethrees.org/2007/11/14/pngcrush/
+ self.response_content = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x01\x00\x00\x00\x007n\xf9$\x00\x00\x00\nIDATx\x9cc`\x00\x00\x00\x02\x00\x01H\xaf\xa4q\x00\x00\x00\x00IEND\xaeB`\x82'
self.response_mimetype = 'image/png'
self.temp_file_name = utils.create_temp_file(self.response_content)
diff --git a/tests/servers/dummy-response-server.py b/tests/servers/dummy-response-server.py
index 74d2514..2bd6902 100755
--- a/tests/servers/dummy-response-server.py
+++ b/tests/servers/dummy-response-server.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
import argparse
from werkzeug.wrappers import Request, Response
@@ -17,14 +18,14 @@ if __name__ == '__main__':
args = parser.parse_args()
#read file into buffer
- print 'Response Content: ' + args.response_file
+ print('Response Content:', args.response_file)
global response_content
f = open(args.response_file, 'rb')
response_content = f.read()
f.close()
#set mimetype
- print 'Response Mimetype: ' + args.response_mimetype
+ print('Response Mimetype:', args.response_mimetype)
global response_mimetype
response_mimetype = args.response_mimetype
diff --git a/tests/utils.py b/tests/utils.py
index 46c17c8..346c8b5 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
from tempfile import mkstemp
import os
import inspect
@@ -22,8 +23,11 @@ def request(config_content, layer_name, format, row, column, zoom):
Helper method to write config_file to disk and do
request
'''
+ if sys.version_info.major == 2:
+ is_string = isinstance(config_content, basestring)
+ else:
+ is_string = isinstance(config_content, (str, bytes))
- is_string = isinstance(config_content, basestring)
if is_string:
absolute_file_name = create_temp_file(config_content)
config = parseConfig(absolute_file_name)
@@ -46,7 +50,7 @@ def create_temp_file(buffer):
for deleting file once done
'''
fd, absolute_file_name = mkstemp(text=True)
- file = os.fdopen(fd, 'w+b')
+ file = os.fdopen(fd, 'wb' if (type(buffer) is bytes) else 'w')
file.write(buffer)
file.close()
return absolute_file_name
@@ -58,8 +62,7 @@ def create_dummy_server(file_with_content, mimetype):
mimetype specified
'''
- # see http://stackoverflow.com/questions/50499/in-python-how-do-i-get-the-path-and-name-of-the-file-that-is-currently-executin
- current_script_dir = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe())))
+ current_script_dir = os.path.dirname(os.path.abspath(__file__))
#start new process using our dummy-response-server.py script
dummy_server_file = os.path.join(current_script_dir, 'servers', 'dummy-response-server.py')
@@ -81,7 +84,7 @@ def create_dummy_server(file_with_content, mimetype):
t.daemon = True # thread dies with the program
t.start()
- server_output = ''
+ server_output = b''
# read line and enter busy loop until the server says it is ok
while True:
@@ -97,7 +100,7 @@ def create_dummy_server(file_with_content, mimetype):
continue
else: # got line
server_output += line
- if "Running on http://" in server_output:
+ if b"Running on http://" in server_output:
break; #server is running, get out of here
else:
continue
diff --git a/tests/vectiles_tests.py b/tests/vectiles_tests.py
index 95adb1b..22918d8 100644
--- a/tests/vectiles_tests.py
+++ b/tests/vectiles_tests.py
@@ -1,3 +1,5 @@
+from __future__ import print_function
+
import os
from unittest import TestCase, skipIf
from collections import namedtuple
@@ -19,7 +21,8 @@ from . import utils
def get_topo_transform(topojson):
'''
'''
- def xform((x, y)):
+ def xform(xy):
+ x, y = xy
lon = topojson['transform']['scale'][0] * x + topojson['transform']['translate'][0]
lat = topojson['transform']['scale'][1] * y + topojson['transform']['translate'][1]
@@ -94,12 +97,11 @@ def decoded_pbf_asshape(feature, extent, srid=4326):
3: "Polygon"
}
if feature['type'] in (1, 2):
- coords = [
- trans_coord(3857, srid, *coord2merc(*g, extent=extent)) for g in feature['geometry']]
+ coords = [trans_coord(3857, srid, *coord2merc(x, y, extent=extent))
+ for (x, y) in feature['geometry']]
elif feature['type'] == 3:
- coords = [
- [trans_coord(3857, srid, *coord2merc(*g, extent=extent)) for g in feature['geometry'][0]]
- ]
+ coords = [[trans_coord(3857, srid, *coord2merc(x, y, extent=extent))
+ for (x, y) in feature['geometry'][0]]]
geoint = {
'type': TYPES_MAP.get(feature['type']),
'coordinates': coords,
@@ -235,7 +237,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
# northwest quadrant should return San Francisco and Lima
tile_mimetype, tile_content = utils.request(self.config_file_content, "vectile_test", "json", 0, 0, 1)
- geojson_result = json.loads(tile_content)
+ geojson_result = json.loads(tile_content.decode('utf8'))
self.assertTrue(tile_mimetype.endswith('/json'))
self.assertEqual(geojson_result['type'], 'FeatureCollection')
@@ -261,7 +263,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
# northeast quadrant should return Berlin
tile_mimetype, tile_content = utils.request(self.config_file_content, "vectile_test", "json", 0, 1, 1)
- geojson_result = json.loads(tile_content)
+ geojson_result = json.loads(tile_content.decode('utf8'))
self.assertTrue(tile_mimetype.endswith('/json'))
self.assertEqual(geojson_result['type'], 'FeatureCollection')
@@ -282,7 +284,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
tile_mimetype, tile_content = utils.request(self.config_file_content, "vectile_test", "json", 0, 0, 0)
self.assertTrue(tile_mimetype.endswith('/json'))
- geojson_result = json.loads(tile_content)
+ geojson_result = json.loads(tile_content.decode('utf8'))
west_hemisphere_geometry = asShape(geojson_result['features'][0]['geometry'])
expected_geometry = LineString([(-180, 32), (180, 32)])
self.assertTrue(expected_geometry.almost_equals(west_hemisphere_geometry))
@@ -305,7 +307,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
tile_mimetype, tile_content = utils.request(self.config_file_content, "vectile_test", "json", 0, 0, 0)
self.assertTrue(tile_mimetype.endswith('/json'))
- geojson_result = json.loads(tile_content)
+ geojson_result = json.loads(tile_content.decode('utf8'))
result_geom = asShape(geojson_result['features'][0]['geometry'])
expected_geom = Polygon( [(-180, -85.05), (180, -85.05), (180, 85.05), (-180, 85.05), (-180, -85.05)])
@@ -346,7 +348,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
tile_mimetype, tile_content = utils.request(self.config_file_content, "vectile_multi", "json", 0, 0, 0)
self.assertTrue(tile_mimetype.endswith('/json'))
- geojson_result = json.loads(tile_content)
+ geojson_result = json.loads(tile_content.decode('utf8'))
feature1, feature2 = geojson_result['vectile_test'], geojson_result['vectile_copy']
self.assertEqual(feature1['type'], 'FeatureCollection')
@@ -382,10 +384,10 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
# northwest quadrant should return San Francisco and Lima
tile_mimetype, tile_content = utils.request(self.config_file_content, "vectile_test", "topojson", 0, 0, 1)
- topojson_result = json.loads(tile_content)
+ topojson_result = json.loads(tile_content.decode('utf8'))
self.assertTrue(tile_mimetype.endswith('/json'))
- print topojson_result
+ print(topojson_result)
self.assertEqual(topojson_result['type'], 'Topology')
self.assertEqual(len(topojson_result['objects']['vectile']['geometries']), 2)
@@ -404,7 +406,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
elif feature['properties']['name'] == 'Lima':
cities.append(feature['properties']['name'])
- print feature['coordinates']
+ print(feature['coordinates'])
self.assertTrue(hypot(point_lima.x - lon, point_lima.y - lat) < 1)
self.assertTrue('San Francisco' in cities)
@@ -414,7 +416,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
# northeast quadrant should return Berlin
tile_mimetype, tile_content = utils.request(self.config_file_content, "vectile_test", "topojson", 0, 1, 1)
- topojson_result = json.loads(tile_content)
+ topojson_result = json.loads(tile_content.decode('utf8'))
self.assertTrue(tile_mimetype.endswith('/json'))
self.assertEqual(topojson_result['type'], 'Topology')
@@ -435,7 +437,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
tile_mimetype, tile_content = utils.request(self.config_file_content, "vectile_test", "topojson", 0, 0, 0)
self.assertTrue(tile_mimetype.endswith('/json'))
- topojson_result = json.loads(tile_content)
+ topojson_result = json.loads(tile_content.decode('utf8'))
topojson_xform = get_topo_transform(topojson_result)
parts = [topojson_result['arcs'][arc] for arc in topojson_result['objects']['vectile']['geometries'][0]['arcs']]
@@ -467,7 +469,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
tile_mimetype, tile_content = utils.request(self.config_file_content, "vectile_test", "topojson", 0, 0, 0)
self.assertTrue(tile_mimetype.endswith('/json'))
- topojson_result = json.loads(tile_content)
+ topojson_result = json.loads(tile_content.decode('utf8'))
topojson_xform = get_topo_transform(topojson_result)
parts = [topojson_result['arcs'][arc[0]] for arc in topojson_result['objects']['vectile']['geometries'][0]['arcs']]
@@ -513,7 +515,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
tile_mimetype, tile_content = utils.request(self.config_file_content, "vectile_multi", "topojson", 0, 0, 0)
self.assertTrue(tile_mimetype.endswith('/json'))
- topojson_result = json.loads(tile_content)
+ topojson_result = json.loads(tile_content.decode('utf8'))
self.assertEqual(topojson_result['type'], 'Topology')
self.assertEqual(topojson_result['objects']['vectile_test']['type'], 'GeometryCollection')
@@ -593,7 +595,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
'''Create a line that goes from west to east (clip on) (pbf)'''
self.defineGeometry('LINESTRING')
- geom = LineString([(-180, 32), (180, 32)])
+ geom = LineString([(-179, 32), (179, 32)])
self.insertTestRow(geom.wkt)
@@ -607,11 +609,10 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
extent = tile_bounds_mercator(0, 0, 0)
west_hemisphere_geometry = decoded_pbf_asshape(layer_result['features'][0], extent)
- # order of points returned are different
- expected_geometry = LineString([(180, 32), (-180, 32)])
+ expected_geometry = LineString([(-179, 32), (179, 32)])
for returned, expected in zip(west_hemisphere_geometry.coords, expected_geometry.coords):
- self.assertTrue(round(returned[0]) == expected[0])
- self.assertTrue(round(returned[1]) == expected[1])
+ self.assertEqual(round(returned[0]), expected[0])
+ self.assertEqual(round(returned[1]), expected[1])
def test_polygon_pbf(self):
'''
diff --git a/tests/vector_tests.py b/tests/vector_tests.py
index 38082a2..980d18c 100644
--- a/tests/vector_tests.py
+++ b/tests/vector_tests.py
@@ -103,7 +103,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
# western hemisphere should return San Francisco and Lima
tile_mimetype, tile_content = utils.request(self.config_file_content, "vector_test", "geojson", 0, 0, 0)
- geojson_result = json.loads(tile_content)
+ geojson_result = json.loads(tile_content.decode('utf8'))
self.assertTrue(tile_mimetype.endswith('/json'))
self.assertEqual(geojson_result['type'], 'FeatureCollection')
@@ -129,7 +129,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
# eastern hemisphere should return Berlin
tile_mimetype, tile_content = utils.request(self.config_file_content, "vector_test", "geojson", 0, 1, 0)
- geojson_result = json.loads(tile_content)
+ geojson_result = json.loads(tile_content.decode('utf8'))
self.assertTrue(tile_mimetype.endswith('/json'))
self.assertEqual(geojson_result['type'], 'FeatureCollection')
@@ -151,7 +151,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
# for western hemisphere....
tile_mimetype, tile_content = utils.request(self.config_file_content, "vector_test", "geojson", 0, 0, 0)
self.assertTrue(tile_mimetype.endswith('/json'))
- geojson_result = json.loads(tile_content)
+ geojson_result = json.loads(tile_content.decode('utf8'))
west_hemisphere_geometry = asShape(geojson_result['features'][0]['geometry'])
expected_geometry = LineString([(-180, 32), (0, 32)])
self.assertTrue(expected_geometry.almost_equals(west_hemisphere_geometry))
@@ -159,7 +159,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
# for eastern hemisphere....
tile_mimetype, tile_content = utils.request(self.config_file_content, "vector_test", "geojson", 0, 1, 0)
self.assertTrue(tile_mimetype.endswith('/json'))
- geojson_result = json.loads(tile_content)
+ geojson_result = json.loads(tile_content.decode('utf8'))
east_hemisphere_geometry = asShape(geojson_result['features'][0]['geometry'])
expected_geometry = LineString([(0, 32), (180, 32)])
self.assertTrue(expected_geometry.almost_equals(east_hemisphere_geometry))
@@ -182,7 +182,7 @@ class VectorProviderTest(PostGISVectorTestBase, TestCase):
tile_mimetype, tile_content = utils.request(self.config_file_content, "vector_test", "geojson", 0, 0, 0)
self.assertTrue(tile_mimetype.endswith('/json'))
- geojson_result = json.loads(tile_content)
+ geojson_result = json.loads(tile_content.decode('utf8'))
result_geom = asShape(geojson_result['features'][0]['geometry'])
expected_geom = Polygon( [(-180, -90), (0, -90), (0, 90), (-180, 90), (-180, -90)])
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/tilestache.git
More information about the Pkg-grass-devel
mailing list