Skip to content

Defining a custom tilestache provider

larsclaussen edited this page Jul 31, 2017 · 6 revisions

Lately I was exploring tilestache with mapnik in a basic setup using docker and docker-compose. Now it is time to dig a little deeper. In a project we are considering to use tilestache, but we must be able to change some input variables dynamically. Especially to set the input directory of the datasource is a main objective. tilestache's custom providers to the rescue! A custom provider basically sub-classes the provider you are defining in your config, in our case the ImageProvider. As the doc string of the provider states:

ImageProvider is known as "mapnik" in TileStache config

A config using mapnik could look like this

...
       "grid":
       {
          "provider":
          {
            "name": "mapnik",
            "mapfile": "/tiles/styles/style_grid.xml"
            }
        },
...

The ImageProvider class implementation shows that two arguments are required, the layer instance and a mapfile. The mapfile variable, however, will not be used until the renderArea method is executed. So all we have to do is set the mapfile attribute before the method is called by sub-classing it. In our use case the state information is stored in redis, but I believe you'll get the picture.

import redis
import os

from TileStache.Mapnik import ImageProvider as MapnikProvider

_mapfile_cache = {}

class ShapeProvider(MapnikProvider, object):

    def __init__(self, *args, **kwargs):
        self.mapfile = None
        self.key = None

        super(ShapeProvider, self).__init__(*args, **kwargs)
        self.redis_client = redis.Redis()


    def renderArea(self, *args, **kwargs):
        self.set_mapfile()
        return super(ShapeProvider, self).renderArea(*args, **kwargs)

    def set_mapfile(self):
        """Set the mapfile variable."""
        _mapfile = _mapfile_cache.get(self.key)
        if not _mapfile:
            _mapfile_path = self.redis_client.get('mapfile:%s' % self.key)
            _mapfile = os.path.join(
                _mapfile_path, 'style_grid.xml'
            )
            # put it in the local cache dict
            _mapfile_cache[self.key] = _mapfile

        if _mapfile != self.mapfile:
            logger.info("[*] Changed xml_path from {} to {}".format(self.mapfile, _mapfile))
            self.mapfile = _mapfile

The config then looks like this:

        'grid':
        {
          "provider":
          {
            'class': '<your module>.providers.Vector:ShapeProvider',
            'kwargs': {
                "mapfile": "",
            },
          },
        },
    }
Clone this wiki locally