This file is indexed.

/usr/lib/python2.7/dist-packages/pyramid_jinja2/__init__.py is in python-pyramid-jinja2 2.7+dfsg-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
import inspect
import os
import posixpath
import sys

from jinja2 import Environment as _Jinja2Environment

from jinja2.exceptions import TemplateNotFound
from jinja2.loaders import FileSystemLoader
from jinja2.utils import open_if_exists

from pyramid.asset import abspath_from_asset_spec
from pyramid.path import DottedNameResolver

from zope.deprecation import deprecated
from zope.interface import Interface

from .compat import text_type
from .settings import (
    parse_env_options_from_settings,
    parse_loader_options_from_settings,
    parse_multiline,
)


ENV_CONFIG_PHASE = 0
EXTRAS_CONFIG_PHASE = 1
PARENT_RELATIVE_DELIM = '@@FROM_PARENT@@'


class IJinja2Environment(Interface):
    pass


class Environment(_Jinja2Environment):
    def join_path(self, uri, parent):
        if os.path.isabs(uri) or ':' in uri:
            # we have an asset spec or absolute path
            return uri

        # uri may be relative to the parent, shuffle it through to the loader
        return uri + PARENT_RELATIVE_DELIM + parent


class FileInfo(object):
    open_if_exists = staticmethod(open_if_exists)
    getmtime = staticmethod(os.path.getmtime)

    def __init__(self, filename, encoding='utf-8'):
        self.filename = filename
        self.encoding = encoding

    def _delay_init(self):
        if '_mtime' in self.__dict__:
            return

        f = self.open_if_exists(self.filename)
        if f is None:
            raise TemplateNotFound(self.filename)
        self._mtime = self.getmtime(self.filename)

        data = ''
        try:
            data = f.read()
        finally:
            f.close()

        if not isinstance(data, text_type):
            data = data.decode(self.encoding)
        self._contents = data

    @property
    def contents(self):
        self._delay_init()
        return self._contents

    @property
    def mtime(self):
        self._delay_init()
        return self._mtime

    def uptodate(self):
        try:
            return os.path.getmtime(self.filename) == self.mtime
        except OSError:
            return False


class _PackageFinder(object):
    inspect = staticmethod(inspect)

    def caller_package(self, excludes=()):
        """A list of excluded patterns, optionally containing a `.` suffix.
        For example, ``'pyramid.'`` would exclude exclude ``'pyramid.config'``
        but not ``'pyramid'``.
        """
        f = None
        for t in self.inspect.stack():
            f = t[0]
            name = f.f_globals.get('__name__')
            if name:
                excluded = False
                for pattern in excludes:
                    if pattern[-1] == '.' and name.startswith(pattern):
                        excluded = True
                        break
                    elif name == pattern:
                        excluded = True
                        break
                if not excluded:
                    break

        if f is None:
            return None

        pname = f.f_globals.get('__name__') or '__main__'
        m = sys.modules[pname]
        f = getattr(m, '__file__', '')
        if (('__init__.py' in f) or ('__init__$py' in f)):  # empty at >>>
            return m

        pname = m.__name__.rsplit('.', 1)[0]

        return sys.modules[pname]


_caller_package = _PackageFinder().caller_package


