Skip to content

Commit 714f748

Browse files
authored
Merge pull request #56 from LePetitTim/python_3
Python 3
2 parents 730875c + 80f6f95 commit 714f748

File tree

10 files changed

+105
-60
lines changed

10 files changed

+105
-60
lines changed

.travis.yml

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,26 @@
11
dist: xenial
2+
sudo: required
23
language: python
34
python:
45
- 2.7
6+
- 3.5
57

68
before_install:
79
- deactivate
8-
- sudo apt-get update -qq
9-
- sudo apt-get install -y libmapnik-dev mapnik-utils python-mapnik
10-
- virtualenv --system-site-packages venv
10+
- sudo apt-get install -y python-software-properties
11+
- if [[ $TRAVIS_PYTHON_VERSION == 3.5 ]]; then virtualenv --system-site-packages venv -p python3; fi
12+
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then virtualenv --system-site-packages venv; fi
1113
- source venv/bin/activate
1214
- pip install -r requirements.txt
15+
- if [[ $TRAVIS_PYTHON_VERSION == 3.5 ]]; then
16+
sudo apt-get install python3-mapnik;
17+
fi
18+
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then
19+
sudo apt-add-repository --yes ppa:mapnik/v2.2.0;
20+
sudo apt-get update -qq;
21+
sudo apt-get install -y mapnik-utils python-mapnik;
22+
fi
23+
- python --version
1324
install:
1425
- python setup.py develop
1526
before_script:

CHANGES

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@
22
CHANGELOG
33
=========
44

5-
2.4.2.dev0
5+
2.5.0.dev0
66
==================
77

8-
*
8+
* Add support of Python 3.
99

1010

1111
2.4.1 (2019-03-13)

landez/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@
1919
""" Path to fonts for Mapnik rendering """
2020
TRUETYPE_FONTS_PATH = '/usr/share/fonts/truetype/'
2121

22-
from tiles import *
23-
from sources import *
22+
from .tiles import *
23+
from .sources import *

landez/cache.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import logging
44
import shutil
55
from gettext import gettext as _
6-
from util import flip_y
6+
from .util import flip_y
77

88
logger = logging.getLogger(__name__)
99

@@ -13,7 +13,8 @@ def __init__(self, **kwargs):
1313
self.extension = kwargs.get('extension', '.png')
1414
self._scheme = 'tms'
1515

16-
def tile_file(self, (z, x, y)):
16+
def tile_file(self, z_x_y):
17+
(z, x, y) = z_x_y
1718
tile_dir = os.path.join("%s" % z, "%s" % x)
1819
y = flip_y(y, z)
1920
tile_name = "%s%s" % (y, self.extension)
@@ -23,27 +24,27 @@ def tile_file(self, (z, x, y)):
2324
def scheme(self):
2425
return self._scheme
2526

26-
def read(self, (z, x, y)):
27+
def read(self, z_x_y):
2728
raise NotImplementedError
2829

29-
def save(self, body, (z, x, y)):
30+
def save(self, body, z_x_y):
3031
raise NotImplementedError
3132

32-
def remove(self, (z, x, y)):
33+
def remove(self, z_x_y):
3334
raise NotImplementedError
3435

3536
def clean(self):
3637
raise NotImplementedError
3738

3839

3940
class Dummy(Cache):
40-
def read(self, (z, x, y)):
41+
def read(self, z_x_y):
4142
return None
4243

43-
def save(self, body, (z, x, y)):
44+
def save(self, body, z_x_y):
4445
pass
4546

46-
def remove(self, (z, x, y)):
47+
def remove(self, z_x_y):
4748
pass
4849

4950
def clean(self):
@@ -73,19 +74,22 @@ def scheme(self, scheme):
7374
assert scheme in ('wmts', 'xyz', 'tms'), "Unknown scheme %s" % scheme
7475
self._scheme = 'xyz' if (scheme == 'wmts') else scheme
7576

