~paparazzi-uav/paparazzi/v5.0-manual

« back to all changes in this revision

Viewing changes to sw/ext/opencv_bebop/opencv/3rdparty/jinja2/loaders.py

  • Committer: Paparazzi buildbot
  • Date: 2016-05-18 15:00:29 UTC
  • Revision ID: felix.ruess+docbot@gmail.com-20160518150029-e8lgzi5kvb4p7un9
Manual import commit 4b8bbb730080dac23cf816b98908dacfabe2a8ec from v5.0 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
"""
 
3
    jinja2.loaders
 
4
    ~~~~~~~~~~~~~~
 
5
 
 
6
    Jinja loader classes.
 
7
 
 
8
    :copyright: (c) 2010 by the Jinja Team.
 
9
    :license: BSD, see LICENSE for more details.
 
10
"""
 
11
import os
 
12
import sys
 
13
import weakref
 
14
from types import ModuleType
 
15
from os import path
 
16
from hashlib import sha1
 
17
from jinja2.exceptions import TemplateNotFound
 
18
from jinja2.utils import open_if_exists, internalcode
 
19
from jinja2._compat import string_types, iteritems
 
20
 
 
21
 
 
22
def split_template_path(template):
 
23
    """Split a path into segments and perform a sanity check.  If it detects
 
24
    '..' in the path it will raise a `TemplateNotFound` error.
 
25
    """
 
26
    pieces = []
 
27
    for piece in template.split('/'):
 
28
        if path.sep in piece \
 
29
           or (path.altsep and path.altsep in piece) or \
 
30
           piece == path.pardir:
 
31
            raise TemplateNotFound(template)
 
32
        elif piece and piece != '.':
 
33
            pieces.append(piece)
 
34
    return pieces
 
35
 
 
36
 
 
37
class BaseLoader(object):
 
38
    """Baseclass for all loaders.  Subclass this and override `get_source` to
 
39
    implement a custom loading mechanism.  The environment provides a
 
40
    `get_template` method that calls the loader's `load` method to get the
 
41
    :class:`Template` object.
 
42
 
 
43
    A very basic example for a loader that looks up templates on the file
 
44
    system could look like this::
 
45
 
 
46
        from jinja2 import BaseLoader, TemplateNotFound
 
47
        from os.path import join, exists, getmtime
 
48
 
 
49
        class MyLoader(BaseLoader):
 
50
 
 
51
            def __init__(self, path):
 
52
                self.path = path
 
53
 
 
54
            def get_source(self, environment, template):
 
55
                path = join(self.path, template)
 
56
                if not exists(path):
 
57
                    raise TemplateNotFound(template)
 
58
                mtime = getmtime(path)
 
59
                with file(path) as f:
 
60
                    source = f.read().decode('utf-8')
 
61
                return source, path, lambda: mtime == getmtime(path)
 
62
    """
 
63
 
 
64
    #: if set to `False` it indicates that the loader cannot provide access
 
65
    #: to the source of templates.
 
66
    #:
 
67
    #: .. versionadded:: 2.4
 
68
    has_source_access = True
 
69
 
 
70
    def get_source(self, environment, template):
 
71
        """Get the template source, filename and reload helper for a template.
 
72
        It's passed the environment and template name and has to return a
 
73
        tuple in the form ``(source, filename, uptodate)`` or raise a
 
74
        `TemplateNotFound` error if it can't locate the template.
 
75
 
 
76
        The source part of the returned tuple must be the source of the
 
77
        template as unicode string or a ASCII bytestring.  The filename should
 
78
        be the name of the file on the filesystem if it was loaded from there,
 
79
        otherwise `None`.  The filename is used by python for the tracebacks
 
80
        if no loader extension is used.
 
81
 
 
82
        The last item in the tuple is the `uptodate` function.  If auto
 
83
        reloading is enabled it's always called to check if the template
 
84
        changed.  No arguments are passed so the function must store the
 
85
        old state somewhere (for example in a closure).  If it returns `False`
 
86
        the template will be reloaded.
 
87
        """
 
