]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
Don't make cond_expr_undefined configurable 1079/head
authorAdrian Moennich <adrian@planetcoding.net>
Sun, 13 Oct 2019 14:54:00 +0000 (16:54 +0200)
committerAdrian Moennich <adrian@planetcoding.net>
Sun, 13 Oct 2019 14:54:35 +0000 (16:54 +0200)
CHANGES.rst
docs/templates.rst
jinja2/compiler.py
jinja2/environment.py
jinja2/runtime.py
tests/test_api.py

index 1ddb8cabe0774c43142cd92deb9184ada79a6737..536e20c473543edb7babdf78d0ef7b5551e3f54a 100644 (file)
@@ -39,10 +39,11 @@ Unreleased
     :issue:`63`
 -   When providing multiple paths to ``FileSystemLoader``, a template
     can have the same name as a directory. :issue:`821`
--   Make the undefined object returned by ``{{ 'foo' if bar }}`` configurable,
-    and default to standard ``Undefined`` regardless of what is specified as
-    the environment's ``undefined`` object as doing so is not compatible with
-    ``StrictUndefined``. :issue:`710`, :pr:`1079`
+-   Always return a standard :class:`Undefined` when omitting the else clause
+    in a ``{{ 'foo' if bar }}`` expression, regardless of what is specified as
+    the environment's ``undefined`` class, as omitting the else clause is a
+    valid shortcut and not actually an undefined variable that shauld cause
+    an error (in case of :class:`StrictUndefined`). :issue:`710`, :pr:`1079`
 
 
 Version 2.10.3
index 13b693b71ec2426799903c043af3bac6352403e9..af64a5986c769796913817ede7c5a26978548f31 100644 (file)
@@ -1355,8 +1355,8 @@ The general syntax is ``<do something> if <something is true> else <do
 something else>``.
 
 The `else` part is optional.  If not provided, the else block implicitly
-evaluates into an undefined object (using the environment's undefined object
-specified in ``cond_expr_undefined``):
+evaluates into an :class:`Undefined` object (regardless of what ``undefined``
+in the environment is set to):
 
 .. sourcecode:: jinja
 
index 850b26c042fb3a6c027bd731add44cf0b678c2da..b734611bde7a22a844766aafe373d3609e270c21 100644 (file)
@@ -609,7 +609,9 @@ class CodeGenerator(NodeVisitor):
         """
         self.writeline('resolve = context.resolve_or_missing')
         self.writeline('undefined = environment.undefined')
-        self.writeline('cond_expr_undefined = environment.cond_expr_undefined')
+        # always use the standard Undefined class for the implicit else of
+        # conditional expressions
+        self.writeline('cond_expr_undefined = Undefined')
         self.writeline('if 0: yield None')
 
     def push_parameter_definitions(self, frame):
index 477385c9f1b6ec031e2369afbde9fc3fd4f863f9..2687889a3358eb7a9077eb35107d488d2b5f6f5d 100644 (file)
@@ -101,9 +101,6 @@ def _environment_sanity_check(environment):
     """Perform a sanity check on the environment."""
     assert issubclass(environment.undefined, Undefined), 'undefined must ' \
         'be a subclass of undefined because filters depend on it.'
-    assert issubclass(environment.cond_expr_undefined, Undefined), \
-        'cond_expr_undefined must be a subclass of undefined because filters ' \
-        'depend on it.'
     assert environment.block_start_string != \
         environment.variable_start_string != \
         environment.comment_start_string, 'block, variable and comment ' \
@@ -186,13 +183,6 @@ class Environment(object):
             :class:`Undefined` or a subclass of it that is used to represent
             undefined values in the template.
 
-        `cond_expr_undefined`
-            :class:`Undefined` or a subclass of it that is used to represent
-            undefined values in the template for conditional expressions that
-            have no ``else`` part.  This is usually useful when using a more
-            strict undefined class without wanting to break the short version
-            of conditional expressions.
-
         `finalize`
             A callable that can be used to process the result of a variable
             expression before it is output.  For example one can convert
@@ -293,8 +283,7 @@ class Environment(object):
                  cache_size=400,
                  auto_reload=True,
                  bytecode_cache=None,
-                 enable_async=False,
-                 cond_expr_undefined=Undefined):
+                 enable_async=False):
         # !!Important notice!!
         #   The constructor accepts quite a few arguments that should be
         #   passed by keyword rather than position.  However it's important to
@@ -322,7 +311,6 @@ class Environment(object):
 
         # runtime information
         self.undefined = undefined
-        self.cond_expr_undefined = cond_expr_undefined
         self.optimized = optimized
         self.finalize = finalize
         self.autoescape = autoescape
@@ -375,7 +363,7 @@ class Environment(object):
                 extensions=missing, optimized=missing,
                 undefined=missing, finalize=missing, autoescape=missing,
                 loader=missing, cache_size=missing, auto_reload=missing,
-                bytecode_cache=missing, cond_expr_undefined=missing):
+                bytecode_cache=missing):
         """Create a new overlay environment that shares all the data with the
         current environment except for cache and the overridden attributes.
         Extensions cannot be removed for an overlayed environment.  An overlayed
@@ -948,15 +936,14 @@ class Template(object):
                 undefined=Undefined,
                 finalize=None,
                 autoescape=False,
-                enable_async=False,
-                cond_expr_undefined=Undefined):
+                enable_async=False):
         env = get_spontaneous_environment(
             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,
             lstrip_blocks, newline_sequence, keep_trailing_newline,
             frozenset(extensions), optimized, undefined, finalize, autoescape,
-            None, 0, False, None, enable_async, cond_expr_undefined)
+            None, 0, False, None, enable_async)
         return env.from_string(source, template_class=cls)
 
     @classmethod
index ca391bc67f101835151f1fc25b66864c4f739314..cc048cfaadb695e71534188a75744899ea6619b4 100644 (file)
@@ -27,7 +27,7 @@ from jinja2._compat import imap, text_type, iteritems, \
 __all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
            'TemplateRuntimeError', 'missing', 'concat', 'escape',
            'markup_join', 'unicode_join', 'to_string', 'identity',
-           'TemplateNotFound', 'Namespace']
+           'TemplateNotFound', 'Namespace', 'Undefined']
 
 #: the name of the function that is used to convert something into
 #: a string.  We can just use the text type here.
index b29594b3766489e7ed41c79c54c4e351ade96a2f..ec93db2915fb4be595dbf74178748871035a71df 100644 (file)
@@ -367,15 +367,7 @@ class TestUndefined(object):
             .render() == 'default'
         with pytest.raises(AttributeError):
             getattr(StrictUndefined, '__slots__')
-
-    def test_cond_expr_undefined(self):
-        env = Environment(cond_expr_undefined=StrictUndefined)
-        env2 = Environment(undefined=StrictUndefined)
-        pytest.raises(UndefinedError,
-                      env.from_string('{{ "foo" if false }}').render)
-        assert env.from_string('{{ ("foo" if false) is defined }}').render() == 'False'
-        assert env2.from_string('{{ "foo" if false }}').render() == ''
-        assert env2.from_string('{{ ("foo" if false) is defined }}').render() == 'False'
+        assert env.from_string('{{ "foo" if false }}').render() == ''
 
     def test_indexing_gives_undefined(self):
         t = Template("{{ var[42].foo }}")