class SmartAssetSpecLoader(FileSystemLoader):
    '''A Jinja2 template loader that knows how to handle
    asset specifications.
    '''

    def __init__(self, searchpath=(), encoding='utf-8', debug=False):
        FileSystemLoader.__init__(self, searchpath, encoding)
        self.debug = debug

    def list_templates(self):
        raise TypeError('this loader cannot iterate over all templates')

    def _get_absolute_source(self, template):
        filename = abspath_from_asset_spec(template)
        fi = FileInfo(filename, self.encoding)
        if os.path.isfile(fi.filename):
            return fi.contents, fi.filename, fi.uptodate

    def _relative_searchpath(self, chain):
        """ Combine paths in the chain to construct search paths.

        The precedence is for the most-specific paths to be tested first,
        anchored at an absolute path or asset spec. From there, less-specific
        paths are tested.

        For example::
            chain = [
                '../forms.jinja2', 'sub/nav.jinja2',
                'base.jinja2', 'myapp:templates/index.jinja2',
            ]
            searchpath = ['myapp:templates/sub/..', 'sub/..', '..', '']
        """
        # the initial empty string is important because not only does it allow
        # the stack to always contain something join, but it allows the
        # later for-loops to fallback to the original search path by
        # joining to an empty string since os.path.join('', 'foo') == 'foo'
        stack = ['']
        for path in chain:
            is_abspath = os.path.isabs(path)
            is_spec = not is_abspath and ':' in path

            if not is_abspath and is_spec:
                ppkg, ppath = path.split(':', 1)
                path = '{0}:{1}'.format(ppkg, posixpath.dirname(ppath))
            else:
                # this should split windows and posix paths
                path = os.path.dirname(path)

            if not path:
                # skip empty directories
                continue

            subpath = stack[-1]
            path = posixpath.join(path, subpath)
            stack.append(path)

            # do not continue further, all paths are relative to this
            if is_abspath or is_spec:
                break
        return list(reversed(stack))

    def get_source(self, environment, template):
        # keep legacy asset: prefix checking that bypasses
        # source path checking altogether
        if template.startswith('asset:'):
            template = template[6:]

        # split the template into the chain of relative-imports
        rel_chain = template.split(PARENT_RELATIVE_DELIM)
        template, rel_chain = rel_chain[0], rel_chain[1:]

        # load the template directly if it's an absolute path or asset spec
        if os.path.isabs(template) or ':' in template:
            src = self._get_absolute_source(template)
            if src is not None:
                return src
            else:
                # fallback to the search path just incase
                return FileSystemLoader.get_source(self, environment, template)

        # try to import the template as an asset spec or absolute path
        # relative to its parents
        rel_searchpath = self._relative_searchpath(rel_chain)
        for parent in rel_searchpath:
            if os.path.isabs(parent):
                uri = os.path.join(parent, template)
                # avoid recursive includes
                if uri not in rel_chain:
                    src = self._get_absolute_source(uri)
                    if src is not None:
                        return src
            # avoid doing "':' in" and then redundant "split"
            parts = parent.split(':', 1)
            if len(parts) > 1:
                # parent is an asset spec
                ppkg, ppath = parts
                ppath = posixpath.join(ppath, template)
                uri = '{0}:{1}'.format(ppkg, ppath)
                # avoid recursive includes
                if uri not in rel_chain:
                    src = self._get_absolute_source(uri)
                    if src is not None:
                        return src

        # try to load the template from the default search path
        for parent in rel_searchpath:
            try:
                uri = os.path.join(parent, template)
                # avoid recursive includes
                if uri not in rel_chain:
                    return FileSystemLoader.get_source(self, environment, uri)
            except TemplateNotFound:
                pass

        # we're here because of an exception during the last step so extend
        # the message and raise an appropriate error
        # there should always be an exception because the rel_searchpath is
        # guaranteed to contain at least one element ('')
        searchpath = [p for p in rel_searchpath if p] + self.searchpath
        message = '{0}; searchpath={1}'.format(template, searchpath)
        raise TemplateNotFound(name=template, message=message)


class Jinja2TemplateRenderer(object):
    '''Renderer for a jinja2 template'''
    def __init__(self, template_loader):
        self.template_loader = template_loader

    def __call__(self, value, system):
        try:
            system.update(value)
        except (TypeError, ValueError) as ex:
            raise ValueError('renderer was passed non-dictionary '
                             'as value: %s' % str(ex))
        template = self.template_loader()
        return template.render(system)


class Jinja2RendererFactory(object):
    environment = None

    def __call__(self, info):
        name, package = info.name, info.package

        def template_loader():
            # attempt to turn the name into a caller-relative asset spec
            if ':' not in name and package is not None:
                try:
                    name_with_package = '%s:%s' % (package.__name__, name)
                    return self.environment.get_template(name_with_package)
                except TemplateNotFound:
                    pass

            return self.environment.get_template(name)

        return Jinja2TemplateRenderer(template_loader)


def renderer_factory(info):
    registry = info.registry
    env = registry.queryUtility(IJinja2Environment, name='.jinja2')
    if env is None:
        raise ValueError(
            'As of pyramid_jinja2 2.3, the use of the '
            '"pyramid_jinja2.renderer_factory" requires that pyramid_jinja2 '
            'be configured via config.include("pyramid_jinja2") or the '
            'equivalent "pyramid.includes" setting.')
    factory = Jinja2RendererFactory()
    factory.environment = env
    return factory(info)


deprecated(
    'renderer_factory',
    'The pyramid_jinja2.renderer_factory was deprecated in version 2.0 and '
    'will be removed in the future. You should upgrade to the newer '
    'config.add_jinja2_renderer() API.')


def add_jinja2_search_path(config, searchpath, name='.jinja2', prepend=False):
    """
    This function is added as a method of a :term:`Configurator`, and
    should not be called directly.  Instead it should be called like so after
    ``pyramid_jinja2`` has been passed to ``config.include``:

    .. code-block:: python

       config.add_jinja2_search_path('anotherpackage:templates/')

    It will add the directory or :term:`asset specification` passed as
    ``searchpath`` to the current search path of the
    :class:`jinja2.Environment` used by the renderer identified by ``name``.

    By default the path is appended to the end of the search path. If
    ``prepend`` is set to ``True`` then the path will be inserted at the start
    of the search path.

    """
    def register():
        env = get_jinja2_environment(config, name)
        searchpaths = parse_multiline(searchpath)
        for folder in searchpaths:
            path = abspath_from_asset_spec(folder, config.package)
            if prepend:
                env.loader.searchpath.insert(0, path)
            else:
                env.loader.searchpath.append(path)
    config.action(None, register, order=EXTRAS_CONFIG_PHASE)


