diff --git a/.TestDockerfile b/.TestDockerfile index 35cb983..d10bdb4 100644 --- a/.TestDockerfile +++ b/.TestDockerfile @@ -1,10 +1,9 @@ -FROM socrata/base-xenial +FROM socrata/python3-bionic WORKDIR /app RUN DEBIAN_FRONTEND=noninteractive apt-get -y update && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install python-mapnik python-pip -RUN pip install --upgrade pip + DEBIAN_FRONTEND=noninteractive apt-get -y install python3-mapnik RUN mkdir -p /app/carto_renderer diff --git a/Dockerfile b/Dockerfile index 0acd4a4..481abd9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,18 @@ -FROM socrata/base-xenial +FROM socrata/python3-bionic WORKDIR /app RUN DEBIAN_FRONTEND=noninteractive apt-get -y update && \ - DEBIAN_FRONTEND=noninteractive apt-get -y install python-mapnik python-pip -RUN pip install --upgrade pip + DEBIAN_FRONTEND=noninteractive apt-get -y install python3-mapnik RUN mkdir -p /app/carto_renderer ENV LOG_LEVEL INFO -ADD frozen.txt /app/ +COPY bin/freeze-reqs.sh /app/ +COPY dev-requirements.txt /app/ +RUN chmod +x /app/freeze-reqs.sh +RUN /app/freeze-reqs.sh RUN pip install -r /app/frozen.txt COPY ship.d /etc/ship.d/ diff --git a/README.md b/README.md index a28cdf2..60d1823 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ brew install mapnik Install Mapnik (Debian/Ubuntu): ``` -sudo apt-get install python-mapnik +sudo apt-get install python3-mapnik ``` Install Python Dependencies: @@ -30,12 +30,6 @@ pip install -r dev-requirements.txt bin/start-renderer.sh --dev ``` -## Examples ## -Render an image to `test.png`: -``` -curl -o test.png localhost:4096/render -H 'Content-type: application/json' -d @carto_renderer/examples/main.json -``` - ## Testing ## The tests are run using py.test and hypothesis diff --git a/bin/dockerize.sh b/bin/dockerize.sh index edb3535..f35a1b2 100755 --- a/bin/dockerize.sh +++ b/bin/dockerize.sh @@ -3,6 +3,5 @@ set -e cd "$(git rev-parse --show-toplevel 2>/dev/null)" -bin/freeze-reqs.sh docker build --rm -t carto-renderer . diff --git a/bin/freeze-reqs.sh b/bin/freeze-reqs.sh index ac5f5c0..fa931cf 100755 --- a/bin/freeze-reqs.sh +++ b/bin/freeze-reqs.sh @@ -3,17 +3,7 @@ set -ev # Change to the project root. -cd "$(git rev-parse --show-toplevel 2>/dev/null)" - -VENV_DIR="venv" -if [ "${HUDSON_HOME}" ]; then - VENV_DIR="${HUDSON_HOME}/carto-renderer/${VENV_DIR}" -fi - -if [ ! -d "${VENV_DIR}" ]; then - virtualenv "${VENV_DIR}" -fi -source "${VENV_DIR}"/bin/activate +cd /app DEV_FILE='dev-requirements.txt' FROZEN_FILE='frozen.txt' diff --git a/bin/start-renderer.sh b/bin/start-renderer.sh index dba6249..bfaf78e 100755 --- a/bin/start-renderer.sh +++ b/bin/start-renderer.sh @@ -11,20 +11,19 @@ if [ '--dev' = "$1" ]; then fi source venv/bin/activate - if [ ! -d venv/lib/python2.7/site-packages/mapnik ]; then - ln -s "$MAPNIK_DIR" venv/lib/python2.7/site-packages/ + if [ ! -d venv/lib/python3.6/site-packages/mapnik ]; then + ln -s "$MAPNIK_DIR" venv/lib/python3.6/site-packages/ fi pip install --upgrade --requirement dev-requirements.txt PYTHONPATH=. carto_renderer/service.py else bin/dockerize.sh - rm frozen.txt - + if [ 'Darwin' = "$(uname)" ]; then OPTS=(-p 4096:4096 -e 'STYLE_HOST=docker.for.mac.localhost') else - OPTS=('--net=host') + OPTS=('--net=host' -e 'STYLE_HOST=localhost') fi docker run "${OPTS[@]}" -e STYLE_PORT=4097 -e LOG_LEVEL=INFO carto-renderer diff --git a/carto_renderer/errors.py b/carto_renderer/errors.py index e785f71..09794e6 100644 --- a/carto_renderer/errors.py +++ b/carto_renderer/errors.py @@ -10,9 +10,9 @@ class ServiceError(Exception): Base class for errors in this service. """ def __init__(self, message, status_code, request_body=None): - super(ServiceError, self).__init__(message) self.status_code = status_code self.request_body = request_body + self.message = message logger = get_logger(self) if request_body: logger.error('Fatal Error (%d): "%s"; body: "%s"', @@ -41,6 +41,6 @@ def __init__(self, keys, blob): message = '' beg = keys[:-1] - message = PayloadKeyError.msg.format("', '".join(beg), keys[-1]) + message = PayloadKeyError.msg.format(b"', '".join(beg), keys[-1]) super(PayloadKeyError, self).__init__(message, 400, request_body=blob) diff --git a/carto_renderer/examples/main-urlencode.mss b/carto_renderer/examples/main-urlencode.mss deleted file mode 100644 index be1c9bb..0000000 --- a/carto_renderer/examples/main-urlencode.mss +++ /dev/null @@ -1 +0,0 @@ -%23main%7Bmarker-fill%3A%23006%3Bmarker-width%3A3%3Bmarker-line-color%3A%23009%3Bmarker-line-width%3A1%3Bpolygon-fill%3A%23900%3B%7D diff --git a/carto_renderer/examples/main.json b/carto_renderer/examples/main.json deleted file mode 100644 index c88ac56..0000000 --- a/carto_renderer/examples/main.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "bpbf": "GukQCgRtYWluEhASBAAAAQEYASIGCaA9oBMCEg8SBAAAAQIYASIFCYA6IAISEBIEAAABAxgBIgYJgDrgAQISEBIEAAABBBgBIgYJwD2gKAISEBIEAAABBRgBIgYJwATAGQISEBIEAAABBBgBIgYJgDrgAgISEBIEAAABBhgBIgYJgC7gFgISEBIEAAABBxgBIgYJwDyAHgISEBIEAAgBBRgBIgYJgD+gIAISEBIEAAABBxgBIgYJwDyABQISDxIEAAABCRgBIgUJwDxAAhIQEgQAAAEFGAEiBgngPOA7AhIQEgQAAAEJGAEiBgmAP6AgAhIQEgQAAAEKGAEiBgnAPIAhAhIQEgQAAAELGAEiBgnAPIAhAhIQEgQAAAEKGAEiBgnAPYAhAhIQEgQADAEJGAEiBgngPcAwAhIQEgQAAAEHGAEiBgnAPMAQAhIQEgQADQEFGAEiBgnAPcAhAhIQEgQAAAEOGAEiBgmALsAWAhIQEgQAAAEHGAEiBgngOeAEAhIQEgQAAAEJGAEiBgmgC8AEAhIQEgQAAAEHGAEiBgnAPIAhAhIQEgQAAAEFGAEiBgnAPIAhAhIQEgQAAAEKGAEiBgnAPOASAhIQEgQAAAEJGAEiBgnAPIAhAhIQEgQADAEJGAEiBgnAPYAhAhIQEgQAAAEDGAEiBgmgBeAZAhIQEgQADAEFGAEiBgnABOAZAhIQEgQAAAEJGAEiBgmgPYAXAhIQEgQAAAEJGAEiBgmALuAWAhIQEgQAAAEPGAEiBgnAPKATAhIQEgQAAAEJGAEiBgnABOAZAhIQEgQAAAEPGAEiBgngPOAvAhIQEgQAAAEQGAEiBgmgPcAbAhIQEgQAAAEOGAEiBgnAPYABAhIQEgQAAAECGAEiBgmAOuACAhIQEgQAAAERGAEiBgnAPeAfAhIQEgQAAAEFGAEiBgnAPeAkAhIQEgQAAAESGAEiBgnAPIAhAhIQEgQAAAEBGAEiBgmAP6AgAhIQEgQAAAEEGAEiBgnAPeAoAhIQEgQAAAEEGAEiBgnAPaAqAhIQEgQAAAEFGAEiBgmALsAWAhIQEgQAAAEFGAEiBgngPKAoAhIQEgQADAEFGAEiBgnAPKACAhIQEgQAAAEFGAEiBgnABYA9AhIQEgQADAECGAEiBgmgBaAaAhIQEgQAAAEDGAEiBgmALsAWAhIQEgQAAAERGAEiBgnAPIAEAhIQEgQAAAETGAEiBgnAPYAhAhIQEgQAAAEOGAEiBgmAP6AgAhIQEgQAAAELGAEiBgnAPcApAhIQEgQAAAEBGAEiBgnAPIACAhIQEgQAAAEKGAEiBgnAPcAhAhIQEgQAAAEBGAEiBgnAPcAhAhIQEgQAAAEHGAEiBgnAPaAqAhIQEgQAAAEFGAEiBgmgPeAYAhIQEgQADAEJGAEiBgnAPcAhAhIQEgQADAEFGAEiBgnAP6A0AhIQEgQAFAEGGAEiBgmAP6AgAhIQEgQAAAEVGAEiBgmAP6AgAhoFY291bnQaCnByb3BlcnRpZXMiAwoBMSI/Cj17ICJhcnJlc3QiIDogImZhbHNlIiwgInByaW1hcnlfdHlwZSIgOiAiREVDRVBUSVZFIFBSQUNUSUNFIiB9IkAKPnsgImFycmVzdCIgOiAiZmFsc2UiLCAicHJpbWFyeV90eXBlIiA6ICJNT1RPUiBWRUhJQ0xFIFRIRUZUIiB9IjUKM3sgImFycmVzdCIgOiAiZmFsc2UiLCAicHJpbWFyeV90eXBlIiA6ICJCVVJHTEFSWSIgfSI0CjJ7ICJhcnJlc3QiIDogImZhbHNlIiwgInByaW1hcnlfdHlwZSIgOiAiQkFUVEVSWSIgfSIyCjB7ICJhcnJlc3QiIDogImZhbHNlIiwgInByaW1hcnlfdHlwZSIgOiAiVEhFRlQiIH0iMQoveyAiYXJyZXN0IiA6ICJ0cnVlIiwgInByaW1hcnlfdHlwZSIgOiAiVEhFRlQiIH0iNAoyeyAiYXJyZXN0IiA6ICJmYWxzZSIsICJwcmltYXJ5X3R5cGUiIDogIkFTU0FVTFQiIH0iAwoBNyI8Cjp7ICJhcnJlc3QiIDogImZhbHNlIiwgInByaW1hcnlfdHlwZSIgOiAiQ1JJTUlOQUwgREFNQUdFIiB9IjUKM3sgImFycmVzdCIgOiAidHJ1ZSIsICJwcmltYXJ5X3R5cGUiIDogIk5BUkNPVElDUyIgfSIzCjF7ICJhcnJlc3QiIDogInRydWUiLCAicHJpbWFyeV90eXBlIiA6ICJCQVRURVJZIiB9IgMKATIiAwoBNCI6Cjh7ICJhcnJlc3QiIDogImZhbHNlIiwgInByaW1hcnlfdHlwZSIgOiAiT1RIRVIgT0ZGRU5TRSIgfSI4CjZ7ICJhcnJlc3QiIDogImZhbHNlIiwgInByaW1hcnlfdHlwZSIgOiAiU0VYIE9GRkVOU0UiIH0iOQo3eyAiYXJyZXN0IiA6ICJ0cnVlIiwgInByaW1hcnlfdHlwZSIgOiAiT1RIRVIgT0ZGRU5TRSIgfSIzCjF7ICJhcnJlc3QiIDogInRydWUiLCAicHJpbWFyeV90eXBlIiA6ICJBU1NBVUxUIiB9Ij0KO3sgImFycmVzdCIgOiAidHJ1ZSIsICJwcmltYXJ5X3R5cGUiIDogIkNSSU1JTkFMIFRSRVNQQVNTIiB9Ij0KO3sgImFycmVzdCIgOiAidHJ1ZSIsICJwcmltYXJ5X3R5cGUiIDogIldFQVBPTlMgVklPTEFUSU9OIiB9IgMKATgiOwo5eyAiYXJyZXN0IiA6ICJ0cnVlIiwgInByaW1hcnlfdHlwZSIgOiAiQ1JJTUlOQUwgREFNQUdFIiB9KIAgeAE=", - "zoom" : 5, - "style": "#main {marker-fill: #006; marker-width: 3; marker-line-color: #009; marker-line-width: 1; polygon-fill: #900;}" -} diff --git a/carto_renderer/examples/main.mss b/carto_renderer/examples/main.mss deleted file mode 100644 index 900b8da..0000000 --- a/carto_renderer/examples/main.mss +++ /dev/null @@ -1,7 +0,0 @@ -#main { - marker-fill: #006; - marker-width: 3; - marker-line-color: #009; - marker-line-width: 1; - polygon-fill: #900; -} diff --git a/carto_renderer/examples/min.mss b/carto_renderer/examples/min.mss deleted file mode 100644 index f4785aa..0000000 --- a/carto_renderer/examples/min.mss +++ /dev/null @@ -1 +0,0 @@ -#main{marker-line-color:#00C;marker-width:1} diff --git a/carto_renderer/service.py b/carto_renderer/service.py index 174cf6f..ebc1350 100755 --- a/carto_renderer/service.py +++ b/carto_renderer/service.py @@ -4,9 +4,9 @@ """ import json -from urllib import quote_plus +from urllib.parse import quote_plus -from tornado import web +from tornado import web, escape from tornado.httpclient import AsyncHTTPClient, HTTPRequest from tornado.ioloop import IOLoop from tornado.options import define, parse_command_line, options @@ -49,8 +49,7 @@ def render_png(tile, _zoom, xml, overscan): box_max = TILE_SIZE + overscan - 1 map_tile.zoom_to_box(mapnik.Box2d(box_min, box_min, box_max, box_max)) - for (name, features) in tile.items(): - name = name.encode('ascii', 'ignore') + for (name, features) in list(tile.items()): source = mapnik.MemoryDatasource() map_layer = mapnik.Layer(name) map_layer.datasource = source @@ -103,10 +102,10 @@ def extract_body(self): body = self.request.body try: - extracted = msgpack.loads(body) + extracted = msgpack.loads(body, raw=True) except Exception: logger.warn('Invalid message') - raise BadRequest('Could not parse message.', body) + raise BadRequest('Could not parse message.', escape.to_unicode(body)) return extracted def _handle_request_exception(self, err): @@ -119,13 +118,14 @@ def _handle_request_exception(self, err): logger.exception(err) if isinstance(err, ServiceError): status_code = err.status_code + payload['message'] = err.message if err.request_body: payload['request_body'] = err.request_body else: + payload['message'] = str(err) status_code = 500 payload['resultCode'] = status_code - payload['message'] = err.message self.clear() self.set_status(status_code) @@ -168,7 +168,7 @@ class RenderHandler(BaseHandler): Expects a dictionary with 'style', 'zoom', and 'tile' values. """ - keys = ['tile', 'zoom', 'style'] + keys = [b'tile', b'zoom', b'style'] def initialize(self, http_client, style_host, style_port): """Magic Tornado __init__ replacement.""" @@ -176,8 +176,8 @@ def initialize(self, http_client, style_host, style_port): self.style_host = style_host # pragma: no cover self.style_port = style_port # pragma: no cover - @web.asynchronous - def post(self): +# @web.asynchronous + async def post(self): """ Actually render the png. @@ -192,7 +192,7 @@ def post(self): raise PayloadKeyError(self.keys, geobody) else: try: - overscan = int(geobody['overscan']) + overscan = int(geobody[b'overscan']) except: logger.warn('Invalid JSON; overscan must be an integer: %s', geobody) @@ -200,7 +200,7 @@ def post(self): request_body=geobody) try: - zoom = int(geobody['zoom']) + zoom = int(geobody[b'zoom']) except: logger.warn('Invalid JSON; zoom must be an integer: %s', geobody) @@ -210,9 +210,9 @@ def post(self): path = 'http://{host}:{port}/style?style={css}'.format( host=self.style_host, port=self.style_port, - css=quote_plus(geobody['style'])) + css=quote_plus(geobody[b'style'])) - tile = geobody['tile'] + tile = geobody[b'tile'] def handle_response(response): """ @@ -228,7 +228,7 @@ def handle_response(response): logger.info('zoom: %d, num features: %d, len(xml): %d', zoom, - sum([len(layer) for layer in tile.values()]), + sum([len(layer) for layer in list(tile.values())]), len(xml)) logger.debug('xml: %s', LogWrapper.Lazy(lambda: xml.replace('\n', ' '))) @@ -241,7 +241,8 @@ def handle_response(response): else {} req = HTTPRequest(path, headers=headers) - self.http_client.fetch(req, callback=handle_response) + resp = await self.http_client.fetch(req) + handle_response(resp) def main(): # pragma: no cover diff --git a/carto_renderer/test/test_service.py b/carto_renderer/test/test_service.py index de4c8ae..9726e8d 100644 --- a/carto_renderer/test/test_service.py +++ b/carto_renderer/test/test_service.py @@ -1,10 +1,12 @@ # pylint: disable=missing-docstring,line-too-long,import-error,abstract-method import string -from urllib import quote_plus +from urllib.parse import quote_plus from base64 import b64encode import json import mock +import asyncio +import pytest from hypothesis import given from hypothesis.strategies import integers, text from pytest import raises @@ -13,7 +15,7 @@ from carto_renderer import service, errors def tile_encode(layer): - return {k: [b64encode(f) for f in feats] for k, feats in layer.items()} + return {k: [b64encode(f) for f in feats] for k, feats in list(layer.items())} def to_wkb(*wkts): @@ -36,10 +38,10 @@ def __init__(self, style, xml): self.resp = MockClient.MockResp(xml) self.style = style - def fetch(self, req, callback): + async def fetch(self, req): path = req.url assert path.endswith(quote_plus(self.style)) - callback(self.resp) + return self.resp class StringHandler(RequestHandler): @@ -76,10 +78,10 @@ def set_status(self, code, reason=None): self.status_reason = reason def was_written(self): - return u''.join([unicode(s) for s in self.written]) + return ''.join([str(s) for s in self.written]) def was_written_b64(self): - return u''.join([b64encode(s) for s in self.written]) + return b''.join([b64encode(s) for s in self.written]) class BaseStrHandler(service.BaseHandler, StringHandler): @@ -158,55 +160,54 @@ def test_base_handler_bad_req(): base.extract_body() assert "could not parse" in bad_json.value.message.lower() - -def test_render_handler_bad_req(): +@pytest.mark.asyncio +async def test_render_handler_bad_req(): keys = ["tile", "zoom", "style"] with raises(errors.PayloadKeyError) as empty_tile: render = RenderStrHandler() render.request.headers['content-type'] = 'application/octet-stream' render.body = {} - render.post() + await render.post() for k in keys: assert k in empty_tile.value.message.lower() with raises(errors.PayloadKeyError) as no_style: render = RenderStrHandler() render.request.headers['content-type'] = 'application/octet-stream' - render.body = {"zoom": "", "body": ""} - render.post() + render.body = {b'zoom': '', b'body': ''} + await render.post() for k in keys: assert k in no_style.value.message.lower() with raises(errors.PayloadKeyError) as no_zoom: render = RenderStrHandler() render.request.headers['content-type'] = 'application/octet-stream' - render.body = {"style": "", "tile": ""} - render.post() + render.body = {b'style': '', b'tile': ''} + await render.post() for k in keys: assert k in no_zoom.value.message.lower() with raises(errors.PayloadKeyError) as no_tile: render = RenderStrHandler() render.request.headers['content-type'] = 'application/octet-stream' - render.body = {"style": "", "zoom": ""} - render.post() + render.body = {b'style': '', b'zoom': ''} + await render.post() for k in keys: assert k in no_tile.value.message.lower() with raises(errors.BadRequest) as bad_zoom: render = RenderStrHandler() render.request.headers['content-type'] = 'application/octet-stream' - render.body = {"style": "", "zoom": "", "tile": "", "overscan": 32} - render.post() + render.body = {b'style': '', b'zoom': '', b'tile': '', b'overscan': 32} + await render.post() with raises(errors.BadRequest) as bad_overscan: render = RenderStrHandler() render.request.headers['content-type'] = 'application/octet-stream' - render.body = {"style": "", "zoom": "", "tile": "", "overscan": ""} - render.post() - + render.body = {b"style": "", b"zoom": "", b"tile": "", b"overscan": ""} + await render.post() assert "zoom" in bad_zoom.value.message.lower() assert "int" in bad_zoom.value.message.lower() @@ -215,7 +216,8 @@ def test_render_handler_bad_req(): @given(text(alphabet=string.printable), text(alphabet=string.printable)) -def test_render_handler(host, port): +@pytest.mark.asyncio +async def test_render_handler(host, port): """ This is a simple regression test, it only hits one case. """ @@ -240,14 +242,14 @@ def test_render_handler(host, port): } tile = tile_encode(layer) - handler.body = {'zoom': 14, 'style': css, 'tile': tile, 'overscan' : 0} + handler.body = {b'zoom': 14, b'style': css, b'tile': tile, b'overscan' : 0} handler.http_client = MockClient(css, xml) handler.style_host = str(host) handler.style_port = str(port) - handler.post() + await handler.post() - expected = """iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAABFUlEQVR4nO3BMQEAAADCoPVP7WsIoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAMBPAABPO1TCQAAAABJRU5ErkJggg==""" # noqa + expected = b"""iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAABFUlEQVR4nO3BMQEAAADCoPVP7WsIoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAMBPAABPO1TCQAAAABJRU5ErkJggg==""" # noqa assert handler.finished assert handler.was_written_b64() == expected @@ -255,7 +257,8 @@ def test_render_handler(host, port): @given(text(alphabet=string.printable), text(alphabet=string.printable)) -def test_render_handler_no_xml(host, port): +@pytest.mark.asyncio +async def test_render_handler_no_xml(host, port): css = '#main{marker-line-color:#00C;marker-width:1}' layer = { "main": to_wkb("POINT(50 50)") @@ -264,19 +267,19 @@ def test_render_handler_no_xml(host, port): tile = tile_encode(layer) handler = RenderStrHandler() - handler.body = {'zoom': 14, 'style': css, 'tile': tile, 'overscan': 32} + handler.body = {b'zoom': 14, b'style': css, b'tile': tile, b'overscan': 32} handler.http_client = MockClient(css, None) handler.style_host = str(host) handler.style_port = str(port) with raises(errors.ServiceError) as no_xml: - handler.post() + await handler.post() assert "style-renderer" in no_xml.value.message.lower() def test_render_png_ignores_bad_wkb(): - expected = """iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAABLUlEQVR4nO3OQQkAIBQFwVfLQIYwmkE0j2YQ5F9mYO+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/ZI1qy+AErsduvVFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8dAAgUwUoWSdR9gAAAABJRU5ErkJggg==""" # noqa + expected = b"""iVBORw0KGgoAAAANSUhEUgAAAQAAAAEACAYAAABccqhmAAABLUlEQVR4nO3OQQkAIBQFwVfLQIYwmkE0j2YQ5F9mYO+bAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL/ZI1qy+AErsduvVFwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB8dAAgUwUoWSdR9gAAAABJRU5ErkJggg==""" # noqa tile = { "main": to_wkb("POINT(50 50)") + ['INVALID'] diff --git a/carto_renderer/util.py b/carto_renderer/util.py index 2cb69b5..bbe9e1d 100644 --- a/carto_renderer/util.py +++ b/carto_renderer/util.py @@ -34,7 +34,7 @@ def info(self, *args): def warn(self, *args): """Log a warning.""" - self.underlying.warn(*args, extra=LogWrapper.ENV) + self.underlying.warning(*args, extra=LogWrapper.ENV) def error(self, *args): """Log an error.""" diff --git a/dev-requirements.txt b/dev-requirements.txt index f1ff5ae..1d42214 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,7 +1,9 @@ -msgpack-python +msgpack tornado +asyncio -hypothesis # test -mock # test -pytest # test -sh # test +hypothesis # test +mock # test +pytest # test +sh # test +pytest-asyncio # test