Search code examples
pythonpython-3.xjinja2pelican

Syntax "if any() / if all() in object" in Jinja


1. Summary

I can’t find, what is the correct syntax in Jinja2 for expressions like if any() in object/if all() in object.

2. MCVE

  • Live demo on Repl.it:

    """Jinja2 if any() in object MCVE."""
    from jinja2 import Template
    
    KIRA_BLOCK = """
    {% if 14 in range(1,5) or 4 in range(1,5) or 7 in range(1,5) %}
        Kira Goddess!
    {% endif %}
    """
    
    print(Template(KIRA_BLOCK).render())
    
    

How can I get the same result without duplicate code?

3. Not helped

  1. I tried searching for the answer to my question and similar examples in Google, GitHub and Jinja documentation

  2. I didn’t understand how can I use Jinja built-in filters to solve my problem

  3. I tried select() filter, as recommended in this answer on Stack Overflow. Like this:

    KIRA_BLOCK = """
    {% if (14,4,7)|select|first in range(1,5) %}
        Kira Goddess!
    {% endif %}
    """
    
  4. I tried to register a custom any() filter, as recommended in the same answer on Stack Overflow. Like this:

    """Jinja2 if any() in object MCVE."""
    from jinja2 import Environment
    from jinja2 import Template
    
    
    environment = Environment()
    
    environment.filters["any"] = any
    
    KIRA_BLOCK = """
    {% if (14,4,7)|any in range(1,5) %}
        Kira Goddess!
    {% endif %}
    """
    
    
    print(Template(KIRA_BLOCK).render())
    
    

4. Real example

For preventing XY problem:

I use similar templates in static site generator Pelican. Example:

{# [INFO] If any of the classes "attention", "caution" or "warning" exists in my article, I add specific styles #}
{% if "class=\"attenion\"" in article.content or if "class=\"caution\"" in article.content or if "class=\"warning\"" in article.content %}
    <link rel="preload" href="path/to/css/third-party/Admonition/admonition-warning.min.css" as="style" onload="this.rel='stylesheet'">

{# [INFO] Elif all classes "faq", "help" and "question" exists in my article, I add another styles #}
{% elif "class=\"faq\"" in article.content and if "class=\"help\"" in article.content and if "class=\"question\"" in article.content %}
    <link rel="preload" href="path/to/css/third-party/Admonition/admonition-question.min.css" as="style" onload="this.rel='stylesheet'">
{% endif %}

I don’t understand how to remove hard coding from these templates.

Thanks.


Solution

  • I can’t find, what is the correct syntax in Jinja2 for expressions like if any() in object/if any() in object.

    That's not how the any() function works in Python. You might write something like this:

    if any(value == 4 for value in mylist):
        ...
    

    The any() function, as shown in the documentation, is equivalent to:

    def any(iterable):
        for element in iterable:
            if element:
                return True
        return False
    

    The above unfortunately doesn't translate well into Jinja, because Jinja doesn't support list/tuple comprehensions, without which the any() function is much less useful.


    Looking at what you're actually trying to do:

    {#
       [INFO] If any of the classes "attention", "caution" or
      "warning" exists in my article, I add specific styles
    #}
    {% if "class=\"attenion\"" in article.content
         or if "class=\"caution\"" in article.content 
          or if "class=\"warning\"" in article.content %}
        <link rel="preload" href="path/to/css/third-party/Admonition/admonition-warning.min.css" as="style" onload="this.rel='stylesheet'">
    {% endif %}
    

    You could register a custom has_class filter that looks like this:

    def has_class(content, classnames):
        return any(f'class="{name}"' in content for name in classnames)
    

    And use it like this:

    {#
       [INFO] If any of the classes "attention", "caution" or
      "warning" exists in my article, I add specific styles
    #}
    {% if article.content|has_class(['attention', 'caution', 'warning']) %}
        <link rel="preload" href="path/to/css/third-party/Admonition/admonition-warning.min.css" as="style" onload="this.rel='stylesheet'">
    {% endif %}