88
        if not self.has_source_access:
 
89
            raise RuntimeError('%s cannot provide access to the source' %
 
90
                               self.__class__.__name__)
 
91
        raise TemplateNotFound(template)
 
92
 
 
93
    def list_templates(self):
 
94
        """Iterates over all templates.  If the loader does not support that
 
95
        it should raise a :exc:`TypeError` which is the default behavior.
 
96
        """
 
97
        raise TypeError('this loader cannot iterate over all templates')
 
98
 
 
99
    @internalcode
 
100
    def load(self, environment, name, globals=None):
 
101
        """Loads a template.  This method looks up the template in the cache
 
102
        or loads one by calling :meth:`get_source`.  Subclasses should not
 
103
        override this method as loaders working on collections of other
 
104
        loaders (such as :class:`PrefixLoader` or :class:`ChoiceLoader`)
 
105
        will not call this method but `get_source` directly.
 
106
        """
 
107
        code = None
 
108
        if globals is None:
 
109
            globals = {}
 
110
 
 
111
        # first we try to get the source for this template together
 
112
        # with the filename and the uptodate function.
 
113
        source, filename, uptodate = self.get_source(environment, name)
 
114
 
 
115
        # try to load the code from the bytecode cache if there is a
 
116
        # bytecode cache configured.
 
117
        bcc = environment.bytecode_cache
 
118
        if bcc is not None:
 
119
            bucket = bcc.get_bucket(environment, name, filename, source)
 
120
            code = bucket.code
 
121
 
 
122
        # if we don't have code so far (not cached, no longer up to
 
123
        # date) etc. we compile the template
 
124
        if code is None:
 
125
            code = environment.compile(source, name, filename)
 
126
 
 
127
        # if the bytecode cache is available and the bucket doesn't
 
128
        # have a code so far, we give the bucket the new code and put
 
129
        # it back to the bytecode cache.
 
130
        if bcc is not None and bucket.code is None:
 
131
            bucket.code = code
 
132
            bcc.set_bucket(bucket)
 
133
 
 
134
        return environment.template_class.from_code(environment, code,
 
135
                                                    globals, uptodate)
 
136
 
 
137
 
 
138
class FileSystemLoader(BaseLoader):
 
139
    """Loads templates from the file system.  This loader can find templates
 
140
    in folders on the file system and is the preferred way to load them.
 
141
 
 
142
    The loader takes the path to the templates as string, or if multiple
 
143
    locations are wanted a list of them which is then looked up in the
 
144
    given order:
 
145
 
 
146
    >>> loader = FileSystemLoader('/path/to/templates')
 
147
    >>> loader = FileSystemLoader(['/path/to/templates', '/other/path'])
 
148
 
 
149
    Per default the template encoding is ``'utf-8'`` which can be changed
 
150
    by setting the `encoding` parameter to something else.
 
151
    """
 
152
 
 
153
    def __init__(self, searchpath, encoding='utf-8'):
 
154
        if isinstance(searchpath, string_types):
 
155
            searchpath = [searchpath]
 
156
        self.searchpath = list(searchpath)
 
157
        self.encoding = encoding
 
158
 
 
159
    def get_source(self, environment, template):
 
160
        pieces = split_template_path(template)
 
161
        for searchpath in self.searchpath:
 
162
            filename = path.join(searchpath, *pieces)
 
163
            f = open_if_exists(filename)
 
164
            if f is None:
 
165
                continue
 
166
            try:
 
167
                contents = f.read().decode(self.encoding)
 
168
            finally:
 
169
                f.close()
 
170
 
 
171
            mtime = path.getmtime(filename)
 
172
            def uptodate():
 
173
                try:
 
174
                    return path.getmtime(filename) == mtime
 
175
                except OSError:
 
176
                    return False
 
