pngtile/application.py
author Tero Marttila <terom@paivola.fi>
Sun, 14 Sep 2014 23:17:45 +0300
changeset 139 8eff4a9fdd5e
parent 138 59d61da2b64f
child 146 0f2a918eb90a
permissions -rw-r--r--
pngtile.application: BaseApplication.render_html(end=...) to place scripts at end of body, after script-src's
138
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     1
from werkzeug import Request, Response, exceptions
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     2
from werkzeug.utils import html
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     3
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     4
import pypngtile
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     5
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     6
import os.path
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     7
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     8
class BaseApplication (object):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
     9
    def __init__ (self, image_root):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    10
        if not os.path.isdir(image_root) :
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    11
            raise Exception("Given image_root does not exist: {image_root}".format(image_root=image_root))
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    12
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    13
        self.image_root = os.path.abspath(image_root)
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    14
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    15
        self.image_cache = { }
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    16
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    17
    def lookup_image (self, url):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    18
        """
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    19
            Lookup image by request path.
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    20
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    21
            Returns image_name, image_path.
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    22
        """
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    23
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    24
        if not os.path.isdir(self.image_root):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    25
            raise exceptions.InternalServerError("Server image_root has gone missing")
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    26
    
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    27
        # path to image
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    28
        name = url.lstrip('/')
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    29
        
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    30
        # build absolute path
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    31
        path = os.path.abspath(os.path.join(self.image_root, name))
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    32
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    33
        # ensure the path points inside the data root
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    34
        if not path.startswith(self.image_root):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    35
            raise exceptions.NotFound(name)
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    36
        
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    37
        if not os.path.exists(path):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    38
            raise exceptions.NotFound(name)
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    39
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    40
        if os.path.isdir(path):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    41
            raise exceptions.BadRequest("Is a directory: {name}".format(name=name))
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    42
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    43
        if not path.endswith('.png'):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    44
            raise exceptions.BadRequest("Not a PNG image: {name}".format(name=name))
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    45
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    46
        return name, path
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    47
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    48
    def get_image (self, url):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    49
        """
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    50
            Return Image object.
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    51
        """
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    52
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    53
        name, path = self.lookup_image(url)
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    54
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    55
        # get Image object
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    56
        image = self.image_cache.get(path)
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    57
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    58
        if not image:
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    59
            # open
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    60
            image = pypngtile.Image(path)
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    61
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    62
            # check
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    63
            if image.status() not in (pypngtile.CACHE_FRESH, pypngtile.CACHE_STALE):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    64
                raise exceptions.InternalServerError("Image cache not available: {name}".format(name=name))
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    65
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    66
            # load
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    67
            image.open()
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    68
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    69
            # cache
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    70
            self.image_cache[path] = image
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    71
        
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    72
        return image, name
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    73
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    74
    def handle (self, request):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    75
        """
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    76
            Handle request for an image
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    77
        """
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    78
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    79
        raise NotImplementedError()
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    80
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    81
    @Request.application
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    82
    def __call__ (self, request):
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    83
        """
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    84
            WSGI entry point.
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    85
        """
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    86
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    87
        try:
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    88
            return self.handle(request)
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    89
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    90
        except exceptions.HTTPException as error:
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    91
            return error
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    92
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    93
    STYLESHEETS = ( )
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    94
    SCRIPTS = ( )
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    95
139
8eff4a9fdd5e pngtile.application: BaseApplication.render_html(end=...) to place scripts at end of body, after script-src's
Tero Marttila <terom@paivola.fi>
parents: 138
diff changeset
    96
    def render_html (self, title, body, stylesheets=None, scripts=None, end=()):
138
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    97
        if stylesheets is None:
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    98
            stylesheets = self.STYLESHEETS
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
    99
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   100
        if scripts is None:
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   101
            scripts = self.SCRIPTS
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   102
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   103
        return html.html(lang='en', *[
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   104
            html.head(
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   105
                html.title(title),
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   106
                *[
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   107
                    html.link(rel='stylesheet', href=href) for href in stylesheets
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   108
                ]
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   109
            ),
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   110
            html.body(
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   111
                *(body + tuple(
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   112
                    html.script(src=src) for src in scripts
139
8eff4a9fdd5e pngtile.application: BaseApplication.render_html(end=...) to place scripts at end of body, after script-src's
Tero Marttila <terom@paivola.fi>
parents: 138
diff changeset
   113
                ) + end)
138
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   114
            ),
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   115
        ])
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   116
59d61da2b64f pngtile.tile: split off BaseAppliation
Tero Marttila <terom@paivola.fi>
parents:
diff changeset
   117