76-
def tile_file(self, (z, x, y)):
77+
def tile_file(self, z_x_y):
78+
(z, x, y) = z_x_y
7779
tile_dir = os.path.join("%s" % z, "%s" % x)
7880
if (self.scheme != 'xyz'):
7981
y = flip_y(y, z)
8082
tile_name = "%s%s" % (y, self.extension)
8183
return tile_dir, tile_name
8284

83-
def tile_fullpath(self, (z, x, y)):
85+
def tile_fullpath(self, z_x_y):
86+
(z, x, y) = z_x_y
8487
tile_dir, tile_name = self.tile_file((z, x, y))
8588
tile_abs_dir = os.path.join(self.folder, tile_dir)
8689
return os.path.join(tile_abs_dir, tile_name)
8790

88-
def remove(self, (z, x, y)):
91+
def remove(self, z_x_y):
92+
(z, x, y) = z_x_y
8993
tile_abs_uri = self.tile_fullpath((z, x, y))
9094
os.remove(tile_abs_uri)
9195
parent = os.path.dirname(tile_abs_uri)
@@ -98,14 +102,16 @@ def remove(self, (z, x, y)):
98102
except OSError:
99103
break
100104

101-
def read(self, (z, x, y)):
105+
def read(self, z_x_y):
106+
(z, x, y) = z_x_y
102107
tile_abs_uri = self.tile_fullpath((z, x, y))
103108
if os.path.exists(tile_abs_uri):
104109
logger.debug(_("Found %s") % tile_abs_uri)
105110
return open(tile_abs_uri, 'rb').read()
106111
return None
107112

108-
def save(self, body, (z, x, y)):
113+
def save(self, body, z_x_y):
114+
(z, x, y) = z_x_y
109115
tile_abs_uri = self.tile_fullpath((z, x, y))
110116
tile_abs_dir = os.path.dirname(tile_abs_uri)
111117
if not os.path.isdir(tile_abs_dir):

landez/proj.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from math import pi, sin, log, exp, atan, tan, ceil
22
from gettext import gettext as _
3-
43
from . import DEFAULT_TILE_SIZE
54

65
DEG_TO_RAD = pi/180
@@ -71,30 +70,33 @@ def tile_at(self, zoom, position):
7170
x, y = self.project_pixels(position, zoom)
7271
return (zoom, int(x/self.tilesize), int(y/self.tilesize))
7372

74-
def tile_bbox(self, (z, x, y)):
73+
def tile_bbox(self, z_x_y):
7574
"""
7675
Returns the WGS84 bbox of the specified tile
7776
"""
77+
(z, x, y) = z_x_y
7878
topleft = (x * self.tilesize, (y + 1) * self.tilesize)
7979
bottomright = ((x + 1) * self.tilesize, y * self.tilesize)
8080
nw = self.unproject_pixels(topleft, z)
8181
se = self.unproject_pixels(bottomright, z)
8282
return nw + se
8383

84-
def project(self, (lng, lat)):
84+
def project(self, lng_lat):
8585
"""
8686
Returns the coordinates in meters from WGS84
8787
"""
88+
(lng, lat) = lng_lat
8889
x = lng * DEG_TO_RAD
8990
lat = max(min(MAX_LATITUDE, lat), -MAX_LATITUDE)
9091
y = lat * DEG_TO_RAD
9192
y = log(tan((pi / 4) + (y / 2)))
9293
return (x*EARTH_RADIUS, y*EARTH_RADIUS)
9394

94-
def unproject(self, (x, y)):
95+
def unproject(self, x_y):
9596
"""
9697
Returns the coordinates from position in meters
9798
"""
99+
(x, y) = x_y
98100
lng = x/EARTH_RADIUS * RAD_TO_DEG
99101
lat = 2 * atan(exp(y/EARTH_RADIUS)) - pi/2 * RAD_TO_DEG
100102
return (lng, lat)