177
            return contents, filename, uptodate
 
178
        raise TemplateNotFound(template)
 
179
 
 
180
    def list_templates(self):
 
181
        found = set()
 
182
        for searchpath in self.searchpath:
 
183
            for dirpath, dirnames, filenames in os.walk(searchpath):
 
184
                for filename in filenames:
 
185
                    template = os.path.join(dirpath, filename) \
 
186
                        [len(searchpath):].strip(os.path.sep) \
 
187
                                          .replace(os.path.sep, '/')
 
188
                    if template[:2] == './':
 
189
                        template = template[2:]
 
190
                    if template not in found:
 
191
                        found.add(template)
 
192
        return sorted(found)
 
193
 
 
194
 
 
195
class PackageLoader(BaseLoader):
 
196
    """Load templates from python eggs or packages.  It is constructed with
 
197
    the name of the python package and the path to the templates in that
 
198
    package::
 
199
 
 
200
        loader = PackageLoader('mypackage', 'views')
 
201
 
 
202
    If the package path is not given, ``'templates'`` is assumed.
 
203
 
 
204
    Per default the template encoding is ``'utf-8'`` which can be changed
 
205
    by setting the `encoding` parameter to something else.  Due to the nature
 
206
    of eggs it's only possible to reload templates if the package was loaded
 
207
    from the file system and not a zip file.
 
208
    """
 
209
 
 
210
    def __init__(self, package_name, package_path='templates',
 
211
                 encoding='utf-8'):
 
212
        from pkg_resources import DefaultProvider, ResourceManager, \
 
213
                                  get_provider
 
214
        provider = get_provider(package_name)
 
215
        self.encoding = encoding
 
216
        self.manager = ResourceManager()
 
217
        self.filesystem_bound = isinstance(provider, DefaultProvider)
 
218
        self.provider = provider
 
219
        self.package_path = package_path
 
220
 
 
221
    def get_source(self, environment, template):
 
222
        pieces = split_template_path(template)
 
223
        p = '/'.join((self.package_path,) + tuple(pieces))
 
224
        if not self.provider.has_resource(p):
 
225
            raise TemplateNotFound(template)
 
226
 
 
227
        filename = uptodate = None
 
228
        if self.filesystem_bound:
 
229
            filename = self.provider.get_resource_filename(self.manager, p)
 
230
            mtime = path.getmtime(filename)
 
231
            def uptodate():
 
232
                try:
 
233
                    return path.getmtime(filename) == mtime
 
234
                except OSError:
 
235
                    return False
 
236
 
 
237
        source = self.provider.get_resource_string(self.manager, p)
 
238
        return source.decode(self.encoding), filename, uptodate
 
239
 
 
240
    def list_templates(self):
 
241
        path = self.package_path
 
242
        if path[:2] == './':
 
243
            path = path[2:]
 
244
        elif path == '.':
 
245
            path = ''
 
246
        offset = len(path)
 
247
        results = []
 
248
        def _walk(path):
 
249
            for filename in self.provider.resource_listdir(path):
 
250
                fullname = path + '/' + filename
 
251
                if self.provider.resource_isdir(fullname):
 
252
                    _walk(fullname)
 
253
                else:
 
254
                    results.append(fullname[offset:].lstrip('/'))
 
255
        _walk(path)
 
256
        results.sort()
 
257
        return results
 
258
 
 
259
 
 
260
class DictLoader(BaseLoader):
 
261
    """Loads a template from a python dict.  It's passed a dict of unicode
 
262
    strings bound to template names.  This loader is useful for unittesting:
 
263
 
 
264
    >>> loader = DictLoader({'index.html': 'source here'})
 
265
 
 
266
    Because auto reloading is rarely useful this is disabled per default.
 
267
    """
 
268
 
 
269
    def __init__(self, mapping):
 
270
        self.mapping = mapping
 
271
 
 
272
    def get_source(self, environment, template):
 