def add_jinja2_extension(config, ext, name='.jinja2'):
    """
    This function is added as a method of a :term:`Configurator`, and
    should not be called directly.  Instead it should be called like so after
    ``pyramid_jinja2`` has been passed to ``config.include``:

    .. code-block:: python

       config.add_jinja2_extension(myext)

    It will add the Jinja2 extension passed as ``ext`` to the current
    :class:`jinja2.Environment` used by the renderer named ``name``.

    """
    ext = config.maybe_dotted(ext)
    def register():
        env = get_jinja2_environment(config, name)
        env.add_extension(ext)
    config.action(None, register, order=EXTRAS_CONFIG_PHASE)


def get_jinja2_environment(config, name='.jinja2'):
    """
    This function is added as a method of a :term:`Configurator`, and
    should not be called directly.  Instead it should be called like so after
    ``pyramid_jinja2`` has been passed to ``config.include``:

    .. code-block:: python

       config.get_jinja2_environment()

    It will return the configured ``jinja2.Environment`` for the
    renderer named ``name``. The environment is created as an :term:`action`
    which is deferred to allow users to override the configuration. In order
    to get back the configured environment, you must either force a commit
    via ``config.commit`` or schedule an action which can setup the
    environment after it has been created:

    .. code-block:: python

       def setup_jinja2_env():
           env = config.get_jinja2_environment()
           # ...
       config.action(None, setup_jinja2_env, order=999)

    """
    registry = config.registry
    return registry.queryUtility(IJinja2Environment, name=name)


def create_environment_from_options(env_opts, loader_opts):
    loader = SmartAssetSpecLoader(**loader_opts)

    newstyle = env_opts.pop('newstyle', False)
    gettext = env_opts.pop('gettext', None)
    filters = env_opts.pop('filters', {})
    tests = env_opts.pop('tests', {})
    globals = env_opts.pop('globals', {})

    env = Environment(
        loader=loader,
        **env_opts
    )

    env.install_gettext_callables(
        gettext.gettext, gettext.ngettext, newstyle=newstyle)

    env.filters.update(filters)
    env.tests.update(tests)
    env.globals.update(globals)

    return env


def add_jinja2_renderer(config, name, settings_prefix='jinja2.', package=None):
    """
    This function is added as a method of a :term:`Configurator`, and
    should not be called directly.  Instead it should be called like so after
    ``pyramid_jinja2`` has been passed to ``config.include``:

    .. code-block:: python

       config.add_jinja2_renderer('.html', settings_prefix='jinja2.')

    It will register a new renderer, loaded from settings at the specified
    ``settings_prefix`` prefix. This renderer will be active for files using
    the specified extension ``name``.

    """
    renderer_factory = Jinja2RendererFactory()
    config.add_renderer(name, renderer_factory)

    package = package or config.package
    resolver = DottedNameResolver(package=package)

    def register():
        registry = config.registry
        settings = config.get_settings()

        loader_opts = parse_loader_options_from_settings(
            settings,
            settings_prefix,
            resolver.maybe_resolve,
            package,
        )
        env_opts = parse_env_options_from_settings(
            settings,
            settings_prefix,
            resolver.maybe_resolve,
            package,
        )
        env = create_environment_from_options(env_opts, loader_opts)
        renderer_factory.environment = env

        registry.registerUtility(env, IJinja2Environment, name=name)

    config.action(
        ('jinja2-renderer', name), register, order=ENV_CONFIG_PHASE)


def includeme(config):
    """Set up standard configurator registrations.  Use via:

    .. code-block:: python

       config = Configurator()
       config.include('pyramid_jinja2')

    Once this function has been invoked, the ``.jinja2`` renderer is
    available for use in Pyramid and these new directives are available as
    methods of the configurator:

    - ``add_jinja2_renderer``: Add a new Jinja2 renderer, with a different
      file extension and/or settings.

    - ``add_jinja2_search_path``: Add a new location to the search path
      for the specified renderer.

    - ``add_jinja2_extension``: Add a list of extensions to the Jinja2
      environment used by the specified renderer.

    - ``get_jinja2_environment``: Return the :class:`jinja2.Environment`
      used by the specified renderer.

    """
    config.add_directive('add_jinja2_renderer', add_jinja2_renderer)
    config.add_directive('add_jinja2_search_path', add_jinja2_search_path)
    config.add_directive('add_jinja2_extension', add_jinja2_extension)
    config.add_directive('get_jinja2_environment', get_jinja2_environment)

    package = _caller_package(('pyramid', 'pyramid.', 'pyramid_jinja2'))
    config.add_jinja2_renderer('.jinja2', package=package)

    # always insert default search path relative to package
    default_search_path = '%s:' % (package.__name__,)
    config.add_jinja2_search_path(default_search_path, name='.jinja2')