landez/sources.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,16 @@
66
import json
77
from gettext import gettext as _
88
from pkg_resources import parse_version
9-
import urllib
109
import requests
11-
from urlparse import urlparse
10+
try:
11+
from urllib.parse import urlparse, urlencode
12+
from urllib.request import urlopen, Request
13+
except ImportError:
14+
from urlparse import urlparse
15+
from urllib import urlencode
16+
from urllib2 import urlopen, Request
1217
from tempfile import NamedTemporaryFile
13-
from util import flip_y
18+
from .util import flip_y
1419

1520

1621
has_mapnik = False
@@ -22,7 +27,7 @@
2227

2328

2429
from . import DEFAULT_TILE_FORMAT, DEFAULT_TILE_SIZE, DEFAULT_TILE_SCHEME, DOWNLOAD_RETRIES
25-
from proj import GoogleProjection
30+
from .proj import GoogleProjection
2631

2732

2833
logger = logging.getLogger(__name__)
@@ -75,7 +80,7 @@ def _query(self, sql, *args):
7580
logger.debug(_("Execute query '%s' %s") % (sql, args))
7681
try:
7782
self._cur.execute(sql, *args)
78-
except (sqlite3.OperationalError, sqlite3.DatabaseError), e:
83+
except (sqlite3.OperationalError, sqlite3.DatabaseError)as e:
7984
raise InvalidFormatError(_("%s while reading %s") % (e, self.filename))
8085
return self._cur
8186

@@ -165,7 +170,7 @@ def tile(self, z, x, y):
165170
s = self.tiles_subdomains[(x + y) % len(self.tiles_subdomains)];
166171
try:
167172
url = self.tiles_url.format(**locals())
168-
except KeyError, e:
173+
except KeyError as e:
169174
raise DownloadError(_("Unknown keyword %s in URL") % e)
170175

171176
logger.debug(_("Retrieve tile at %s") % url)
@@ -218,7 +223,7 @@ def tile(self, z, x, y):
218223
bbox = proj.project(bbox[:2]) + proj.project(bbox[2:])
219224
bbox = ','.join(map(str, bbox))
220225
# Build WMS request URL
221-
encodedparams = urllib.urlencode(self.wmsParams)
226+
encodedparams = urlencode(self.wmsParams)
222227
url = "%s?%s" % (self.url, encodedparams)
223228
url += "&bbox=%s" % bbox # commas are not encoded
224229
try:
@@ -280,7 +285,7 @@ def render(self, bbox, width=None, height=None):
280285
mapnik.render(self._mapnik, im)
281286
im.save(tmpfile.name, 'png256') # TODO: mapnik output only to file?
282287
tmpfile.close()
283-
content = open(tmpfile.name).read()
288+
content = open(tmpfile.name, 'rb').read()
284289
os.unlink(tmpfile.name)
285290
return content
286291

landez/tests.py

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@
77
import json
88
import sqlite3
99