273
        if template in self.mapping:
 
274
            source = self.mapping[template]
 
275
            return source, None, lambda: source == self.mapping.get(template)
 
276
        raise TemplateNotFound(template)
 
277
 
 
278
    def list_templates(self):
 
279
        return sorted(self.mapping)
 
280
 
 
281
 
 
282
class FunctionLoader(BaseLoader):
 
283
    """A loader that is passed a function which does the loading.  The
 
284
    function becomes the name of the template passed and has to return either
 
285
    an unicode string with the template source, a tuple in the form ``(source,
 
286
    filename, uptodatefunc)`` or `None` if the template does not exist.
 
287
 
 
288
    >>> def load_template(name):
 
289
    ...     if name == 'index.html':
 
290
    ...         return '...'
 
291
    ...
 
292
    >>> loader = FunctionLoader(load_template)
 
293
 
 
294
    The `uptodatefunc` is a function that is called if autoreload is enabled
 
295
    and has to return `True` if the template is still up to date.  For more
 
296
    details have a look at :meth:`BaseLoader.get_source` which has the same
 
297
    return value.
 
298
    """
 
299
 
 
300
    def __init__(self, load_func):
 
301
        self.load_func = load_func
 
302
 
 
303
    def get_source(self, environment, template):
 
304
        rv = self.load_func(template)
 
305
        if rv is None:
 
306
            raise TemplateNotFound(template)
 
307
        elif isinstance(rv, string_types):
 
308
            return rv, None, None
 
309
        return rv
 
310
 
 
311
 
 
312
class PrefixLoader(BaseLoader):
 
313
    """A loader that is passed a dict of loaders where each loader is bound
 
314
    to a prefix.  The prefix is delimited from the template by a slash per
 
315
    default, which can be changed by setting the `delimiter` argument to
 
316
    something else::
 
317
 
 
318
        loader = PrefixLoader({
 
319
            'app1':     PackageLoader('mypackage.app1'),
 
320
            'app2':     PackageLoader('mypackage.app2')
 
321
        })
 
322
 
 
323
    By loading ``'app1/index.html'`` the file from the app1 package is loaded,
 
324
    by loading ``'app2/index.html'`` the file from the second.
 
325
    """
 
326
 
 
327
    def __init__(self, mapping, delimiter='/'):
 
328
        self.mapping = mapping
 
329
        self.delimiter = delimiter
 
330
 
 
331
    def get_loader(self, template):
 
332
        try:
 
333
            prefix, name = template.split(self.delimiter, 1)
 
334
            loader = self.mapping[prefix]
 
335
        except (ValueError, KeyError):
 
336
            raise TemplateNotFound(template)
 
337
        return loader, name
 
338
 
 
339
    def get_source(self, environment, template):
 
340
        loader, name = self.get_loader(template)
 
341
        try:
 
342
            return loader.get_source(environment, name)
 
343
        except TemplateNotFound:
 
344
            # re-raise the exception with the correct fileame here.
 
345
            # (the one that includes the prefix)
 
346
            raise TemplateNotFound(template)
 
347
 
 
348
    @internalcode
 
349
    def load(self, environment, name, globals=None):
 
350
        loader, local_name = self.get_loader(name)
 
351
        try:
 
352
            return loader.load(environment, local_name)
 
353
        except TemplateNotFound:
 
354
            # re-raise the exception with the correct fileame here.
 
355
            # (the one that includes the prefix)
 
356
            raise TemplateNotFound(name)
 
357
 
 
358
    def list_templates(self):
 
359
        result = []
 
360
        for prefix, loader in iteritems(self.mapping):
 
361
            for template in loader.list_templates():
 
362
                result.append(prefix + self.delimiter + template)
 
363
        return result
 
364
 
 
365
 
 
366
class ChoiceLoader(BaseLoader):
 
