Moved Jinja2 into 3rdparty. Now using latest stable version from pypi (2.7.1)
This commit is contained in:
parent
224f44a255
commit
86b7e3d15d
@ -27,13 +27,13 @@
|
|||||||
:license: BSD, see LICENSE for more details.
|
:license: BSD, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
__version__ = '2.8-dev'
|
__version__ = '2.7.1'
|
||||||
|
|
||||||
# high level interface
|
# high level interface
|
||||||
from jinja2.environment import Environment, Template
|
from jinja2.environment import Environment, Template
|
||||||
|
|
||||||
# loaders
|
# loaders
|
||||||
from jinja2.loaders import BaseLoader, FileSystemLoader, \
|
from jinja2.loaders import BaseLoader, FileSystemLoader, PackageLoader, \
|
||||||
DictLoader, FunctionLoader, PrefixLoader, ChoiceLoader, \
|
DictLoader, FunctionLoader, PrefixLoader, ChoiceLoader, \
|
||||||
ModuleLoader
|
ModuleLoader
|
||||||
|
|
||||||
@ -58,7 +58,7 @@ from jinja2.utils import Markup, escape, clear_caches, \
|
|||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'Environment', 'Template', 'BaseLoader', 'FileSystemLoader',
|
'Environment', 'Template', 'BaseLoader', 'FileSystemLoader',
|
||||||
'DictLoader', 'FunctionLoader', 'PrefixLoader',
|
'PackageLoader', 'DictLoader', 'FunctionLoader', 'PrefixLoader',
|
||||||
'ChoiceLoader', 'BytecodeCache', 'FileSystemBytecodeCache',
|
'ChoiceLoader', 'BytecodeCache', 'FileSystemBytecodeCache',
|
||||||
'MemcachedBytecodeCache', 'Undefined', 'DebugUndefined',
|
'MemcachedBytecodeCache', 'Undefined', 'DebugUndefined',
|
||||||
'StrictUndefined', 'TemplateError', 'UndefinedError', 'TemplateNotFound',
|
'StrictUndefined', 'TemplateError', 'UndefinedError', 'TemplateNotFound',
|
@ -82,6 +82,12 @@ else:
|
|||||||
return filename.encode('utf-8')
|
return filename.encode('utf-8')
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
try:
|
||||||
|
next = next
|
||||||
|
except NameError:
|
||||||
|
def next(it):
|
||||||
|
return it.next()
|
||||||
|
|
||||||
|
|
||||||
def with_metaclass(meta, *bases):
|
def with_metaclass(meta, *bases):
|
||||||
# This requires a bit of explanation: the basic idea is to make a
|
# This requires a bit of explanation: the basic idea is to make a
|
||||||
@ -103,7 +109,42 @@ def with_metaclass(meta, *bases):
|
|||||||
return metaclass('temporary_class', None, {})
|
return metaclass('temporary_class', None, {})
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from collections import Mapping as mapping_types
|
||||||
|
except ImportError:
|
||||||
|
import UserDict
|
||||||
|
mapping_types = (UserDict.UserDict, UserDict.DictMixin, dict)
|
||||||
|
|
||||||
|
|
||||||
|
# common types. These do exist in the special types module too which however
|
||||||
|
# does not exist in IronPython out of the box. Also that way we don't have
|
||||||
|
# to deal with implementation specific stuff here
|
||||||
|
class _C(object):
|
||||||
|
def method(self): pass
|
||||||
|
def _func():
|
||||||
|
yield None
|
||||||
|
function_type = type(_func)
|
||||||
|
generator_type = type(_func())
|
||||||
|
method_type = type(_C().method)
|
||||||
|
code_type = type(_C.method.__code__)
|
||||||
|
try:
|
||||||
|
raise TypeError()
|
||||||
|
except TypeError:
|
||||||
|
_tb = sys.exc_info()[2]
|
||||||
|
traceback_type = type(_tb)
|
||||||
|
frame_type = type(_tb.tb_frame)
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from urllib.parse import quote_from_bytes as url_quote
|
from urllib.parse import quote_from_bytes as url_quote
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from urllib import quote as url_quote
|
from urllib import quote as url_quote
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
from thread import allocate_lock
|
||||||
|
except ImportError:
|
||||||
|
try:
|
||||||
|
from threading import Lock as allocate_lock
|
||||||
|
except ImportError:
|
||||||
|
from dummy_thread import allocate_lock
|
132
3rdparty/jinja2/_stringdefs.py
vendored
Normal file
132
3rdparty/jinja2/_stringdefs.py
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -21,7 +21,7 @@ import tempfile
|
|||||||
import fnmatch
|
import fnmatch
|
||||||
from hashlib import sha1
|
from hashlib import sha1
|
||||||
from jinja2.utils import open_if_exists
|
from jinja2.utils import open_if_exists
|
||||||
from jinja2._compat import BytesIO, pickle, PY2
|
from jinja2._compat import BytesIO, pickle, PY2, text_type
|
||||||
|
|
||||||
|
|
||||||
# marshal works better on 3.x, one hack less required
|
# marshal works better on 3.x, one hack less required
|
||||||
@ -160,7 +160,7 @@ class BytecodeCache(object):
|
|||||||
hash = sha1(name.encode('utf-8'))
|
hash = sha1(name.encode('utf-8'))
|
||||||
if filename is not None:
|
if filename is not None:
|
||||||
filename = '|' + filename
|
filename = '|' + filename
|
||||||
if isinstance(filename, unicode):
|
if isinstance(filename, text_type):
|
||||||
filename = filename.encode('utf-8')
|
filename = filename.encode('utf-8')
|
||||||
hash.update(filename)
|
hash.update(filename)
|
||||||
return hash.hexdigest()
|
return hash.hexdigest()
|
@ -16,7 +16,7 @@ from jinja2.nodes import EvalContext
|
|||||||
from jinja2.visitor import NodeVisitor
|
from jinja2.visitor import NodeVisitor
|
||||||
from jinja2.exceptions import TemplateAssertionError
|
from jinja2.exceptions import TemplateAssertionError
|
||||||
from jinja2.utils import Markup, concat, escape
|
from jinja2.utils import Markup, concat, escape
|
||||||
from jinja2._compat import range_type, text_type, string_types, \
|
from jinja2._compat import range_type, next, text_type, string_types, \
|
||||||
iteritems, NativeStringIO, imap
|
iteritems, NativeStringIO, imap
|
||||||
|
|
||||||
|
|
||||||
@ -949,16 +949,9 @@ class CodeGenerator(NodeVisitor):
|
|||||||
self.indent()
|
self.indent()
|
||||||
|
|
||||||
if node.with_context:
|
if node.with_context:
|
||||||
self.writeline('include_context = template.new_context('
|
|
||||||
'context.parent, True, locals())')
|
|
||||||
self.writeline('for name, context_blocks in context.'
|
|
||||||
'blocks.%s():' % dict_item_iter)
|
|
||||||
self.indent()
|
|
||||||
self.writeline('include_context.blocks.setdefault('
|
|
||||||
'name, [])[0:0] = context_blocks')
|
|
||||||
self.outdent()
|
|
||||||
self.writeline('for event in template.root_render_func('
|
self.writeline('for event in template.root_render_func('
|
||||||
'include_context):')
|
'template.new_context(context.parent, True, '
|
||||||
|
'locals())):')
|
||||||
else:
|
else:
|
||||||
self.writeline('for event in template.module._body_stream:')
|
self.writeline('for event in template.module._body_stream:')
|
||||||
|
|
32
3rdparty/jinja2/constants.py
vendored
Normal file
32
3rdparty/jinja2/constants.py
vendored
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
jinja.constants
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Various constants.
|
||||||
|
|
||||||
|
:copyright: (c) 2010 by the Jinja Team.
|
||||||
|
:license: BSD, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
#: list of lorem ipsum words used by the lipsum() helper function
|
||||||
|
LOREM_IPSUM_WORDS = u'''\
|
||||||
|
a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at
|
||||||
|
auctor augue bibendum blandit class commodo condimentum congue consectetuer
|
||||||
|
consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus
|
||||||
|
diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend
|
||||||
|
elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames
|
||||||
|
faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac
|
||||||
|
hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum
|
||||||
|
justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem
|
||||||
|
luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie
|
||||||
|
mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non
|
||||||
|
nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque
|
||||||
|
penatibus per pharetra phasellus placerat platea porta porttitor posuere
|
||||||
|
potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus
|
||||||
|
ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit
|
||||||
|
sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor
|
||||||
|
tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices
|
||||||
|
ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus
|
||||||
|
viverra volutpat vulputate'''
|
@ -12,10 +12,10 @@
|
|||||||
"""
|
"""
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
from types import TracebackType, CodeType
|
from types import TracebackType
|
||||||
from jinja2.utils import missing, internal_code
|
from jinja2.utils import missing, internal_code
|
||||||
from jinja2.exceptions import TemplateSyntaxError
|
from jinja2.exceptions import TemplateSyntaxError
|
||||||
from jinja2._compat import iteritems, reraise
|
from jinja2._compat import iteritems, reraise, code_type
|
||||||
|
|
||||||
# on pypy we can take advantage of transparent proxies
|
# on pypy we can take advantage of transparent proxies
|
||||||
try:
|
try:
|
||||||
@ -245,11 +245,11 @@ def fake_exc_info(exc_info, filename, lineno):
|
|||||||
location = 'block "%s"' % function[6:]
|
location = 'block "%s"' % function[6:]
|
||||||
else:
|
else:
|
||||||
location = 'template'
|
location = 'template'
|
||||||
code = CodeType(0, code.co_nlocals, code.co_stacksize,
|
code = code_type(0, code.co_nlocals, code.co_stacksize,
|
||||||
code.co_flags, code.co_code, code.co_consts,
|
code.co_flags, code.co_code, code.co_consts,
|
||||||
code.co_names, code.co_varnames, filename,
|
code.co_names, code.co_varnames, filename,
|
||||||
location, code.co_firstlineno,
|
location, code.co_firstlineno,
|
||||||
code.co_lnotab, (), ())
|
code.co_lnotab, (), ())
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
@ -29,6 +29,7 @@ KEEP_TRAILING_NEWLINE = False
|
|||||||
|
|
||||||
# default filters, tests and namespace
|
# default filters, tests and namespace
|
||||||
from jinja2.filters import FILTERS as DEFAULT_FILTERS
|
from jinja2.filters import FILTERS as DEFAULT_FILTERS
|
||||||
|
from jinja2.tests import TESTS as DEFAULT_TESTS
|
||||||
DEFAULT_NAMESPACE = {
|
DEFAULT_NAMESPACE = {
|
||||||
'range': range_type,
|
'range': range_type,
|
||||||
'dict': lambda **kw: kw,
|
'dict': lambda **kw: kw,
|
@ -15,7 +15,7 @@ from jinja2.defaults import BLOCK_START_STRING, \
|
|||||||
BLOCK_END_STRING, VARIABLE_START_STRING, VARIABLE_END_STRING, \
|
BLOCK_END_STRING, VARIABLE_START_STRING, VARIABLE_END_STRING, \
|
||||||
COMMENT_START_STRING, COMMENT_END_STRING, LINE_STATEMENT_PREFIX, \
|
COMMENT_START_STRING, COMMENT_END_STRING, LINE_STATEMENT_PREFIX, \
|
||||||
LINE_COMMENT_PREFIX, TRIM_BLOCKS, NEWLINE_SEQUENCE, \
|
LINE_COMMENT_PREFIX, TRIM_BLOCKS, NEWLINE_SEQUENCE, \
|
||||||
DEFAULT_FILTERS, DEFAULT_NAMESPACE, \
|
DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE, \
|
||||||
KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS
|
KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS
|
||||||
from jinja2.lexer import get_lexer, TokenStream
|
from jinja2.lexer import get_lexer, TokenStream
|
||||||
from jinja2.parser import Parser
|
from jinja2.parser import Parser
|
||||||
@ -290,6 +290,7 @@ class Environment(object):
|
|||||||
|
|
||||||
# defaults
|
# defaults
|
||||||
self.filters = DEFAULT_FILTERS.copy()
|
self.filters = DEFAULT_FILTERS.copy()
|
||||||
|
self.tests = DEFAULT_TESTS.copy()
|
||||||
self.globals = DEFAULT_NAMESPACE.copy()
|
self.globals = DEFAULT_NAMESPACE.copy()
|
||||||
|
|
||||||
# set the loader provided
|
# set the loader provided
|
||||||
@ -410,7 +411,7 @@ class Environment(object):
|
|||||||
func = self.filters.get(name)
|
func = self.filters.get(name)
|
||||||
if func is None:
|
if func is None:
|
||||||
raise TemplateRuntimeError('no filter named %r' % name)
|
raise TemplateRuntimeError('no filter named %r' % name)
|
||||||
args = list(args or ())
|
args = [value] + list(args or ())
|
||||||
if getattr(func, 'contextfilter', False):
|
if getattr(func, 'contextfilter', False):
|
||||||
if context is None:
|
if context is None:
|
||||||
raise TemplateRuntimeError('Attempted to invoke context '
|
raise TemplateRuntimeError('Attempted to invoke context '
|
||||||
@ -425,7 +426,7 @@ class Environment(object):
|
|||||||
args.insert(0, eval_ctx)
|
args.insert(0, eval_ctx)
|
||||||
elif getattr(func, 'environmentfilter', False):
|
elif getattr(func, 'environmentfilter', False):
|
||||||
args.insert(0, self)
|
args.insert(0, self)
|
||||||
return func(value, *args, **(kwargs or {}))
|
return func(*args, **(kwargs or {}))
|
||||||
|
|
||||||
def call_test(self, name, value, args=None, kwargs=None):
|
def call_test(self, name, value, args=None, kwargs=None):
|
||||||
"""Invokes a test on a value the same way the compiler does it.
|
"""Invokes a test on a value the same way the compiler does it.
|
636
3rdparty/jinja2/ext.py
vendored
Normal file
636
3rdparty/jinja2/ext.py
vendored
Normal file
@ -0,0 +1,636 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
jinja2.ext
|
||||||
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
Jinja extensions allow to add custom tags similar to the way django custom
|
||||||
|
tags work. By default two example extensions exist: an i18n and a cache
|
||||||
|
extension.
|
||||||
|
|
||||||
|
:copyright: (c) 2010 by the Jinja Team.
|
||||||
|
:license: BSD.
|
||||||
|
"""
|
||||||
|
from jinja2 import nodes
|
||||||
|
from jinja2.defaults import BLOCK_START_STRING, \
|
||||||
|
BLOCK_END_STRING, VARIABLE_START_STRING, VARIABLE_END_STRING, \
|
||||||
|
COMMENT_START_STRING, COMMENT_END_STRING, LINE_STATEMENT_PREFIX, \
|
||||||
|
LINE_COMMENT_PREFIX, TRIM_BLOCKS, NEWLINE_SEQUENCE, \
|
||||||
|
KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS
|
||||||
|
from jinja2.environment import Environment
|
||||||
|
from jinja2.runtime import concat
|
||||||
|
from jinja2.exceptions import TemplateAssertionError, TemplateSyntaxError
|
||||||
|
from jinja2.utils import contextfunction, import_string, Markup
|
||||||
|
from jinja2._compat import next, with_metaclass, string_types, iteritems
|
||||||
|
|
||||||
|
|
||||||
|
# the only real useful gettext functions for a Jinja template. Note
|
||||||
|
# that ugettext must be assigned to gettext as Jinja doesn't support
|
||||||
|
# non unicode strings.
|
||||||
|
GETTEXT_FUNCTIONS = ('_', 'gettext', 'ngettext')
|
||||||
|
|
||||||
|
|
||||||
|
class ExtensionRegistry(type):
|
||||||
|
"""Gives the extension an unique identifier."""
|
||||||
|
|
||||||
|
def __new__(cls, name, bases, d):
|
||||||
|
rv = type.__new__(cls, name, bases, d)
|
||||||
|
rv.identifier = rv.__module__ + '.' + rv.__name__
|
||||||
|
return rv
|
||||||
|
|
||||||
|
|
||||||
|
class Extension(with_metaclass(ExtensionRegistry, object)):
|
||||||
|
"""Extensions can be used to add extra functionality to the Jinja template
|
||||||
|
system at the parser level. Custom extensions are bound to an environment
|
||||||
|
but may not store environment specific data on `self`. The reason for
|
||||||
|
this is that an extension can be bound to another environment (for
|
||||||
|
overlays) by creating a copy and reassigning the `environment` attribute.
|
||||||
|
|
||||||
|
As extensions are created by the environment they cannot accept any
|
||||||
|
arguments for configuration. One may want to work around that by using
|
||||||
|
a factory function, but that is not possible as extensions are identified
|
||||||
|
by their import name. The correct way to configure the extension is
|
||||||
|
storing the configuration values on the environment. Because this way the
|
||||||
|
environment ends up acting as central configuration storage the
|
||||||
|
attributes may clash which is why extensions have to ensure that the names
|
||||||
|
they choose for configuration are not too generic. ``prefix`` for example
|
||||||
|
is a terrible name, ``fragment_cache_prefix`` on the other hand is a good
|
||||||
|
name as includes the name of the extension (fragment cache).
|
||||||
|
"""
|
||||||
|
|
||||||
|
#: if this extension parses this is the list of tags it's listening to.
|
||||||
|
tags = set()
|
||||||
|
|
||||||
|
#: the priority of that extension. This is especially useful for
|
||||||
|
#: extensions that preprocess values. A lower value means higher
|
||||||
|
#: priority.
|
||||||
|
#:
|
||||||
|
#: .. versionadded:: 2.4
|
||||||
|
priority = 100
|
||||||
|
|
||||||
|
def __init__(self, environment):
|
||||||
|
self.environment = environment
|
||||||
|
|
||||||
|
def bind(self, environment):
|
||||||
|
"""Create a copy of this extension bound to another environment."""
|
||||||
|
rv = object.__new__(self.__class__)
|
||||||
|
rv.__dict__.update(self.__dict__)
|
||||||
|
rv.environment = environment
|
||||||
|
return rv
|
||||||
|
|
||||||
|
def preprocess(self, source, name, filename=None):
|
||||||
|
"""This method is called before the actual lexing and can be used to
|
||||||
|
preprocess the source. The `filename` is optional. The return value
|
||||||
|
must be the preprocessed source.
|
||||||
|
"""
|
||||||
|
return source
|
||||||
|
|
||||||
|
def filter_stream(self, stream):
|
||||||
|
"""It's passed a :class:`~jinja2.lexer.TokenStream` that can be used
|
||||||
|
to filter tokens returned. This method has to return an iterable of
|
||||||
|
:class:`~jinja2.lexer.Token`\s, but it doesn't have to return a
|
||||||
|
:class:`~jinja2.lexer.TokenStream`.
|
||||||
|
|
||||||
|
In the `ext` folder of the Jinja2 source distribution there is a file
|
||||||
|
called `inlinegettext.py` which implements a filter that utilizes this
|
||||||
|
method.
|
||||||
|
"""
|
||||||
|
return stream
|
||||||
|
|
||||||
|
def parse(self, parser):
|
||||||
|
"""If any of the :attr:`tags` matched this method is called with the
|
||||||
|
parser as first argument. The token the parser stream is pointing at
|
||||||
|
is the name token that matched. This method has to return one or a
|
||||||
|
list of multiple nodes.
|
||||||
|
"""
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
def attr(self, name, lineno=None):
|
||||||
|
"""Return an attribute node for the current extension. This is useful
|
||||||
|
to pass constants on extensions to generated template code.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
self.attr('_my_attribute', lineno=lineno)
|
||||||
|
"""
|
||||||
|
return nodes.ExtensionAttribute(self.identifier, name, lineno=lineno)
|
||||||
|
|
||||||
|
def call_method(self, name, args=None, kwargs=None, dyn_args=None,
|
||||||
|
dyn_kwargs=None, lineno=None):
|
||||||
|
"""Call a method of the extension. This is a shortcut for
|
||||||
|
:meth:`attr` + :class:`jinja2.nodes.Call`.
|
||||||
|
"""
|
||||||
|
if args is None:
|
||||||
|
args = []
|
||||||
|
if kwargs is None:
|
||||||
|
kwargs = []
|
||||||
|
return nodes.Call(self.attr(name, lineno=lineno), args, kwargs,
|
||||||
|
dyn_args, dyn_kwargs, lineno=lineno)
|
||||||
|
|
||||||
|
|
||||||
|
@contextfunction
|
||||||
|
def _gettext_alias(__context, *args, **kwargs):
|
||||||
|
return __context.call(__context.resolve('gettext'), *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def _make_new_gettext(func):
|
||||||
|
@contextfunction
|
||||||
|
def gettext(__context, __string, **variables):
|
||||||
|
rv = __context.call(func, __string)
|
||||||
|
if __context.eval_ctx.autoescape:
|
||||||
|
rv = Markup(rv)
|
||||||
|
return rv % variables
|
||||||
|
return gettext
|
||||||
|
|
||||||
|
|
||||||
|
def _make_new_ngettext(func):
|
||||||
|
@contextfunction
|
||||||
|
def ngettext(__context, __singular, __plural, __num, **variables):
|
||||||
|
variables.setdefault('num', __num)
|
||||||
|
rv = __context.call(func, __singular, __plural, __num)
|
||||||
|
if __context.eval_ctx.autoescape:
|
||||||
|
rv = Markup(rv)
|
||||||
|
return rv % variables
|
||||||
|
return ngettext
|
||||||
|
|
||||||
|
|
||||||
|
class InternationalizationExtension(Extension):
|
||||||
|
"""This extension adds gettext support to Jinja2."""
|
||||||
|
tags = set(['trans'])
|
||||||
|
|
||||||
|
# TODO: the i18n extension is currently reevaluating values in a few
|
||||||
|
# situations. Take this example:
|
||||||
|
# {% trans count=something() %}{{ count }} foo{% pluralize
|
||||||
|
# %}{{ count }} fooss{% endtrans %}
|
||||||
|
# something is called twice here. One time for the gettext value and
|
||||||
|
# the other time for the n-parameter of the ngettext function.
|
||||||
|
|
||||||
|
def __init__(self, environment):
|
||||||
|
Extension.__init__(self, environment)
|
||||||
|
environment.globals['_'] = _gettext_alias
|
||||||
|
environment.extend(
|
||||||
|
install_gettext_translations=self._install,
|
||||||
|
install_null_translations=self._install_null,
|
||||||
|
install_gettext_callables=self._install_callables,
|
||||||
|
uninstall_gettext_translations=self._uninstall,
|
||||||
|
extract_translations=self._extract,
|
||||||
|
newstyle_gettext=False
|
||||||
|
)
|
||||||
|
|
||||||
|
def _install(self, translations, newstyle=None):
|
||||||
|
gettext = getattr(translations, 'ugettext', None)
|
||||||
|
if gettext is None:
|
||||||
|
gettext = translations.gettext
|
||||||
|
ngettext = getattr(translations, 'ungettext', None)
|
||||||
|
if ngettext is None:
|
||||||
|
ngettext = translations.ngettext
|
||||||
|
self._install_callables(gettext, ngettext, newstyle)
|
||||||
|
|
||||||
|
def _install_null(self, newstyle=None):
|
||||||
|
self._install_callables(
|
||||||
|
lambda x: x,
|
||||||
|
lambda s, p, n: (n != 1 and (p,) or (s,))[0],
|
||||||
|
newstyle
|
||||||
|
)
|
||||||
|
|
||||||
|
def _install_callables(self, gettext, ngettext, newstyle=None):
|
||||||
|
if newstyle is not None:
|
||||||
|
self.environment.newstyle_gettext = newstyle
|
||||||
|
if self.environment.newstyle_gettext:
|
||||||
|
gettext = _make_new_gettext(gettext)
|
||||||
|
ngettext = _make_new_ngettext(ngettext)
|
||||||
|
self.environment.globals.update(
|
||||||
|
gettext=gettext,
|
||||||
|
ngettext=ngettext
|
||||||
|
)
|
||||||
|
|
||||||
|
def _uninstall(self, translations):
|
||||||
|
for key in 'gettext', 'ngettext':
|
||||||
|
self.environment.globals.pop(key, None)
|
||||||
|
|
||||||
|
def _extract(self, source, gettext_functions=GETTEXT_FUNCTIONS):
|
||||||
|
if isinstance(source, string_types):
|
||||||
|
source = self.environment.parse(source)
|
||||||
|
return extract_from_ast(source, gettext_functions)
|
||||||
|
|
||||||
|
def parse(self, parser):
|
||||||
|
"""Parse a translatable tag."""
|
||||||
|
lineno = next(parser.stream).lineno
|
||||||
|
num_called_num = False
|
||||||
|
|
||||||
|
# find all the variables referenced. Additionally a variable can be
|
||||||
|
# defined in the body of the trans block too, but this is checked at
|
||||||
|
# a later state.
|
||||||
|
plural_expr = None
|
||||||
|
plural_expr_assignment = None
|
||||||
|
variables = {}
|
||||||
|
while parser.stream.current.type != 'block_end':
|
||||||
|
if variables:
|
||||||
|
parser.stream.expect('comma')
|
||||||
|
|
||||||
|
# skip colon for python compatibility
|
||||||
|
if parser.stream.skip_if('colon'):
|
||||||
|
break
|
||||||
|
|
||||||
|
name = parser.stream.expect('name')
|
||||||
|
if name.value in variables:
|
||||||
|
parser.fail('translatable variable %r defined twice.' %
|
||||||
|
name.value, name.lineno,
|
||||||
|
exc=TemplateAssertionError)
|
||||||
|
|
||||||
|
# expressions
|
||||||
|
if parser.stream.current.type == 'assign':
|
||||||
|
next(parser.stream)
|
||||||
|
variables[name.value] = var = parser.parse_expression()
|
||||||
|
else:
|
||||||
|
variables[name.value] = var = nodes.Name(name.value, 'load')
|
||||||
|
|
||||||
|
if plural_expr is None:
|
||||||
|
if isinstance(var, nodes.Call):
|
||||||
|
plural_expr = nodes.Name('_trans', 'load')
|
||||||
|
variables[name.value] = plural_expr
|
||||||
|
plural_expr_assignment = nodes.Assign(
|
||||||
|
nodes.Name('_trans', 'store'), var)
|
||||||
|
else:
|
||||||
|
plural_expr = var
|
||||||
|
num_called_num = name.value == 'num'
|
||||||
|
|
||||||
|
parser.stream.expect('block_end')
|
||||||
|
|
||||||
|
plural = plural_names = None
|
||||||
|
have_plural = False
|
||||||
|
referenced = set()
|
||||||
|
|
||||||
|
# now parse until endtrans or pluralize
|
||||||
|
singular_names, singular = self._parse_block(parser, True)
|
||||||
|
if singular_names:
|
||||||
|
referenced.update(singular_names)
|
||||||
|
if plural_expr is None:
|
||||||
|
plural_expr = nodes.Name(singular_names[0], 'load')
|
||||||
|
num_called_num = singular_names[0] == 'num'
|
||||||
|
|
||||||
|
# if we have a pluralize block, we parse that too
|
||||||
|
if parser.stream.current.test('name:pluralize'):
|
||||||
|
have_plural = True
|
||||||
|
next(parser.stream)
|
||||||
|
if parser.stream.current.type != 'block_end':
|
||||||
|
name = parser.stream.expect('name')
|
||||||
|
if name.value not in variables:
|
||||||
|
parser.fail('unknown variable %r for pluralization' %
|
||||||
|
name.value, name.lineno,
|
||||||
|
exc=TemplateAssertionError)
|
||||||
|
plural_expr = variables[name.value]
|
||||||
|
num_called_num = name.value == 'num'
|
||||||
|
parser.stream.expect('block_end')
|
||||||
|
plural_names, plural = self._parse_block(parser, False)
|
||||||
|
next(parser.stream)
|
||||||
|
referenced.update(plural_names)
|
||||||
|
else:
|
||||||
|
next(parser.stream)
|
||||||
|
|
||||||
|
# register free names as simple name expressions
|
||||||
|
for var in referenced:
|
||||||
|
if var not in variables:
|
||||||
|
variables[var] = nodes.Name(var, 'load')
|
||||||
|
|
||||||
|
if not have_plural:
|
||||||
|
plural_expr = None
|
||||||
|
elif plural_expr is None:
|
||||||
|
parser.fail('pluralize without variables', lineno)
|
||||||
|
|
||||||
|
node = self._make_node(singular, plural, variables, plural_expr,
|
||||||
|
bool(referenced),
|
||||||
|
num_called_num and have_plural)
|
||||||
|
node.set_lineno(lineno)
|
||||||
|
if plural_expr_assignment is not None:
|
||||||
|
return [plural_expr_assignment, node]
|
||||||
|
else:
|
||||||
|
return node
|
||||||
|
|
||||||
|
def _parse_block(self, parser, allow_pluralize):
|
||||||
|
"""Parse until the next block tag with a given name."""
|
||||||
|
referenced = []
|
||||||
|
buf = []
|
||||||
|
while 1:
|
||||||
|
if parser.stream.current.type == 'data':
|
||||||
|
buf.append(parser.stream.current.value.replace('%', '%%'))
|
||||||
|
next(parser.stream)
|
||||||
|
elif parser.stream.current.type == 'variable_begin':
|
||||||
|
next(parser.stream)
|
||||||
|
name = parser.stream.expect('name').value
|
||||||
|
referenced.append(name)
|
||||||
|
buf.append('%%(%s)s' % name)
|
||||||
|
parser.stream.expect('variable_end')
|
||||||
|
elif parser.stream.current.type == 'block_begin':
|
||||||
|
next(parser.stream)
|
||||||
|
if parser.stream.current.test('name:endtrans'):
|
||||||
|
break
|
||||||
|
elif parser.stream.current.test('name:pluralize'):
|
||||||
|
if allow_pluralize:
|
||||||
|
break
|
||||||
|
parser.fail('a translatable section can have only one '
|
||||||
|
'pluralize section')
|
||||||
|
parser.fail('control structures in translatable sections are '
|
||||||
|
'not allowed')
|
||||||
|
elif parser.stream.eos:
|
||||||
|
parser.fail('unclosed translation block')
|
||||||
|
else:
|
||||||
|
assert False, 'internal parser error'
|
||||||
|
|
||||||
|
return referenced, concat(buf)
|
||||||
|
|
||||||
|
def _make_node(self, singular, plural, variables, plural_expr,
|
||||||
|
vars_referenced, num_called_num):
|
||||||
|
"""Generates a useful node from the data provided."""
|
||||||
|
# no variables referenced? no need to escape for old style
|
||||||
|
# gettext invocations only if there are vars.
|
||||||
|
if not vars_referenced and not self.environment.newstyle_gettext:
|
||||||
|
singular = singular.replace('%%', '%')
|
||||||
|
if plural:
|
||||||
|
plural = plural.replace('%%', '%')
|
||||||
|
|
||||||
|
# singular only:
|
||||||
|
if plural_expr is None:
|
||||||
|
gettext = nodes.Name('gettext', 'load')
|
||||||
|
node = nodes.Call(gettext, [nodes.Const(singular)],
|
||||||
|
[], None, None)
|
||||||
|
|
||||||
|
# singular and plural
|
||||||
|
else:
|
||||||
|
ngettext = nodes.Name('ngettext', 'load')
|
||||||
|
node = nodes.Call(ngettext, [
|
||||||
|
nodes.Const(singular),
|
||||||
|
nodes.Const(plural),
|
||||||
|
plural_expr
|
||||||
|
], [], None, None)
|
||||||
|
|
||||||
|
# in case newstyle gettext is used, the method is powerful
|
||||||
|
# enough to handle the variable expansion and autoescape
|
||||||
|
# handling itself
|
||||||
|
if self.environment.newstyle_gettext:
|
||||||
|
for key, value in iteritems(variables):
|
||||||
|
# the function adds that later anyways in case num was
|
||||||
|
# called num, so just skip it.
|
||||||
|
if num_called_num and key == 'num':
|
||||||
|
continue
|
||||||
|
node.kwargs.append(nodes.Keyword(key, value))
|
||||||
|
|
||||||
|
# otherwise do that here
|
||||||
|
else:
|
||||||
|
# mark the return value as safe if we are in an
|
||||||
|
# environment with autoescaping turned on
|
||||||
|
node = nodes.MarkSafeIfAutoescape(node)
|
||||||
|
if variables:
|
||||||
|
node = nodes.Mod(node, nodes.Dict([
|
||||||
|
nodes.Pair(nodes.Const(key), value)
|
||||||
|
for key, value in variables.items()
|
||||||
|
]))
|
||||||
|
return nodes.Output([node])
|
||||||
|
|
||||||
|
|
||||||
|
class ExprStmtExtension(Extension):
|
||||||
|
"""Adds a `do` tag to Jinja2 that works like the print statement just
|
||||||
|
that it doesn't print the return value.
|
||||||
|
"""
|
||||||
|
tags = set(['do'])
|
||||||
|
|
||||||
|
def parse(self, parser):
|
||||||
|
node = nodes.ExprStmt(lineno=next(parser.stream).lineno)
|
||||||
|
node.node = parser.parse_tuple()
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
class LoopControlExtension(Extension):
|
||||||
|
"""Adds break and continue to the template engine."""
|
||||||
|
tags = set(['break', 'continue'])
|
||||||
|
|
||||||
|
def parse(self, parser):
|
||||||
|
token = next(parser.stream)
|
||||||
|
if token.value == 'break':
|
||||||
|
return nodes.Break(lineno=token.lineno)
|
||||||
|
return nodes.Continue(lineno=token.lineno)
|
||||||
|
|
||||||
|
|
||||||
|
class WithExtension(Extension):
|
||||||
|
"""Adds support for a django-like with block."""
|
||||||
|
tags = set(['with'])
|
||||||
|
|
||||||
|
def parse(self, parser):
|
||||||
|
node = nodes.Scope(lineno=next(parser.stream).lineno)
|
||||||
|
assignments = []
|
||||||
|
while parser.stream.current.type != 'block_end':
|
||||||
|
lineno = parser.stream.current.lineno
|
||||||
|
if assignments:
|
||||||
|
parser.stream.expect('comma')
|
||||||
|
target = parser.parse_assign_target()
|
||||||
|
parser.stream.expect('assign')
|
||||||
|
expr = parser.parse_expression()
|
||||||
|
assignments.append(nodes.Assign(target, expr, lineno=lineno))
|
||||||
|
node.body = assignments + \
|
||||||
|
list(parser.parse_statements(('name:endwith',),
|
||||||
|
drop_needle=True))
|
||||||
|
return node
|
||||||
|
|
||||||
|
|
||||||
|
class AutoEscapeExtension(Extension):
|
||||||
|
"""Changes auto escape rules for a scope."""
|
||||||
|
tags = set(['autoescape'])
|
||||||
|
|
||||||
|
def parse(self, parser):
|
||||||
|
node = nodes.ScopedEvalContextModifier(lineno=next(parser.stream).lineno)
|
||||||
|
node.options = [
|
||||||
|
nodes.Keyword('autoescape', parser.parse_expression())
|
||||||
|
]
|
||||||
|
node.body = parser.parse_statements(('name:endautoescape',),
|
||||||
|
drop_needle=True)
|
||||||
|
return nodes.Scope([node])
|
||||||
|
|
||||||
|
|
||||||
|
def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS,
|
||||||
|
babel_style=True):
|
||||||
|
"""Extract localizable strings from the given template node. Per
|
||||||
|
default this function returns matches in babel style that means non string
|
||||||
|
parameters as well as keyword arguments are returned as `None`. This
|
||||||
|
allows Babel to figure out what you really meant if you are using
|
||||||
|
gettext functions that allow keyword arguments for placeholder expansion.
|
||||||
|
If you don't want that behavior set the `babel_style` parameter to `False`
|
||||||
|
which causes only strings to be returned and parameters are always stored
|
||||||
|
in tuples. As a consequence invalid gettext calls (calls without a single
|
||||||
|
string parameter or string parameters after non-string parameters) are
|
||||||
|
skipped.
|
||||||
|
|
||||||
|
This example explains the behavior:
|
||||||
|
|
||||||
|
>>> from jinja2 import Environment
|
||||||
|
>>> env = Environment()
|
||||||
|
>>> node = env.parse('{{ (_("foo"), _(), ngettext("foo", "bar", 42)) }}')
|
||||||
|
>>> list(extract_from_ast(node))
|
||||||
|
[(1, '_', 'foo'), (1, '_', ()), (1, 'ngettext', ('foo', 'bar', None))]
|
||||||
|
>>> list(extract_from_ast(node, babel_style=False))
|
||||||
|
[(1, '_', ('foo',)), (1, 'ngettext', ('foo', 'bar'))]
|
||||||
|
|
||||||
|
For every string found this function yields a ``(lineno, function,
|
||||||
|
message)`` tuple, where:
|
||||||
|
|
||||||
|
* ``lineno`` is the number of the line on which the string was found,
|
||||||
|
* ``function`` is the name of the ``gettext`` function used (if the
|
||||||
|
string was extracted from embedded Python code), and
|
||||||
|
* ``message`` is the string itself (a ``unicode`` object, or a tuple
|
||||||
|
of ``unicode`` objects for functions with multiple string arguments).
|
||||||
|
|
||||||
|
This extraction function operates on the AST and is because of that unable
|
||||||
|
to extract any comments. For comment support you have to use the babel
|
||||||
|
extraction interface or extract comments yourself.
|
||||||
|
"""
|
||||||
|
for node in node.find_all(nodes.Call):
|
||||||
|
if not isinstance(node.node, nodes.Name) or \
|
||||||
|
node.node.name not in gettext_functions:
|
||||||
|
continue
|
||||||
|
|
||||||
|
strings = []
|
||||||
|
for arg in node.args:
|
||||||
|
if isinstance(arg, nodes.Const) and \
|
||||||
|
isinstance(arg.value, string_types):
|
||||||
|
strings.append(arg.value)
|
||||||
|
else:
|
||||||
|
strings.append(None)
|
||||||
|
|
||||||
|
for arg in node.kwargs:
|
||||||
|
strings.append(None)
|
||||||
|
if node.dyn_args is not None:
|
||||||
|
strings.append(None)
|
||||||
|
if node.dyn_kwargs is not None:
|
||||||
|
strings.append(None)
|
||||||
|
|
||||||
|
if not babel_style:
|
||||||
|
strings = tuple(x for x in strings if x is not None)
|
||||||
|
if not strings:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
if len(strings) == 1:
|
||||||
|
strings = strings[0]
|
||||||
|
else:
|
||||||
|
strings = tuple(strings)
|
||||||
|
yield node.lineno, node.node.name, strings
|
||||||
|
|
||||||
|
|
||||||
|
class _CommentFinder(object):
|
||||||
|
"""Helper class to find comments in a token stream. Can only
|
||||||
|
find comments for gettext calls forwards. Once the comment
|
||||||
|
from line 4 is found, a comment for line 1 will not return a
|
||||||
|
usable value.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, tokens, comment_tags):
|
||||||
|
self.tokens = tokens
|
||||||
|
self.comment_tags = comment_tags
|
||||||
|
self.offset = 0
|
||||||
|
self.last_lineno = 0
|
||||||
|
|
||||||
|
def find_backwards(self, offset):
|
||||||
|
try:
|
||||||
|
for _, token_type, token_value in \
|
||||||
|
reversed(self.tokens[self.offset:offset]):
|
||||||
|
if token_type in ('comment', 'linecomment'):
|
||||||
|
try:
|
||||||
|
prefix, comment = token_value.split(None, 1)
|
||||||
|
except ValueError:
|
||||||
|
continue
|
||||||
|
if prefix in self.comment_tags:
|
||||||
|
return [comment.rstrip()]
|
||||||
|
return []
|
||||||
|
finally:
|
||||||
|
self.offset = offset
|
||||||
|
|
||||||
|
def find_comments(self, lineno):
|
||||||
|
if not self.comment_tags or self.last_lineno > lineno:
|
||||||
|
return []
|
||||||
|
for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset:]):
|
||||||
|
if token_lineno > lineno:
|
||||||
|
return self.find_backwards(self.offset + idx)
|
||||||
|
return self.find_backwards(len(self.tokens))
|
||||||
|
|
||||||
|
|
||||||
|
def babel_extract(fileobj, keywords, comment_tags, options):
|
||||||
|
"""Babel extraction method for Jinja templates.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.3
|
||||||
|
Basic support for translation comments was added. If `comment_tags`
|
||||||
|
is now set to a list of keywords for extraction, the extractor will
|
||||||
|
try to find the best preceeding comment that begins with one of the
|
||||||
|
keywords. For best results, make sure to not have more than one
|
||||||
|
gettext call in one line of code and the matching comment in the
|
||||||
|
same line or the line before.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.5.1
|
||||||
|
The `newstyle_gettext` flag can be set to `True` to enable newstyle
|
||||||
|
gettext calls.
|
||||||
|
|
||||||
|
.. versionchanged:: 2.7
|
||||||
|
A `silent` option can now be provided. If set to `False` template
|
||||||
|
syntax errors are propagated instead of being ignored.
|
||||||
|
|
||||||
|
:param fileobj: the file-like object the messages should be extracted from
|
||||||
|
:param keywords: a list of keywords (i.e. function names) that should be
|
||||||
|
recognized as translation functions
|
||||||
|
:param comment_tags: a list of translator tags to search for and include
|
||||||
|
in the results.
|
||||||
|
:param options: a dictionary of additional options (optional)
|
||||||
|
:return: an iterator over ``(lineno, funcname, message, comments)`` tuples.
|
||||||
|
(comments will be empty currently)
|
||||||
|
"""
|
||||||
|
extensions = set()
|
||||||
|
for extension in options.get('extensions', '').split(','):
|
||||||
|
extension = extension.strip()
|
||||||
|
if not extension:
|
||||||
|
continue
|
||||||
|
extensions.add(import_string(extension))
|
||||||
|
if InternationalizationExtension not in extensions:
|
||||||
|
extensions.add(InternationalizationExtension)
|
||||||
|
|
||||||
|
def getbool(options, key, default=False):
|
||||||
|
return options.get(key, str(default)).lower() in \
|
||||||
|
('1', 'on', 'yes', 'true')
|
||||||
|
|
||||||
|
silent = getbool(options, 'silent', True)
|
||||||
|
environment = Environment(
|
||||||
|
options.get('block_start_string', BLOCK_START_STRING),
|
||||||
|
options.get('block_end_string', BLOCK_END_STRING),
|
||||||
|
options.get('variable_start_string', VARIABLE_START_STRING),
|
||||||
|
options.get('variable_end_string', VARIABLE_END_STRING),
|
||||||
|
options.get('comment_start_string', COMMENT_START_STRING),
|
||||||
|
options.get('comment_end_string', COMMENT_END_STRING),
|
||||||
|
options.get('line_statement_prefix') or LINE_STATEMENT_PREFIX,
|
||||||
|
options.get('line_comment_prefix') or LINE_COMMENT_PREFIX,
|
||||||
|
getbool(options, 'trim_blocks', TRIM_BLOCKS),
|
||||||
|
getbool(options, 'lstrip_blocks', LSTRIP_BLOCKS),
|
||||||
|
NEWLINE_SEQUENCE,
|
||||||
|
getbool(options, 'keep_trailing_newline', KEEP_TRAILING_NEWLINE),
|
||||||
|
frozenset(extensions),
|
||||||
|
cache_size=0,
|
||||||
|
auto_reload=False
|
||||||
|
)
|
||||||
|
|
||||||
|
if getbool(options, 'newstyle_gettext'):
|
||||||
|
environment.newstyle_gettext = True
|
||||||
|
|
||||||
|
source = fileobj.read().decode(options.get('encoding', 'utf-8'))
|
||||||
|
try:
|
||||||
|
node = environment.parse(source)
|
||||||
|
tokens = list(environment.lex(environment.preprocess(source)))
|
||||||
|
except TemplateSyntaxError as e:
|
||||||
|
if not silent:
|
||||||
|
raise
|
||||||
|
# skip templates with syntax errors
|
||||||
|
return
|
||||||
|
|
||||||
|
finder = _CommentFinder(tokens, comment_tags)
|
||||||
|
for lineno, func, message in extract_from_ast(node, keywords):
|
||||||
|
yield lineno, func, message, finder.find_comments(lineno)
|
||||||
|
|
||||||
|
|
||||||
|
#: nicer import names
|
||||||
|
i18n = InternationalizationExtension
|
||||||
|
do = ExprStmtExtension
|
||||||
|
loopcontrols = LoopControlExtension
|
||||||
|
with_ = WithExtension
|
||||||
|
autoescape = AutoEscapeExtension
|
@ -18,7 +18,7 @@ from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \
|
|||||||
unicode_urlencode
|
unicode_urlencode
|
||||||
from jinja2.runtime import Undefined
|
from jinja2.runtime import Undefined
|
||||||
from jinja2.exceptions import FilterArgumentError
|
from jinja2.exceptions import FilterArgumentError
|
||||||
from jinja2._compat import imap, string_types, text_type, iteritems
|
from jinja2._compat import next, imap, string_types, text_type, iteritems
|
||||||
|
|
||||||
|
|
||||||
_word_re = re.compile(r'\w+(?u)')
|
_word_re = re.compile(r'\w+(?u)')
|
||||||
@ -183,10 +183,10 @@ def do_title(s):
|
|||||||
uppercase letters, all remaining characters are lowercase.
|
uppercase letters, all remaining characters are lowercase.
|
||||||
"""
|
"""
|
||||||
rv = []
|
rv = []
|
||||||
for item in re.compile(r'([-\s]+)(?u)').split(soft_unicode(s)):
|
for item in re.compile(r'([-\s]+)(?u)').split(s):
|
||||||
if not item:
|
if not item:
|
||||||
continue
|
continue
|
||||||
rv.append(item[0].upper() + item[1:])
|
rv.append(item[0].upper() + item[1:].lower())
|
||||||
return ''.join(rv)
|
return ''.join(rv)
|
||||||
|
|
||||||
|
|
||||||
@ -842,15 +842,14 @@ def do_map(*args, **kwargs):
|
|||||||
|
|
||||||
@contextfilter
|
@contextfilter
|
||||||
def do_select(*args, **kwargs):
|
def do_select(*args, **kwargs):
|
||||||
"""Filters a sequence of objects by appying a test to the object and only
|
"""Filters a sequence of objects by appying a test to either the object
|
||||||
selecting the ones with the test succeeding.
|
or the attribute and only selecting the ones with the test succeeding.
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
|
|
||||||
.. sourcecode:: jinja
|
.. sourcecode:: jinja
|
||||||
|
|
||||||
{{ numbers|select("odd") }}
|
{{ numbers|select("odd") }}
|
||||||
{{ numbers|select("odd") }}
|
|
||||||
|
|
||||||
.. versionadded:: 2.7
|
.. versionadded:: 2.7
|
||||||
"""
|
"""
|
||||||
@ -859,8 +858,8 @@ def do_select(*args, **kwargs):
|
|||||||
|
|
||||||
@contextfilter
|
@contextfilter
|
||||||
def do_reject(*args, **kwargs):
|
def do_reject(*args, **kwargs):
|
||||||
"""Filters a sequence of objects by appying a test to the object and
|
"""Filters a sequence of objects by appying a test to either the object
|
||||||
rejecting the ones with the test succeeding.
|
or the attribute and rejecting the ones with the test succeeding.
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
|
|
||||||
@ -875,8 +874,8 @@ def do_reject(*args, **kwargs):
|
|||||||
|
|
||||||
@contextfilter
|
@contextfilter
|
||||||
def do_selectattr(*args, **kwargs):
|
def do_selectattr(*args, **kwargs):
|
||||||
"""Filters a sequence of objects by appying a test to an attribute of an
|
"""Filters a sequence of objects by appying a test to either the object
|
||||||
object and only selecting the ones with the test succeeding.
|
or the attribute and only selecting the ones with the test succeeding.
|
||||||
|
|
||||||
Example usage:
|
Example usage:
|
||||||
|
|
||||||
@ -892,8 +891,8 @@ def do_selectattr(*args, **kwargs):
|
|||||||
|
|
||||||
@contextfilter
|
@contextfilter
|
||||||
def do_rejectattr(*args, **kwargs):
|
def do_rejectattr(*args, **kwargs):
|
||||||
"""Filters a sequence of objects by appying a test to an attribute of an
|
"""Filters a sequence of objects by appying a test to either the object
|
||||||
object or the attribute and rejecting the ones with the test succeeding.
|
or the attribute and rejecting the ones with the test succeeding.
|
||||||
|
|
||||||
.. sourcecode:: jinja
|
.. sourcecode:: jinja
|
||||||
|
|
@ -20,7 +20,7 @@ from operator import itemgetter
|
|||||||
from collections import deque
|
from collections import deque
|
||||||
from jinja2.exceptions import TemplateSyntaxError
|
from jinja2.exceptions import TemplateSyntaxError
|
||||||
from jinja2.utils import LRUCache
|
from jinja2.utils import LRUCache
|
||||||
from jinja2._compat import iteritems, implements_iterator, text_type, \
|
from jinja2._compat import next, iteritems, implements_iterator, text_type, \
|
||||||
intern
|
intern
|
||||||
|
|
||||||
|
|
@ -192,6 +192,71 @@ class FileSystemLoader(BaseLoader):
|
|||||||
return sorted(found)
|
return sorted(found)
|
||||||
|
|
||||||
|
|
||||||
|
class PackageLoader(BaseLoader):
|
||||||
|
"""Load templates from python eggs or packages. It is constructed with
|
||||||
|
the name of the python package and the path to the templates in that
|
||||||
|
package::
|
||||||
|
|
||||||
|
loader = PackageLoader('mypackage', 'views')
|
||||||
|
|
||||||
|
If the package path is not given, ``'templates'`` is assumed.
|
||||||
|
|
||||||
|
Per default the template encoding is ``'utf-8'`` which can be changed
|
||||||
|
by setting the `encoding` parameter to something else. Due to the nature
|
||||||
|
of eggs it's only possible to reload templates if the package was loaded
|
||||||
|
from the file system and not a zip file.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, package_name, package_path='templates',
|
||||||
|
encoding='utf-8'):
|
||||||
|
from pkg_resources import DefaultProvider, ResourceManager, \
|
||||||
|
get_provider
|
||||||
|
provider = get_provider(package_name)
|
||||||
|
self.encoding = encoding
|
||||||
|
self.manager = ResourceManager()
|
||||||
|
self.filesystem_bound = isinstance(provider, DefaultProvider)
|
||||||
|
self.provider = provider
|
||||||
|
self.package_path = package_path
|
||||||
|
|
||||||
|
def get_source(self, environment, template):
|
||||||
|
pieces = split_template_path(template)
|
||||||
|
p = '/'.join((self.package_path,) + tuple(pieces))
|
||||||
|
if not self.provider.has_resource(p):
|
||||||
|
raise TemplateNotFound(template)
|
||||||
|
|
||||||
|
filename = uptodate = None
|
||||||
|
if self.filesystem_bound:
|
||||||
|
filename = self.provider.get_resource_filename(self.manager, p)
|
||||||
|
mtime = path.getmtime(filename)
|
||||||
|
def uptodate():
|
||||||
|
try:
|
||||||
|
return path.getmtime(filename) == mtime
|
||||||
|
except OSError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
source = self.provider.get_resource_string(self.manager, p)
|
||||||
|
return source.decode(self.encoding), filename, uptodate
|
||||||
|
|
||||||
|
def list_templates(self):
|
||||||
|
path = self.package_path
|
||||||
|
if path[:2] == './':
|
||||||
|
path = path[2:]
|
||||||
|
elif path == '.':
|
||||||
|
path = ''
|
||||||
|
offset = len(path)
|
||||||
|
results = []
|
||||||
|
def _walk(path):
|
||||||
|
for filename in self.provider.resource_listdir(path):
|
||||||
|
fullname = path + '/' + filename
|
||||||
|
if self.provider.resource_isdir(fullname):
|
||||||
|
_walk(fullname)
|
||||||
|
else:
|
||||||
|
results.append(fullname[offset:].lstrip('/'))
|
||||||
|
_walk(path)
|
||||||
|
results.sort()
|
||||||
|
return results
|
||||||
|
|
||||||
|
|
||||||
class DictLoader(BaseLoader):
|
class DictLoader(BaseLoader):
|
||||||
"""Loads a template from a python dict. It's passed a dict of unicode
|
"""Loads a template from a python dict. It's passed a dict of unicode
|
||||||
strings bound to template names. This loader is useful for unittesting:
|
strings bound to template names. This loader is useful for unittesting:
|
@ -41,7 +41,7 @@ class Markup(text_type):
|
|||||||
>>> class Foo(object):
|
>>> class Foo(object):
|
||||||
... def __html__(self):
|
... def __html__(self):
|
||||||
... return '<a href="#">foo</a>'
|
... return '<a href="#">foo</a>'
|
||||||
...
|
...
|
||||||
>>> Markup(Foo())
|
>>> Markup(Foo())
|
||||||
Markup(u'<a href="#">foo</a>')
|
Markup(u'<a href="#">foo</a>')
|
||||||
|
|
103
3rdparty/jinja2/meta.py
vendored
Normal file
103
3rdparty/jinja2/meta.py
vendored
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
jinja2.meta
|
||||||
|
~~~~~~~~~~~
|
||||||
|
|
||||||
|
This module implements various functions that exposes information about
|
||||||
|
templates that might be interesting for various kinds of applications.
|
||||||
|
|
||||||
|
:copyright: (c) 2010 by the Jinja Team, see AUTHORS for more details.
|
||||||
|
:license: BSD, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
from jinja2 import nodes
|
||||||
|
from jinja2.compiler import CodeGenerator
|
||||||
|
from jinja2._compat import string_types
|
||||||
|
|
||||||
|
|
||||||
|
class TrackingCodeGenerator(CodeGenerator):
|
||||||
|
"""We abuse the code generator for introspection."""
|
||||||
|
|
||||||
|
def __init__(self, environment):
|
||||||
|
CodeGenerator.__init__(self, environment, '<introspection>',
|
||||||
|
'<introspection>')
|
||||||
|
self.undeclared_identifiers = set()
|
||||||
|
|
||||||
|
def write(self, x):
|
||||||
|
"""Don't write."""
|
||||||
|
|
||||||
|
def pull_locals(self, frame):
|
||||||
|
"""Remember all undeclared identifiers."""
|
||||||
|
self.undeclared_identifiers.update(frame.identifiers.undeclared)
|
||||||
|
|
||||||
|
|
||||||
|
def find_undeclared_variables(ast):
|
||||||
|
"""Returns a set of all variables in the AST that will be looked up from
|
||||||
|
the context at runtime. Because at compile time it's not known which
|
||||||
|
variables will be used depending on the path the execution takes at
|
||||||
|
runtime, all variables are returned.
|
||||||
|
|
||||||
|
>>> from jinja2 import Environment, meta
|
||||||
|
>>> env = Environment()
|
||||||
|
>>> ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')
|
||||||
|
>>> meta.find_undeclared_variables(ast)
|
||||||
|
set(['bar'])
|
||||||
|
|
||||||
|
.. admonition:: Implementation
|
||||||
|
|
||||||
|
Internally the code generator is used for finding undeclared variables.
|
||||||
|
This is good to know because the code generator might raise a
|
||||||
|
:exc:`TemplateAssertionError` during compilation and as a matter of
|
||||||
|
fact this function can currently raise that exception as well.
|
||||||
|
"""
|
||||||
|
codegen = TrackingCodeGenerator(ast.environment)
|
||||||
|
codegen.visit(ast)
|
||||||
|
return codegen.undeclared_identifiers
|
||||||
|
|
||||||
|
|
||||||
|
def find_referenced_templates(ast):
|
||||||
|
"""Finds all the referenced templates from the AST. This will return an
|
||||||
|
iterator over all the hardcoded template extensions, inclusions and
|
||||||
|
imports. If dynamic inheritance or inclusion is used, `None` will be
|
||||||
|
yielded.
|
||||||
|
|
||||||
|
>>> from jinja2 import Environment, meta
|
||||||
|
>>> env = Environment()
|
||||||
|
>>> ast = env.parse('{% extends "layout.html" %}{% include helper %}')
|
||||||
|
>>> list(meta.find_referenced_templates(ast))
|
||||||
|
['layout.html', None]
|
||||||
|
|
||||||
|
This function is useful for dependency tracking. For example if you want
|
||||||
|
to rebuild parts of the website after a layout template has changed.
|
||||||
|
"""
|
||||||
|
for node in ast.find_all((nodes.Extends, nodes.FromImport, nodes.Import,
|
||||||
|
nodes.Include)):
|
||||||
|
if not isinstance(node.template, nodes.Const):
|
||||||
|
# a tuple with some non consts in there
|
||||||
|
if isinstance(node.template, (nodes.Tuple, nodes.List)):
|
||||||
|
for template_name in node.template.items:
|
||||||
|
# something const, only yield the strings and ignore
|
||||||
|
# non-string consts that really just make no sense
|
||||||
|
if isinstance(template_name, nodes.Const):
|
||||||
|
if isinstance(template_name.value, string_types):
|
||||||
|
yield template_name.value
|
||||||
|
# something dynamic in there
|
||||||
|
else:
|
||||||
|
yield None
|
||||||
|
# something dynamic we don't know about here
|
||||||
|
else:
|
||||||
|
yield None
|
||||||
|
continue
|
||||||
|
# constant is a basestring, direct template name
|
||||||
|
if isinstance(node.template.value, string_types):
|
||||||
|
yield node.template.value
|
||||||
|
# a tuple or list (latter *should* not happen) made of consts,
|
||||||
|
# yield the consts that are strings. We could warn here for
|
||||||
|
# non string values
|
||||||
|
elif isinstance(node, nodes.Include) and \
|
||||||
|
isinstance(node.template.value, (tuple, list)):
|
||||||
|
for template_name in node.template.value:
|
||||||
|
if isinstance(template_name, string_types):
|
||||||
|
yield template_name
|
||||||
|
# something else we don't care about, we could warn here
|
||||||
|
else:
|
||||||
|
yield None
|
@ -12,16 +12,16 @@
|
|||||||
:copyright: (c) 2010 by the Jinja Team.
|
:copyright: (c) 2010 by the Jinja Team.
|
||||||
:license: BSD, see LICENSE for more details.
|
:license: BSD, see LICENSE for more details.
|
||||||
"""
|
"""
|
||||||
import types
|
|
||||||
import operator
|
import operator
|
||||||
|
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from jinja2.utils import Markup
|
from jinja2.utils import Markup
|
||||||
from jinja2._compat import izip, with_metaclass, text_type
|
from jinja2._compat import next, izip, with_metaclass, text_type, \
|
||||||
|
method_type, function_type
|
||||||
|
|
||||||
|
|
||||||
#: the types we support for context functions
|
#: the types we support for context functions
|
||||||
_context_function_types = (types.FunctionType, types.MethodType)
|
_context_function_types = (function_type, method_type)
|
||||||
|
|
||||||
|
|
||||||
_binop_to_func = {
|
_binop_to_func = {
|
||||||
@ -232,6 +232,9 @@ class Node(with_metaclass(NodeType, object)):
|
|||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not self.__eq__(other)
|
return not self.__eq__(other)
|
||||||
|
|
||||||
|
# Restore Python 2 hashing behavior on Python 3
|
||||||
|
__hash__ = object.__hash__
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '%s(%s)' % (
|
return '%s(%s)' % (
|
||||||
self.__class__.__name__,
|
self.__class__.__name__,
|
@ -11,10 +11,10 @@
|
|||||||
from jinja2 import nodes
|
from jinja2 import nodes
|
||||||
from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError
|
from jinja2.exceptions import TemplateSyntaxError, TemplateAssertionError
|
||||||
from jinja2.lexer import describe_token, describe_token_expr
|
from jinja2.lexer import describe_token, describe_token_expr
|
||||||
from jinja2._compat import imap
|
from jinja2._compat import next, imap
|
||||||
|
|
||||||
|
|
||||||
#: statements that callinto
|
#: statements that callinto
|
||||||
_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
|
_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
|
||||||
'macro', 'include', 'from', 'import',
|
'macro', 'include', 'from', 'import',
|
||||||
'set'])
|
'set'])
|
@ -14,7 +14,7 @@ from jinja2.utils import Markup, soft_unicode, escape, missing, concat, \
|
|||||||
internalcode, object_type_repr
|
internalcode, object_type_repr
|
||||||
from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
|
from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \
|
||||||
TemplateNotFound
|
TemplateNotFound
|
||||||
from jinja2._compat import imap, text_type, iteritems, \
|
from jinja2._compat import next, imap, text_type, iteritems, \
|
||||||
implements_iterator, implements_to_string, string_types, PY2
|
implements_iterator, implements_to_string, string_types, PY2
|
||||||
|
|
||||||
|
|
||||||
@ -497,6 +497,15 @@ class Undefined(object):
|
|||||||
__float__ = __complex__ = __pow__ = __rpow__ = \
|
__float__ = __complex__ = __pow__ = __rpow__ = \
|
||||||
_fail_with_undefined_error
|
_fail_with_undefined_error
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
return type(self) is type(other)
|
||||||
|
|
||||||
|
def __ne__(self, other):
|
||||||
|
return not self.__eq__(other)
|
||||||
|
|
||||||
|
def __hash__(self):
|
||||||
|
return id(type(self))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return u''
|
return u''
|
||||||
|
|
||||||
@ -563,7 +572,8 @@ class StrictUndefined(Undefined):
|
|||||||
"""
|
"""
|
||||||
__slots__ = ()
|
__slots__ = ()
|
||||||
__iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \
|
__iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \
|
||||||
__ne__ = __bool__ = Undefined._fail_with_undefined_error
|
__ne__ = __bool__ = __hash__ = \
|
||||||
|
Undefined._fail_with_undefined_error
|
||||||
|
|
||||||
|
|
||||||
# remove remaining slots attributes, after the metaclass did the magic they
|
# remove remaining slots attributes, after the metaclass did the magic they
|
368
3rdparty/jinja2/sandbox.py
vendored
Normal file
368
3rdparty/jinja2/sandbox.py
vendored
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
jinja2.sandbox
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Adds a sandbox layer to Jinja as it was the default behavior in the old
|
||||||
|
Jinja 1 releases. This sandbox is slightly different from Jinja 1 as the
|
||||||
|
default behavior is easier to use.
|
||||||
|
|
||||||
|
The behavior can be changed by subclassing the environment.
|
||||||
|
|
||||||
|
:copyright: (c) 2010 by the Jinja Team.
|
||||||
|
:license: BSD.
|
||||||
|
"""
|
||||||
|
import operator
|
||||||
|
from jinja2.environment import Environment
|
||||||
|
from jinja2.exceptions import SecurityError
|
||||||
|
from jinja2._compat import string_types, function_type, method_type, \
|
||||||
|
traceback_type, code_type, frame_type, generator_type, PY2
|
||||||
|
|
||||||
|
|
||||||
|
#: maximum number of items a range may produce
|
||||||
|
MAX_RANGE = 100000
|
||||||
|
|
||||||
|
#: attributes of function objects that are considered unsafe.
|
||||||
|
UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
|
||||||
|
'func_defaults', 'func_globals'])
|
||||||
|
|
||||||
|
#: unsafe method attributes. function attributes are unsafe for methods too
|
||||||
|
UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
|
||||||
|
|
||||||
|
#: unsafe generator attirbutes.
|
||||||
|
UNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code'])
|
||||||
|
|
||||||
|
# On versions > python 2 the special attributes on functions are gone,
|
||||||
|
# but they remain on methods and generators for whatever reason.
|
||||||
|
if not PY2:
|
||||||
|
UNSAFE_FUNCTION_ATTRIBUTES = set()
|
||||||
|
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
# make sure we don't warn in python 2.6 about stuff we don't care about
|
||||||
|
warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
|
||||||
|
module='jinja2.sandbox')
|
||||||
|
|
||||||
|
from collections import deque
|
||||||
|
|
||||||
|
_mutable_set_types = (set,)
|
||||||
|
_mutable_mapping_types = (dict,)
|
||||||
|
_mutable_sequence_types = (list,)
|
||||||
|
|
||||||
|
|
||||||
|
# on python 2.x we can register the user collection types
|
||||||
|
try:
|
||||||
|
from UserDict import UserDict, DictMixin
|
||||||
|
from UserList import UserList
|
||||||
|
_mutable_mapping_types += (UserDict, DictMixin)
|
||||||
|
_mutable_set_types += (UserList,)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# if sets is still available, register the mutable set from there as well
|
||||||
|
try:
|
||||||
|
from sets import Set
|
||||||
|
_mutable_set_types += (Set,)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
#: register Python 2.6 abstract base classes
|
||||||
|
try:
|
||||||
|
from collections import MutableSet, MutableMapping, MutableSequence
|
||||||
|
_mutable_set_types += (MutableSet,)
|
||||||
|
_mutable_mapping_types += (MutableMapping,)
|
||||||
|
_mutable_sequence_types += (MutableSequence,)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
_mutable_spec = (
|
||||||
|
(_mutable_set_types, frozenset([
|
||||||
|
'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
|
||||||
|
'symmetric_difference_update', 'update'
|
||||||
|
])),
|
||||||
|
(_mutable_mapping_types, frozenset([
|
||||||
|
'clear', 'pop', 'popitem', 'setdefault', 'update'
|
||||||
|
])),
|
||||||
|
(_mutable_sequence_types, frozenset([
|
||||||
|
'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
|
||||||
|
])),
|
||||||
|
(deque, frozenset([
|
||||||
|
'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
|
||||||
|
'popleft', 'remove', 'rotate'
|
||||||
|
]))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def safe_range(*args):
|
||||||
|
"""A range that can't generate ranges with a length of more than
|
||||||
|
MAX_RANGE items.
|
||||||
|
"""
|
||||||
|
rng = range(*args)
|
||||||
|
if len(rng) > MAX_RANGE:
|
||||||
|
raise OverflowError('range too big, maximum size for range is %d' %
|
||||||
|
MAX_RANGE)
|
||||||
|
return rng
|
||||||
|
|
||||||
|
|
||||||
|
def unsafe(f):
|
||||||
|
"""Marks a function or method as unsafe.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
@unsafe
|
||||||
|
def delete(self):
|
||||||
|
pass
|
||||||
|
"""
|
||||||
|
f.unsafe_callable = True
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
|
def is_internal_attribute(obj, attr):
|
||||||
|
"""Test if the attribute given is an internal python attribute. For
|
||||||
|
example this function returns `True` for the `func_code` attribute of
|
||||||
|
python objects. This is useful if the environment method
|
||||||
|
:meth:`~SandboxedEnvironment.is_safe_attribute` is overridden.
|
||||||
|
|
||||||
|
>>> from jinja2.sandbox import is_internal_attribute
|
||||||
|
>>> is_internal_attribute(lambda: None, "func_code")
|
||||||
|
True
|
||||||
|
>>> is_internal_attribute((lambda x:x).func_code, 'co_code')
|
||||||
|
True
|
||||||
|
>>> is_internal_attribute(str, "upper")
|
||||||
|
False
|
||||||
|
"""
|
||||||
|
if isinstance(obj, function_type):
|
||||||
|
if attr in UNSAFE_FUNCTION_ATTRIBUTES:
|
||||||
|
return True
|
||||||
|
elif isinstance(obj, method_type):
|
||||||
|
if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
|
||||||
|
attr in UNSAFE_METHOD_ATTRIBUTES:
|
||||||
|
return True
|
||||||
|
elif isinstance(obj, type):
|
||||||
|
if attr == 'mro':
|
||||||
|
return True
|
||||||
|
elif isinstance(obj, (code_type, traceback_type, frame_type)):
|
||||||
|
return True
|
||||||
|
elif isinstance(obj, generator_type):
|
||||||
|
if attr in UNSAFE_GENERATOR_ATTRIBUTES:
|
||||||
|
return True
|
||||||
|
return attr.startswith('__')
|
||||||
|
|
||||||
|
|
||||||
|
def modifies_known_mutable(obj, attr):
|
||||||
|
"""This function checks if an attribute on a builtin mutable object
|
||||||
|
(list, dict, set or deque) would modify it if called. It also supports
|
||||||
|
the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
|
||||||
|
with Python 2.6 onwards the abstract base classes `MutableSet`,
|
||||||
|
`MutableMapping`, and `MutableSequence`.
|
||||||
|
|
||||||
|
>>> modifies_known_mutable({}, "clear")
|
||||||
|
True
|
||||||
|
>>> modifies_known_mutable({}, "keys")
|
||||||
|
False
|
||||||
|
>>> modifies_known_mutable([], "append")
|
||||||
|
True
|
||||||
|
>>> modifies_known_mutable([], "index")
|
||||||
|
False
|
||||||
|
|
||||||
|
If called with an unsupported object (such as unicode) `False` is
|
||||||
|
returned.
|
||||||
|
|
||||||
|
>>> modifies_known_mutable("foo", "upper")
|
||||||
|
False
|
||||||
|
"""
|
||||||
|
for typespec, unsafe in _mutable_spec:
|
||||||
|
if isinstance(obj, typespec):
|
||||||
|
return attr in unsafe
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class SandboxedEnvironment(Environment):
|
||||||
|
"""The sandboxed environment. It works like the regular environment but
|
||||||
|
tells the compiler to generate sandboxed code. Additionally subclasses of
|
||||||
|
this environment may override the methods that tell the runtime what
|
||||||
|
attributes or functions are safe to access.
|
||||||
|
|
||||||
|
If the template tries to access insecure code a :exc:`SecurityError` is
|
||||||
|
raised. However also other exceptions may occour during the rendering so
|
||||||
|
the caller has to ensure that all exceptions are catched.
|
||||||
|
"""
|
||||||
|
sandboxed = True
|
||||||
|
|
||||||
|
#: default callback table for the binary operators. A copy of this is
|
||||||
|
#: available on each instance of a sandboxed environment as
|
||||||
|
#: :attr:`binop_table`
|
||||||
|
default_binop_table = {
|
||||||
|
'+': operator.add,
|
||||||
|
'-': operator.sub,
|
||||||
|
'*': operator.mul,
|
||||||
|
'/': operator.truediv,
|
||||||
|
'//': operator.floordiv,
|
||||||
|
'**': operator.pow,
|
||||||
|
'%': operator.mod
|
||||||
|
}
|
||||||
|
|
||||||
|
#: default callback table for the unary operators. A copy of this is
|
||||||
|
#: available on each instance of a sandboxed environment as
|
||||||
|
#: :attr:`unop_table`
|
||||||
|
default_unop_table = {
|
||||||
|
'+': operator.pos,
|
||||||
|
'-': operator.neg
|
||||||
|
}
|
||||||
|
|
||||||
|
#: a set of binary operators that should be intercepted. Each operator
|
||||||
|
#: that is added to this set (empty by default) is delegated to the
|
||||||
|
#: :meth:`call_binop` method that will perform the operator. The default
|
||||||
|
#: operator callback is specified by :attr:`binop_table`.
|
||||||
|
#:
|
||||||
|
#: The following binary operators are interceptable:
|
||||||
|
#: ``//``, ``%``, ``+``, ``*``, ``-``, ``/``, and ``**``
|
||||||
|
#:
|
||||||
|
#: The default operation form the operator table corresponds to the
|
||||||
|
#: builtin function. Intercepted calls are always slower than the native
|
||||||
|
#: operator call, so make sure only to intercept the ones you are
|
||||||
|
#: interested in.
|
||||||
|
#:
|
||||||
|
#: .. versionadded:: 2.6
|
||||||
|
intercepted_binops = frozenset()
|
||||||
|
|
||||||
|
#: a set of unary operators that should be intercepted. Each operator
|
||||||
|
#: that is added to this set (empty by default) is delegated to the
|
||||||
|
#: :meth:`call_unop` method that will perform the operator. The default
|
||||||
|
#: operator callback is specified by :attr:`unop_table`.
|
||||||
|
#:
|
||||||
|
#: The following unary operators are interceptable: ``+``, ``-``
|
||||||
|
#:
|
||||||
|
#: The default operation form the operator table corresponds to the
|
||||||
|
#: builtin function. Intercepted calls are always slower than the native
|
||||||
|
#: operator call, so make sure only to intercept the ones you are
|
||||||
|
#: interested in.
|
||||||
|
#:
|
||||||
|
#: .. versionadded:: 2.6
|
||||||
|
intercepted_unops = frozenset()
|
||||||
|
|
||||||
|
def intercept_unop(self, operator):
|
||||||
|
"""Called during template compilation with the name of a unary
|
||||||
|
operator to check if it should be intercepted at runtime. If this
|
||||||
|
method returns `True`, :meth:`call_unop` is excuted for this unary
|
||||||
|
operator. The default implementation of :meth:`call_unop` will use
|
||||||
|
the :attr:`unop_table` dictionary to perform the operator with the
|
||||||
|
same logic as the builtin one.
|
||||||
|
|
||||||
|
The following unary operators are interceptable: ``+`` and ``-``
|
||||||
|
|
||||||
|
Intercepted calls are always slower than the native operator call,
|
||||||
|
so make sure only to intercept the ones you are interested in.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
Environment.__init__(self, *args, **kwargs)
|
||||||
|
self.globals['range'] = safe_range
|
||||||
|
self.binop_table = self.default_binop_table.copy()
|
||||||
|
self.unop_table = self.default_unop_table.copy()
|
||||||
|
|
||||||
|
def is_safe_attribute(self, obj, attr, value):
|
||||||
|
"""The sandboxed environment will call this method to check if the
|
||||||
|
attribute of an object is safe to access. Per default all attributes
|
||||||
|
starting with an underscore are considered private as well as the
|
||||||
|
special attributes of internal python objects as returned by the
|
||||||
|
:func:`is_internal_attribute` function.
|
||||||
|
"""
|
||||||
|
return not (attr.startswith('_') or is_internal_attribute(obj, attr))
|
||||||
|
|
||||||
|
def is_safe_callable(self, obj):
|
||||||
|
"""Check if an object is safely callable. Per default a function is
|
||||||
|
considered safe unless the `unsafe_callable` attribute exists and is
|
||||||
|
True. Override this method to alter the behavior, but this won't
|
||||||
|
affect the `unsafe` decorator from this module.
|
||||||
|
"""
|
||||||
|
return not (getattr(obj, 'unsafe_callable', False) or
|
||||||
|
getattr(obj, 'alters_data', False))
|
||||||
|
|
||||||
|
def call_binop(self, context, operator, left, right):
|
||||||
|
"""For intercepted binary operator calls (:meth:`intercepted_binops`)
|
||||||
|
this function is executed instead of the builtin operator. This can
|
||||||
|
be used to fine tune the behavior of certain operators.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6
|
||||||
|
"""
|
||||||
|
return self.binop_table[operator](left, right)
|
||||||
|
|
||||||
|
def call_unop(self, context, operator, arg):
|
||||||
|
"""For intercepted unary operator calls (:meth:`intercepted_unops`)
|
||||||
|
this function is executed instead of the builtin operator. This can
|
||||||
|
be used to fine tune the behavior of certain operators.
|
||||||
|
|
||||||
|
.. versionadded:: 2.6
|
||||||
|
"""
|
||||||
|
return self.unop_table[operator](arg)
|
||||||
|
|
||||||
|
def getitem(self, obj, argument):
|
||||||
|
"""Subscribe an object from sandboxed code."""
|
||||||
|
try:
|
||||||
|
return obj[argument]
|
||||||
|
except (TypeError, LookupError):
|
||||||
|
if isinstance(argument, string_types):
|
||||||
|
try:
|
||||||
|
attr = str(argument)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
value = getattr(obj, attr)
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if self.is_safe_attribute(obj, argument, value):
|
||||||
|
return value
|
||||||
|
return self.unsafe_undefined(obj, argument)
|
||||||
|
return self.undefined(obj=obj, name=argument)
|
||||||
|
|
||||||
|
def getattr(self, obj, attribute):
|
||||||
|
"""Subscribe an object from sandboxed code and prefer the
|
||||||
|
attribute. The attribute passed *must* be a bytestring.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
value = getattr(obj, attribute)
|
||||||
|
except AttributeError:
|
||||||
|
try:
|
||||||
|
return obj[attribute]
|
||||||
|
except (TypeError, LookupError):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if self.is_safe_attribute(obj, attribute, value):
|
||||||
|
return value
|
||||||
|
return self.unsafe_undefined(obj, attribute)
|
||||||
|
return self.undefined(obj=obj, name=attribute)
|
||||||
|
|
||||||
|
def unsafe_undefined(self, obj, attribute):
|
||||||
|
"""Return an undefined object for unsafe attributes."""
|
||||||
|
return self.undefined('access to attribute %r of %r '
|
||||||
|
'object is unsafe.' % (
|
||||||
|
attribute,
|
||||||
|
obj.__class__.__name__
|
||||||
|
), name=attribute, obj=obj, exc=SecurityError)
|
||||||
|
|
||||||
|
def call(__self, __context, __obj, *args, **kwargs):
|
||||||
|
"""Call an object from sandboxed code."""
|
||||||
|
# the double prefixes are to avoid double keyword argument
|
||||||
|
# errors when proxying the call.
|
||||||
|
if not __self.is_safe_callable(__obj):
|
||||||
|
raise SecurityError('%r is not safely callable' % (__obj,))
|
||||||
|
return __context.call(__obj, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class ImmutableSandboxedEnvironment(SandboxedEnvironment):
|
||||||
|
"""Works exactly like the regular `SandboxedEnvironment` but does not
|
||||||
|
permit modifications on the builtin mutable objects `list`, `set`, and
|
||||||
|
`dict` by using the :func:`modifies_known_mutable` function.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def is_safe_attribute(self, obj, attr, value):
|
||||||
|
if not SandboxedEnvironment.is_safe_attribute(self, obj, attr, value):
|
||||||
|
return False
|
||||||
|
return not modifies_known_mutable(obj, attr)
|
149
3rdparty/jinja2/tests.py
vendored
Normal file
149
3rdparty/jinja2/tests.py
vendored
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
jinja2.tests
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Jinja test functions. Used with the "is" operator.
|
||||||
|
|
||||||
|
:copyright: (c) 2010 by the Jinja Team.
|
||||||
|
:license: BSD, see LICENSE for more details.
|
||||||
|
"""
|
||||||
|
import re
|
||||||
|
from jinja2.runtime import Undefined
|
||||||
|
from jinja2._compat import text_type, string_types, mapping_types
|
||||||
|
|
||||||
|
|
||||||
|
number_re = re.compile(r'^-?\d+(\.\d+)?$')
|
||||||
|
regex_type = type(number_re)
|
||||||
|
|
||||||
|
|
||||||
|
test_callable = callable
|
||||||
|
|
||||||
|
|
||||||
|
def test_odd(value):
|
||||||
|
"""Return true if the variable is odd."""
|
||||||
|
return value % 2 == 1
|
||||||
|
|
||||||
|
|
||||||
|
def test_even(value):
|
||||||
|
"""Return true if the variable is even."""
|
||||||
|
return value % 2 == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_divisibleby(value, num):
|
||||||
|
"""Check if a variable is divisible by a number."""
|
||||||
|
return value % num == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_defined(value):
|
||||||
|
"""Return true if the variable is defined:
|
||||||
|
|
||||||
|
.. sourcecode:: jinja
|
||||||
|
|
||||||
|
{% if variable is defined %}
|
||||||
|
value of variable: {{ variable }}
|
||||||
|
{% else %}
|
||||||
|
variable is not defined
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
See the :func:`default` filter for a simple way to set undefined
|
||||||
|
variables.
|
||||||
|
"""
|
||||||
|
return not isinstance(value, Undefined)
|
||||||
|
|
||||||
|
|
||||||
|
def test_undefined(value):
|
||||||
|
"""Like :func:`defined` but the other way round."""
|
||||||
|
return isinstance(value, Undefined)
|
||||||
|
|
||||||
|
|
||||||
|
def test_none(value):
|
||||||
|
"""Return true if the variable is none."""
|
||||||
|
return value is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_lower(value):
|
||||||
|
"""Return true if the variable is lowercased."""
|
||||||
|
return text_type(value).islower()
|
||||||
|
|
||||||
|
|
||||||
|
def test_upper(value):
|
||||||
|
"""Return true if the variable is uppercased."""
|
||||||
|
return text_type(value).isupper()
|
||||||
|
|
||||||
|
|
||||||
|
def test_string(value):
|
||||||
|
"""Return true if the object is a string."""
|
||||||
|
return isinstance(value, string_types)
|
||||||
|
|
||||||
|
|
||||||
|
def test_mapping(value):
|
||||||
|
"""Return true if the object is a mapping (dict etc.).
|
||||||
|
|
||||||
|
.. versionadded:: 2.6
|
||||||
|
"""
|
||||||
|
return isinstance(value, mapping_types)
|
||||||
|
|
||||||
|
|
||||||
|
def test_number(value):
|
||||||
|
"""Return true if the variable is a number."""
|
||||||
|
return isinstance(value, (int, float, complex))
|
||||||
|
|
||||||
|
|
||||||
|
def test_sequence(value):
|
||||||
|
"""Return true if the variable is a sequence. Sequences are variables
|
||||||
|
that are iterable.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
len(value)
|
||||||
|
value.__getitem__
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def test_sameas(value, other):
|
||||||
|
"""Check if an object points to the same memory address than another
|
||||||
|
object:
|
||||||
|
|
||||||
|
.. sourcecode:: jinja
|
||||||
|
|
||||||
|
{% if foo.attribute is sameas false %}
|
||||||
|
the foo attribute really is the `False` singleton
|
||||||
|
{% endif %}
|
||||||
|
"""
|
||||||
|
return value is other
|
||||||
|
|
||||||
|
|
||||||
|
def test_iterable(value):
|
||||||
|
"""Check if it's possible to iterate over an object."""
|
||||||
|
try:
|
||||||
|
iter(value)
|
||||||
|
except TypeError:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def test_escaped(value):
|
||||||
|
"""Check if the value is escaped."""
|
||||||
|
return hasattr(value, '__html__')
|
||||||
|
|
||||||
|
|
||||||
|
TESTS = {
|
||||||
|
'odd': test_odd,
|
||||||
|
'even': test_even,
|
||||||
|
'divisibleby': test_divisibleby,
|
||||||
|
'defined': test_defined,
|
||||||
|
'undefined': test_undefined,
|
||||||
|
'none': test_none,
|
||||||
|
'lower': test_lower,
|
||||||
|
'upper': test_upper,
|
||||||
|
'string': test_string,
|
||||||
|
'mapping': test_mapping,
|
||||||
|
'number': test_number,
|
||||||
|
'sequence': test_sequence,
|
||||||
|
'iterable': test_iterable,
|
||||||
|
'callable': test_callable,
|
||||||
|
'sameas': test_sameas,
|
||||||
|
'escaped': test_escaped
|
||||||
|
}
|
@ -11,9 +11,8 @@
|
|||||||
import re
|
import re
|
||||||
import errno
|
import errno
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from threading import Lock
|
|
||||||
from jinja2._compat import text_type, string_types, implements_iterator, \
|
from jinja2._compat import text_type, string_types, implements_iterator, \
|
||||||
url_quote
|
allocate_lock, url_quote
|
||||||
|
|
||||||
|
|
||||||
_word_split_re = re.compile(r'(\s+)')
|
_word_split_re = re.compile(r'(\s+)')
|
||||||
@ -310,7 +309,7 @@ class LRUCache(object):
|
|||||||
self._popleft = self._queue.popleft
|
self._popleft = self._queue.popleft
|
||||||
self._pop = self._queue.pop
|
self._pop = self._queue.pop
|
||||||
self._remove = self._queue.remove
|
self._remove = self._queue.remove
|
||||||
self._wlock = Lock()
|
self._wlock = allocate_lock()
|
||||||
self._append = self._queue.append
|
self._append = self._queue.append
|
||||||
|
|
||||||
def __getstate__(self):
|
def __getstate__(self):
|
@ -125,7 +125,11 @@ endfunction()
|
|||||||
# sets the variable MATLAB_FOUND to TRUE
|
# sets the variable MATLAB_FOUND to TRUE
|
||||||
function(locate_matlab_components MATLAB_ROOT_DIR)
|
function(locate_matlab_components MATLAB_ROOT_DIR)
|
||||||
# get the mex extension
|
# get the mex extension
|
||||||
execute_process(COMMAND ${MATLAB_ROOT_DIR}/bin/mexext OUTPUT_VARIABLE MATLAB_MEXEXT_)
|
if (UNIX)
|
||||||
|
execute_process(COMMAND ${MATLAB_ROOT_DIR}/bin/mexext OUTPUT_VARIABLE MATLAB_MEXEXT_)
|
||||||
|
elseif (WIN32)
|
||||||
|
execute_process(COMMAND ${MATLAB_ROOT_DIR}/bin/mexext.bat OUTPUT_VARIABLE MATLAB_MEXEXT_)
|
||||||
|
endif()
|
||||||
if (NOT MATLAB_MEXEXT_)
|
if (NOT MATLAB_MEXEXT_)
|
||||||
return()
|
return()
|
||||||
endif()
|
endif()
|
||||||
@ -154,7 +158,7 @@ function(locate_matlab_components MATLAB_ROOT_DIR)
|
|||||||
find_path(MATLAB_INCLUDE_DIRS_ mex.h ${MATLAB_ROOT_DIR}/extern/include)
|
find_path(MATLAB_INCLUDE_DIRS_ mex.h ${MATLAB_ROOT_DIR}/extern/include)
|
||||||
|
|
||||||
# get the mex shell script
|
# get the mex shell script
|
||||||
find_program(MATLAB_MEX_SCRIPT_ NAMES mex PATHS ${MATLAB_ROOT_DIR}/bin NO_DEFAULT_PATH)
|
find_program(MATLAB_MEX_SCRIPT_ NAMES mex mex.bat PATHS ${MATLAB_ROOT_DIR}/bin NO_DEFAULT_PATH)
|
||||||
|
|
||||||
# get the Matlab executable
|
# get the Matlab executable
|
||||||
find_program(MATLAB_BIN_ NAMES matlab PATHS ${MATLAB_ROOT_DIR}/bin NO_DEFAULT_PATH)
|
find_program(MATLAB_BIN_ NAMES matlab PATHS ${MATLAB_ROOT_DIR}/bin NO_DEFAULT_PATH)
|
||||||
|
@ -97,7 +97,8 @@ ocv_add_module(matlab BINDINGS
|
|||||||
execute_process(COMMAND git log -1 --pretty=%H OUTPUT_VARIABLE GIT_COMMIT ERROR_QUIET)
|
execute_process(COMMAND git log -1 --pretty=%H OUTPUT_VARIABLE GIT_COMMIT ERROR_QUIET)
|
||||||
string(REGEX REPLACE "(\r?\n)+$" "" GIT_COMMIT "${GIT_COMMIT}")
|
string(REGEX REPLACE "(\r?\n)+$" "" GIT_COMMIT "${GIT_COMMIT}")
|
||||||
|
|
||||||
# set the path to the C++ header and doc parser
|
# set the path to the C++ header and doc parser, and template engine
|
||||||
|
set(JINJA2_PATH ${CMAKE_SOURCE_DIR}/3rdparty)
|
||||||
set(HDR_PARSER_PATH ${CMAKE_SOURCE_DIR}/modules/python/src2)
|
set(HDR_PARSER_PATH ${CMAKE_SOURCE_DIR}/modules/python/src2)
|
||||||
set(RST_PARSER_PATH ${CMAKE_SOURCE_DIR}/modules/java/generator)
|
set(RST_PARSER_PATH ${CMAKE_SOURCE_DIR}/modules/java/generator)
|
||||||
|
|
||||||
@ -149,6 +150,7 @@ if (NOT MEX_WORKS)
|
|||||||
execute_process(
|
execute_process(
|
||||||
COMMAND ${PYTHON_EXECUTABLE}
|
COMMAND ${PYTHON_EXECUTABLE}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab.py
|
${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab.py
|
||||||
|
--jinja2 ${JINJA2_PATH}
|
||||||
--hdrparser ${HDR_PARSER_PATH}
|
--hdrparser ${HDR_PARSER_PATH}
|
||||||
--rstparser ${RST_PARSER_PATH}
|
--rstparser ${RST_PARSER_PATH}
|
||||||
--extra "test=${CMAKE_CURRENT_SOURCE_DIR}/test/test_generator.hpp"
|
--extra "test=${CMAKE_CURRENT_SOURCE_DIR}/test/test_generator.hpp"
|
||||||
@ -208,6 +210,7 @@ add_custom_command(
|
|||||||
OUTPUT ${GENERATE_PROXY}
|
OUTPUT ${GENERATE_PROXY}
|
||||||
COMMAND ${PYTHON_EXECUTABLE}
|
COMMAND ${PYTHON_EXECUTABLE}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab.py
|
${CMAKE_CURRENT_SOURCE_DIR}/generator/gen_matlab.py
|
||||||
|
--jinja2 ${JINJA2_PATH}
|
||||||
--hdrparser ${HDR_PARSER_PATH}
|
--hdrparser ${HDR_PARSER_PATH}
|
||||||
--rstparser ${RST_PARSER_PATH}
|
--rstparser ${RST_PARSER_PATH}
|
||||||
--moduleroot ${CMAKE_SOURCE_DIR}/modules
|
--moduleroot ${CMAKE_SOURCE_DIR}/modules
|
||||||
@ -216,24 +219,26 @@ add_custom_command(
|
|||||||
--outdir ${CMAKE_CURRENT_BINARY_DIR}
|
--outdir ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
COMMAND ${PYTHON_EXECUTABLE}
|
COMMAND ${PYTHON_EXECUTABLE}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/generator/build_info.py
|
${CMAKE_CURRENT_SOURCE_DIR}/generator/build_info.py
|
||||||
--os ${CMAKE_SYSTEM}
|
--jinja2 ${JINJA2_PATH}
|
||||||
--arch ${ARCH} ${CMAKE_SYSTEM_PROCESSOR}
|
--os ${CMAKE_SYSTEM}
|
||||||
--compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}
|
--arch ${ARCH} ${CMAKE_SYSTEM_PROCESSOR}
|
||||||
--mex_arch ${MATLAB_ARCH}
|
--compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}
|
||||||
--mex_script ${MATLAB_MEX_SCRIPT}
|
--mex_arch ${MATLAB_ARCH}
|
||||||
--cxx_flags ${MEX_CXXFLAGS}
|
--mex_script ${MATLAB_MEX_SCRIPT}
|
||||||
|
--cxx_flags ${MEX_CXXFLAGS}
|
||||||
--opencv_version ${OPENCV_VERSION}
|
--opencv_version ${OPENCV_VERSION}
|
||||||
--commit ${GIT_COMMIT}
|
--commit ${GIT_COMMIT}
|
||||||
--modules ${opencv_modules}
|
--modules ${opencv_modules}
|
||||||
--configuration "$(Configuration)" ${CMAKE_BUILD_TYPE}
|
--configuration "$(Configuration)" ${CMAKE_BUILD_TYPE}
|
||||||
--outdir ${CMAKE_CURRENT_BINARY_DIR}
|
--outdir ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
COMMAND ${PYTHON_EXECUTABLE}
|
COMMAND ${PYTHON_EXECUTABLE}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/generator/cvmex.py
|
${CMAKE_CURRENT_SOURCE_DIR}/generator/cvmex.py
|
||||||
|
--jinja2 ${JINJA2_PATH}
|
||||||
--opts="${MEX_OPTS}"
|
--opts="${MEX_OPTS}"
|
||||||
--include_dirs="${MEX_INCLUDE_DIRS}"
|
--include_dirs="${MEX_INCLUDE_DIRS}"
|
||||||
--lib_dir=${MEX_LIB_DIR}
|
--lib_dir=${MEX_LIB_DIR}
|
||||||
--libs="${MEX_LIBS}"
|
--libs="${MEX_LIBS}"
|
||||||
--flags ${MEX_CXXFLAGS}
|
--flags ${MEX_CXXFLAGS}
|
||||||
--outdir ${CMAKE_CURRENT_BINARY_DIR}
|
--outdir ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/test/help.m ${CMAKE_CURRENT_BINARY_DIR}/+cv
|
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/test/help.m ${CMAKE_CURRENT_BINARY_DIR}/+cv
|
||||||
COMMAND ${CMAKE_COMMAND} -E touch ${GENERATE_PROXY}
|
COMMAND ${CMAKE_COMMAND} -E touch ${GENERATE_PROXY}
|
||||||
@ -291,6 +296,7 @@ install(CODE
|
|||||||
"execute_process(
|
"execute_process(
|
||||||
COMMAND ${PYTHON_EXECUTABLE}
|
COMMAND ${PYTHON_EXECUTABLE}
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/generator/cvmex.py
|
${CMAKE_CURRENT_SOURCE_DIR}/generator/cvmex.py
|
||||||
|
--jinja2 ${JINJA2_PATH}
|
||||||
--opts=${MEX_OPTS}
|
--opts=${MEX_OPTS}
|
||||||
--include_dirs=-I${CMAKE_INSTALL_PREFIX}/${OPENCV_INCLUDE_INSTALL_PATH}
|
--include_dirs=-I${CMAKE_INSTALL_PREFIX}/${OPENCV_INCLUDE_INSTALL_PATH}
|
||||||
--lib_dir=-L${CMAKE_INSTALL_PREFIX}/${OPENCV_LIB_INSTALL_PATH}
|
--lib_dir=-L${CMAKE_INSTALL_PREFIX}/${OPENCV_LIB_INSTALL_PATH}
|
||||||
|
@ -49,6 +49,7 @@ if __name__ == "__main__":
|
|||||||
import sys, re, os, time
|
import sys, re, os, time
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
|
parser.add_argument('--jinja2')
|
||||||
parser.add_argument('--os')
|
parser.add_argument('--os')
|
||||||
parser.add_argument('--arch', nargs=2)
|
parser.add_argument('--arch', nargs=2)
|
||||||
parser.add_argument('--compiler', nargs='+')
|
parser.add_argument('--compiler', nargs='+')
|
||||||
@ -63,6 +64,9 @@ if __name__ == "__main__":
|
|||||||
parser.add_argument('--outdir')
|
parser.add_argument('--outdir')
|
||||||
build = parser.parse_args()
|
build = parser.parse_args()
|
||||||
|
|
||||||
|
# add jinja to the path
|
||||||
|
sys.path.append(build.jinja2)
|
||||||
|
|
||||||
from filters import *
|
from filters import *
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ if __name__ == "__main__":
|
|||||||
import sys, re, os, time
|
import sys, re, os, time
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
|
parser.add_argument('--jinja2')
|
||||||
parser.add_argument('--opts')
|
parser.add_argument('--opts')
|
||||||
parser.add_argument('--include_dirs')
|
parser.add_argument('--include_dirs')
|
||||||
parser.add_argument('--lib_dir')
|
parser.add_argument('--lib_dir')
|
||||||
@ -51,6 +52,9 @@ if __name__ == "__main__":
|
|||||||
parser.add_argument('--outdir')
|
parser.add_argument('--outdir')
|
||||||
cv = parser.parse_args()
|
cv = parser.parse_args()
|
||||||
|
|
||||||
|
# add jinja to the path
|
||||||
|
sys.path.append(cv.jinja2)
|
||||||
|
|
||||||
from filters import *
|
from filters import *
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
|
@ -168,6 +168,7 @@ if __name__ == "__main__":
|
|||||||
import sys, re, os, time
|
import sys, re, os, time
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
|
parser.add_argument('--jinja2')
|
||||||
parser.add_argument('--hdrparser')
|
parser.add_argument('--hdrparser')
|
||||||
parser.add_argument('--rstparser')
|
parser.add_argument('--rstparser')
|
||||||
parser.add_argument('--moduleroot', default='', required=False)
|
parser.add_argument('--moduleroot', default='', required=False)
|
||||||
@ -177,6 +178,7 @@ if __name__ == "__main__":
|
|||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# add the hdr_parser and rst_parser modules to the path
|
# add the hdr_parser and rst_parser modules to the path
|
||||||
|
sys.path.append(args.jinja2)
|
||||||
sys.path.append(args.hdrparser)
|
sys.path.append(args.hdrparser)
|
||||||
sys.path.append(args.rstparser)
|
sys.path.append(args.rstparser)
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user