diff options
Diffstat (limited to 'lib/spack/external/jinja2/nodes.py')
-rw-r--r-- | lib/spack/external/jinja2/nodes.py | 94 |
1 files changed, 77 insertions, 17 deletions
diff --git a/lib/spack/external/jinja2/nodes.py b/lib/spack/external/jinja2/nodes.py index aa4df72380..4d9a01ad8b 100644 --- a/lib/spack/external/jinja2/nodes.py +++ b/lib/spack/external/jinja2/nodes.py @@ -314,7 +314,7 @@ class For(Stmt): class If(Stmt): """If `test` is true, `body` is rendered, else `else_`.""" - fields = ('test', 'body', 'else_') + fields = ('test', 'body', 'elif_', 'else_') class Macro(Stmt): @@ -387,7 +387,7 @@ class Assign(Stmt): class AssignBlock(Stmt): """Assigns a block to a target.""" - fields = ('target', 'body') + fields = ('target', 'filter', 'body') class Expr(Node): @@ -465,6 +465,18 @@ class Name(Expr): 'True', 'False', 'None') +class NSRef(Expr): + """Reference to a namespace value assignment""" + fields = ('name', 'attr') + + def can_assign(self): + # We don't need any special checks here; NSRef assignments have a + # runtime check to ensure the target is a namespace object which will + # have been checked already as it is created using a normal assignment + # which goes through a `Name` node. + return True + + class Literal(Expr): """Baseclass for literals.""" abstract = True @@ -587,6 +599,25 @@ class CondExpr(Expr): return self.expr2.as_const(eval_ctx) +def args_as_const(node, eval_ctx): + args = [x.as_const(eval_ctx) for x in node.args] + kwargs = dict(x.as_const(eval_ctx) for x in node.kwargs) + + if node.dyn_args is not None: + try: + args.extend(node.dyn_args.as_const(eval_ctx)) + except Exception: + raise Impossible() + + if node.dyn_kwargs is not None: + try: + kwargs.update(node.dyn_kwargs.as_const(eval_ctx)) + except Exception: + raise Impossible() + + return args, kwargs + + class Filter(Expr): """This node applies a filter on an expression. `name` is the name of the filter, the rest of the fields are the same as for :class:`Call`. @@ -594,44 +625,41 @@ class Filter(Expr): If the `node` of a filter is `None` the contents of the last buffer are filtered. Buffers are created by macros and filter blocks. """ + fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs') def as_const(self, eval_ctx=None): eval_ctx = get_eval_context(self, eval_ctx) + if eval_ctx.volatile or self.node is None: raise Impossible() + # we have to be careful here because we call filter_ below. # if this variable would be called filter, 2to3 would wrap the # call in a list beause it is assuming we are talking about the # builtin filter function here which no longer returns a list in # python 3. because of that, do not rename filter_ to filter! filter_ = self.environment.filters.get(self.name) + if filter_ is None or getattr(filter_, 'contextfilter', False): raise Impossible() # We cannot constant handle async filters, so we need to make sure # to not go down this path. - if eval_ctx.environment.is_async and \ - getattr(filter_, 'asyncfiltervariant', False): + if ( + eval_ctx.environment.is_async + and getattr(filter_, 'asyncfiltervariant', False) + ): raise Impossible() - obj = self.node.as_const(eval_ctx) - args = [obj] + [x.as_const(eval_ctx) for x in self.args] + args, kwargs = args_as_const(self, eval_ctx) + args.insert(0, self.node.as_const(eval_ctx)) + if getattr(filter_, 'evalcontextfilter', False): args.insert(0, eval_ctx) elif getattr(filter_, 'environmentfilter', False): args.insert(0, self.environment) - kwargs = dict(x.as_const(eval_ctx) for x in self.kwargs) - if self.dyn_args is not None: - try: - args.extend(self.dyn_args.as_const(eval_ctx)) - except Exception: - raise Impossible() - if self.dyn_kwargs is not None: - try: - kwargs.update(self.dyn_kwargs.as_const(eval_ctx)) - except Exception: - raise Impossible() + try: return filter_(*args, **kwargs) except Exception: @@ -642,8 +670,24 @@ class Test(Expr): """Applies a test on an expression. `name` is the name of the test, the rest of the fields are the same as for :class:`Call`. """ + fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs') + def as_const(self, eval_ctx=None): + test = self.environment.tests.get(self.name) + + if test is None: + raise Impossible() + + eval_ctx = get_eval_context(self, eval_ctx) + args, kwargs = args_as_const(self, eval_ctx) + args.insert(0, self.node.as_const(eval_ctx)) + + try: + return test(*args, **kwargs) + except Exception: + raise Impossible() + class Call(Expr): """Calls an expression. `args` is a list of arguments, `kwargs` a list @@ -914,6 +958,22 @@ class Scope(Stmt): fields = ('body',) +class OverlayScope(Stmt): + """An overlay scope for extensions. This is a largely unoptimized scope + that however can be used to introduce completely arbitrary variables into + a sub scope from a dictionary or dictionary like object. The `context` + field has to evaluate to a dictionary object. + + Example usage:: + + OverlayScope(context=self.call_method('get_context'), + body=[...]) + + .. versionadded:: 2.10 + """ + fields = ('context', 'body') + + class EvalContextModifier(Stmt): """Modifies the eval context. For each option that should be modified, a :class:`Keyword` has to be added to the :attr:`options` list. |