367
    """This loader works like the `PrefixLoader` just that no prefix is
 
368
    specified.  If a template could not be found by one loader the next one
 
369
    is tried.
 
370
 
 
371
    >>> loader = ChoiceLoader([
 
372
    ...     FileSystemLoader('/path/to/user/templates'),
 
373
    ...     FileSystemLoader('/path/to/system/templates')
 
374
    ... ])
 
375
 
 
376
    This is useful if you want to allow users to override builtin templates
 
377
    from a different location.
 
378
    """
 
379
 
 
380
    def __init__(self, loaders):
 
381
        self.loaders = loaders
 
382
 
 
383
    def get_source(self, environment, template):
 
384
        for loader in self.loaders:
 
385
            try:
 
386
                return loader.get_source(environment, template)
 
387
            except TemplateNotFound:
 
388
                pass
 
389
        raise TemplateNotFound(template)
 
390
 
 
391
    @internalcode
 
392
    def load(self, environment, name, globals=None):
 
393
        for loader in self.loaders:
 
394
            try:
 
395
                return loader.load(environment, name, globals)
 
396
            except TemplateNotFound:
 
397
                pass
 
398
        raise TemplateNotFound(name)
 
399
 
 
400
    def list_templates(self):
 
401
        found = set()
 
402
        for loader in self.loaders:
 
403
            found.update(loader.list_templates())
 
404
        return sorted(found)
 
405
 
 
406
 
 
407
class _TemplateModule(ModuleType):
 
408
    """Like a normal module but with support for weak references"""
 
409
 
 
410
 
 
411
class ModuleLoader(BaseLoader):
 
412
    """This loader loads templates from precompiled templates.
 
413
 
 
414
    Example usage:
 
415
 
 
416
    >>> loader = ChoiceLoader([
 
417
    ...     ModuleLoader('/path/to/compiled/templates'),
 
418
    ...     FileSystemLoader('/path/to/templates')
 
419
    ... ])
 
420
 
 
421
    Templates can be precompiled with :meth:`Environment.compile_templates`.
 
422
    """
 
423
 
 
424
    has_source_access = False
 
425
 
 
426
    def __init__(self, path):
 
427
        package_name = '_jinja2_module_templates_%x' % id(self)
 
428
 
 
429
        # create a fake module that looks for the templates in the
 
430
        # path given.
 
431
        mod = _TemplateModule(package_name)
 
432
        if isinstance(path, string_types):
 
433
            path = [path]
 
434
        else:
 
435
            path = list(path)
 
436
        mod.__path__ = path
 
437
 
 
438
        sys.modules[package_name] = weakref.proxy(mod,
 
439
            lambda x: sys.modules.pop(package_name, None))
 
440
 
 
441
        # the only strong reference, the sys.modules entry is weak
 
442
        # so that the garbage collector can remove it once the
 
443
        # loader that created it goes out of business.
 
444
        self.module = mod
 
445
        self.package_name = package_name
 
446
 
 
447
    @staticmethod
 
448
    def get_template_key(name):
 
449
        return 'tmpl_' + sha1(name.encode('utf-8')).hexdigest()
 
450
 
 
451
    @staticmethod
 
452
    def get_module_filename(name):
 
453
        return ModuleLoader.get_template_key(name) + '.py'
 
454
 
 
455
    @internalcode
 
456
    def load(self, environment, name, globals=None):
 
457
        key = self.get_template_key(name)
 
458
        module = '%s.%s' % (self.package_name, key)
 
459
        mod = getattr(self.module, module, None)
 
460
        if mod is None:
 
461
            try:
 
462
                mod = __import__(module, None, None, ['root'])
 
463
            except ImportError:
 
464
                raise TemplateNotFound(name)
 
465
 
 
466
            # remove the entry from sys.modules, we only want the attribute
 
467
            # on the module object we have stored on the loader.
 
468
            sys.modules.pop(module, None)
 
469
 
 
470
        return environment.template_class.from_module_dict(
 
471
            environment, mod.__dict__, globals)