Miya Engine Limitations and Differences from Jinja2¶
This document details the known limitations and differences between Miya Engine and Jinja2, based on extensive testing of the implementation.
Miya Version: v0.1.0
Table of Contents¶
- Critical Limitations
- Comprehensions Limitations
- Filter Limitations
- Macro Limitations
- Syntax Limitations
- Workarounds and Alternatives
Critical Limitations¶
1. List Comprehensions with Filter Clauses¶
Not Supported:
{{ [x for x in numbers if x > 5] }}
{{ [user.name for user in users if user.active] }}
{{ [x for x in items if x.price > 100 and x.stock > 0] }}
Error:
Reason: The parser treats any if inside a comprehension as a ternary operator and requires an else clause.
Workaround:
{# Use filter chains instead #}
{{ users|selectattr("active")|map(attribute="name")|list }}
{{ numbers|select("greaterthan", 5)|list }}
2. Dictionary Comprehensions with .items() Unpacking¶
Not Supported:
Error:
Reason: The parser doesn't support tuple unpacking in dictionary comprehensions.
Workaround:
{# Only single-item iteration works #}
{{ {user.id: user.name for user in users} }}
{{ {item.key: item.value for item in key_value_list} }}
3. Nested Comprehensions¶
Not Supported:
{{ [item for category in categories for item in category.items] }}
{{ [(a, b) for a in list1 for b in list2] }}
Error:
Reason: Multiple for clauses in a single comprehension are not parsed correctly.
Workaround:
{# Use nested loops instead #}
{% set result = [] %}
{% for category in categories %}
{% for item in category.items %}
{% do result.append(item) %}
{% endfor %}
{% endfor %}
4. Inline Conditionals Without else¶
Not Supported:
Error:
Reason: The parser always expects a complete ternary expression with both branches.
Workaround:
{# Use block-level conditionals #}
{% if not loop.last %}, {% endif %}
{% if condition %}{{ value }}{% endif %}
{# Or provide an else clause #}
{{ ", " if not loop.last else "" }}
{{ value if condition else "" }}
Comprehensions Limitations¶
Summary Table¶
| Feature | Jinja2 | Miya | Status |
|---|---|---|---|
[expr for item in list] |
Works | ||
[expr for item in list if cond] |
Not Supported | ||
{key: val for item in list} |
Works | ||
{k: v for k, v in dict.items()} |
Not Supported | ||
[item for list in lists for item in list] |
Not Supported | ||
{k: v for item in list if cond} |
Not Supported |
What Works¶
{# Basic list comprehensions #}
{{ [x * 2 for x in numbers] }}
{{ [user.name for user in users] }}
{{ [item|upper for item in items] }}
{# Basic dict comprehensions #}
{{ {user.id: user.name for user in users} }}
{{ {item.key: item.value for item in data} }}
{# With filters applied #}
{{ [name|title for name in names] }}
{{ [price|round(2) for price in prices] }}
Filter Limitations¶
Collection Filters with Limited Support¶
The following filters appear to have issues when chained or used with certain data types:
Problematic Filters:
- sort - May fail with: "sort filter requires a sequence"
- reverse - Limited support
- unique - May not work as expected
- slice - Limited support
- batch - May have issues
- select - Works but limited
- reject - Works but limited
- selectattr - Works in filter chains, not in comprehensions
- rejectattr - Works in filter chains, not in comprehensions
- groupby - Limited testing
Working Alternatives:
{# This may fail #}
{{ numbers|sort|reverse }}
{# Use these instead #}
{{ numbers|list }} {# Just convert to list #}
{% for num in numbers|sort %}{{ num }}{% endfor %} {# In loops #}
Reliably Working Filters¶
String Filters:
- upper, lower, capitalize, title
- trim, replace, truncate
- split, join
- startswith, endswith, contains
- slugify
Numeric Filters:
- abs, round, int, float
- default
HTML Filters:
- escape, safe, striptags
- urlencode
Other:
- length, first, last
- default
- tojson
Macro Limitations¶
caller() Function Not Supported¶
Not Supported:
{% macro wrapper(title) %}
<div class="card">
<h3>{{ title }}</h3>
{{ caller() }} {# Not supported #}
</div>
{% endmacro %}
{% call wrapper("My Card") %}
<p>Card content</p>
{% endcall %}
Error:
Workaround:
{# Pass content as a parameter instead #}
{% macro wrapper(title, content) %}
<div class="card">
<h3>{{ title }}</h3>
{{ content }}
</div>
{% endmacro %}
{% set my_content %}
<p>Card content</p>
{% endset %}
{{ wrapper("My Card", my_content) }}
Varargs and Kwargs Not Supported¶
Not Supported:
Workaround:
{# Use explicit parameters with defaults #}
{% macro flexible(param1="", param2="", param3="") %}
{# This works #}
{% endmacro %}
Syntax Limitations¶
enumerate() Keyword Arguments¶
Not Supported:
Workaround:
Dictionary Iteration with Tuple Unpacking¶
Not Supported:
Workaround:
{# Iterate over keys #}
{% for key in dict %}
{{ key }}: {{ dict[key] }}
{% endfor %}
{# Or use a list of objects #}
{% for item in items %}
{{ item.key }}: {{ item.value }}
{% endfor %}
Multiple Variable Assignment¶
Not Supported:
Workaround:
Workarounds and Alternatives¶
Pattern 1: Filtering Data¶
Instead of comprehensions with filters:
{# Doesn't work #}
{{ [user for user in users if user.active] }}
{# Use filter chains #}
{{ users|selectattr("active")|list }}
{# Or use loops with conditionals #}
{% set active_users = [] %}
{% for user in users %}
{% if user.active %}
{% do active_users.append(user) %}
{% endif %}
{% endfor %}
Pattern 2: Complex Data Transformations¶
Instead of nested comprehensions:
{# Doesn't work #}
{{ [item for cat in categories for item in cat.items] }}
{# Use nested loops #}
{% set all_items = [] %}
{% for category in categories %}
{% for item in category.items %}
{% do all_items.append(item) %}
{% endfor %}
{% endfor %}
Pattern 3: Conditional Output¶
Instead of inline if without else:
{# Doesn't work #}
{{ ", " if not loop.last }}
{# Use block conditionals #}
{% if not loop.last %}, {% endif %}
{# Or provide else clause #}
{{ ", " if not loop.last else "" }}
Pattern 4: Dictionary Processing¶
Instead of .items() unpacking:
{# Doesn't work #}
{{ {k|upper: v for k, v in dict.items()} }}
{# Create list of key-value objects first #}
{% set kv_list = [] %}
{% for key in dict %}
{% do kv_list.append({"key": key, "value": dict[key]}) %}
{% endfor %}
{{ {item.key|upper: item.value for item in kv_list} }}
Testing Your Templates¶
When migrating from Jinja2 to Miya, test for these patterns:
Checklist¶
- [ ] No comprehensions with
ifclauses - [ ] No
.items()unpacking in comprehensions - [ ] No nested comprehensions (multiple
forclauses) - [ ] All inline conditionals have
elseclauses - [ ] No
caller()in macros - [ ] No varargs/kwargs in macros
- [ ]
enumerate()uses positional args only - [ ] No tuple unpacking in
{% for %}loops - [ ] No multiple variable assignment with
{% set %}
Quick Test¶
# Run examples to verify syntax
cd examples/features/
for dir in */; do
cd "$dir"
go run main.go > /dev/null 2>&1 && echo " $dir" || echo " $dir"
cd ..
done
See Also¶
- Feature Examples - Working examples of all supported features
- JINJA2_VS_MIYA_FEATURE_MATRIX.md - Complete compatibility matrix
- COMPREHENSIVE_FEATURES.md - All supported features with examples
Summary¶
Miya Engine provides ~95% Jinja2 compatibility with these main limitations:
- Comprehensions with
ifclauses - Dictionary comprehensions with
.items() - Nested comprehensions
- Inline conditionals without
else - Macro
caller()function - Some collection filters have limited support
Most Jinja2 templates will work with minor adjustments. Use the examples in examples/features/ as a reference for working syntax.