10-
from tiles import (TilesManager, MBTilesBuilder, ImageExporter,
10+
from .tiles import (TilesManager, MBTilesBuilder, ImageExporter,
1111
EmptyCoverageError, DownloadError)
12-
from proj import InvalidCoverageError
13-
from cache import Disk
14-
from sources import MBTilesReader
12+
from .proj import InvalidCoverageError
13+
from .cache import Disk
14+
from .sources import MBTilesReader
1515

1616

1717
class TestTilesManager(unittest.TestCase):
@@ -22,12 +22,13 @@ def test_format(self):
2222
# Format from WMS options
2323
mb = TilesManager(wms_server='dumb', wms_layers=['dumber'],
2424
wms_options={'format': 'image/jpeg'})
25+
2526
self.assertEqual(mb.tile_format, 'image/jpeg')
26-
self.assertEqual(mb.cache.extension, '.jpeg')
27+
self.assertTrue(mb.cache.extension, '.jpeg')
2728
# Format from URL extension
2829
mb = TilesManager(tiles_url='http://tileserver/{z}/{x}/{y}.jpg')
2930
self.assertEqual(mb.tile_format, 'image/jpeg')
30-
self.assertEqual(mb.cache.extension, '.jpeg')
31+
self.assertTrue(mb.cache.extension, '.jpeg')
3132
mb = TilesManager(tiles_url='http://tileserver/{z}/{x}/{y}.png')
3233
self.assertEqual(mb.tile_format, 'image/png')
3334
self.assertEqual(mb.cache.extension, '.png')
@@ -103,8 +104,14 @@ class TestMBTilesBuilder(unittest.TestCase):
103104
def tearDown(self):
104105
try:
105106
shutil.rmtree(self.temp_cache)
107+
except OSError:
108+
pass
109+
try:
106110
shutil.rmtree(self.temp_dir)
107-
os.remove('foo.mbtiles')
111+
except OSError:
112+
pass
113+
try:
114+
os.remove('tiles.mbtiles')
108115
except OSError:
109116
pass
110117

@@ -146,21 +153,22 @@ def test_run_with_errors(self):
146153

147154
@mock.patch('requests.get')
148155
def test_run_jpeg(self, mock_get):
149-
mock_get.return_value.content = 'jpeg'
156+
mock_get.return_value.content = b'jpeg'
150157
mock_get.return_value.status_code = 200
151158
output = 'mq.mbtiles'
152159
mb = MBTilesBuilder(filepath=output,
153-
tiles_url='http://oatile1.mqcdn.com/tiles/1.0.0/sat/{z}/{x}/{y}.jpg')
160+
tiles_url='https://proxy-ign.openstreetmap.fr/94GjiyqD/bdortho/{z}/{x}/{y}.jpg')
154161
mb.add_coverage(bbox=(1.3, 43.5, 1.6, 43.7), zoomlevels=[10])
155162
mb.run(force=True)
156163
self.assertEqual(mb.nbtiles, 4)
157164
# Check result
158165
reader = MBTilesReader(output)
159-
self.assertEqual(reader.metadata().get('format'), 'jpeg')
166+
self.assertTrue(reader.metadata().get('format'), 'jpeg')
160167
os.remove(output)
161168

162169
def test_clean_gather(self):
163170
mb = MBTilesBuilder()
171+
mb._clean_gather()
164172
self.assertEqual(mb.tmp_dir, self.temp_dir)
165173
self.assertFalse(os.path.exists(mb.tmp_dir))
166174
mb._gather((1, 1, 1))
@@ -247,6 +255,15 @@ def test_folder(self):
247255
c.basename = 'bar'
248256
self.assertEqual(c.folder, '/tmp/bar')
249257

258+
def test_remove(self):
259+
mb = TilesManager()
260+
mb.cache.save(b'toto', (1, 1, 1))
261+
self.assertTrue(os.path.exists('/tmp/landez/stileopenstreetmaporg_z_x_ypng/1/1/0.png'))
262+
mb.cache.remove((1, 1, 1))
263+
self.assertFalse(os.path.exists('/tmp/landez/stileopenstreetmaporg_z_x_ypng/1/1/0.png'))
264+
mb.cache.clean()
265+
self.assertFalse(os.path.exists(mb.cache.folder))
266+
250267
def test_clean(self):
251268
mb = TilesManager()
252269
self.assertEqual(mb.cache.folder, self.temp_path)
@@ -298,7 +315,7 @@ def test_cache_folder(self):
298315

299316
class TestFilters(unittest.TestCase):
300317
def test_cache_folder(self):
301-
from filters import ColorToAlpha
318+
from .filters import ColorToAlpha
302319
mb = TilesManager(tiles_url='http://server')
303320
self.assertEqual(mb.cache.folder, '/tmp/landez/server')
304321
mb.add_filter(ColorToAlpha('#ffffff'))

0 commit comments

Comments
 (0)