NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #3251 most downloaded on PyPI
A Python engine for the Liquid template language.
Last release 5 days ago
29 Sep 2026
Release timing varies
gaps range from 2 weeks to 11 months
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
6 years old
77 releases · first in 2020
One column per quarter.
Fixed the tablerow tag. Previously it would render a blank <tr> given an empty iterable. Now it renders nothing when the target is empty or not iterab
Fixes
tablerow tag. Previously it would render a blank <tr> given an empty iterable. Now it renders nothing when the target is empty or not iterable. See #217.<= and >= operators. Previously we would evaluate some expressions to True when given non-orderable operands, and raise a TypeError in some cases. Now we follow Shopify/liquid behavior. See #219.TypeError would be raised if either the start or stop value's type can not be coerced to an integer. Now we default to 0. See #223.loop_iteration_limit resource limit. Previously we would fail to count nested {% tablerow %} tags when calculating the effective loop count.Fixed overly conservative range literal ( (x..y) ) clamping introduced in version 2.3.0. Now any range with a maximum effective length of sys.maxsize
Fixes
(x..y)) clamping introduced in version 2.3.0. Now any range with a maximum effective length of sys.maxsize is allowed. See #216.Fixed PackageLoader. It now rejects fully qualified template names that could escape the package directory.
PackageLoader. It now rejects fully qualified template names that could escape the package directory.first and last filters when the Liquid.Environment class variable string_first_and_last is True. Setting the string_first_and_last option to True would correctly tell the .first and .last special properties to treat strings as sequences, but the same behavior was not implemented for equivalent filters. Now | first and | last behave the same as .first and .last. See #213.Fixed an issue with excessively large integer values given to offset in {% for %} and {% tablerow %} tags. Previously we would get a ValueError in som
Fixes
Fixed an issue with excessively large integer values given to offset in {% for %} and {% tablerow %} tags. Previously we would get a ValueError in somme cases. Now we clamp offset to the length of the target iterable. See #209.
Fixed an issue with excessively large range literals ((1..10)). We now limit the minimum and maximum values allowed in range literal expressions to between -1024 and 1024.
Fixed an issue with FileSystemLoader where it would raise an OSError if given a very long file name when testing a path for existence.
Features
Added the block_nesting_limit class variable to liquid.Environment for handling excessive markup block nesting in Liquid templates. Previously we would get a RecursionError at render time if Python's recursion limit was reached. Now we raise a BlockNestingError (a subclass of ResourceLimitError) at parse time if block_nesting_limit is reached.
The default block_nesting_limit is 30. That's a maximum depth of 30 blocks per template source string or file.
See #208.
Fixed a bug in the built-in FileSystemLoader where a ValueError would be raised at render time if the target file name is empty or, in some cases, con
Fixes
FileSystemLoader where a ValueError would be raised at render time if the target file name is empty or, in some cases, contains only path punctuation and the loader is configured with a default file extension. Now a TemplateNotFoundError is raised instead. See #203.FileSystemLoader where a ValueError would be raised at render time if the configured default file extension is not a valid suffix. Now we raise a ValueError at FileSystemLoader construction time if the ext argument is not a valid suffix.{% cycle %} tag. Previously, if given a cycle group name without any other arguments, a ZeroDivisionError exception would be raised at render time. Now we raise a LiquidSyntaxError (we don't have a TagArgumentError) at parse time. See #202.AssertionError at render time when resolving variables using bracket syntax for the root segment and that segment evaluates to a non-string value. Now such uses of bracketed path syntax will be resolved to the configured Undefined type. See #206.Fixed {% case %} tags with no associated {% when %} or {% else %} tags, and no closing {% endcase %} tag. Previously a template such as {% case x %} w
Fixed {% case %} tags with no associated {% when %} or {% else %} tags, and no closing {% endcase %} tag. Previously a template such as {% case x %} would cause the parser to hang in an infinite loop.
Fixed FileSystemLoader and CachingFileSystemLoader to reject absolute paths.
FileSystemLoader and CachingFileSystemLoader to reject absolute paths.reject_symlinks keyword argument to FileSystemLoader and CachingFileSystemLoader. When True, symlinks pointing to files outside the search path will be rejected. reject_symlinks defaults to False.squish filter. {{ x | squish }} is equivalent to {{ x | strip | split | join }}. See #195.BoundTemplate.comments() and BoundTemplate.docs() for statically retrieving {% comment %}, {% # inline comment %} and {% doc %} nodes.{% snippet %} tag. Shopify/liquid released then quickly removed {% snippet %}. We're calling it "experimental" and keeping it disabled by default, pending more activity from Shopify/liquid. See #191 and #193.{% render %}. Now we visit partial templates once for each distinct set of arguments passed to {% render %}, potentially reporting "global" variables that we'd previously missed.string_filter decorator to coerce None to an empty string instead of "None". This is what Shopify/liquid does with nil.to_s.Added the escapejs filter for escaping characters for use in JavaScript string literals. Whereas the standard escape filter replaces &, <, >, ' and "
Features
escapejs filter for escaping characters for use in JavaScript string literals. Whereas the standard escape filter replaces &, <, >, ' and " with their equivalent HTML escape sequence, escapejs replaces control characters and potentially dangerous symbols with their corresponding Unicode escape sequences.Docs
escape filter.Fixed static analysis of filters in ternary expressions. See #180.
args and kwargs were considered "global". See #181.{% for %} tag. We were raising a LiquidTypeError when we should have been defaulting to an empty iterable, as Shopify/liquid does.Fixed bad imports from typing_extensions.
Fixes
typing_extensions.This is a major release with several breaking changes. As well as API changes listed below, we:
This is a major release with several breaking changes. As well as API changes listed below, we:
liquid.future.Environment to be the default, so as to improve Shopify/liquid compatibility by default.BoundTemplate.analyze_with_context(). Shout if you need contextual analysis and we'll restore this feature.cache_size argument to liquid.Environment and liquid.Template. Template caching is now handled by template loaders.expression_cache_size argument to liquid.Environment and liquid.Template. Environment-level expression caching is no longer available as it does not play nicely with detailed error messages. If you need to cache parsing of Liquid expressions, it is now recommended to implement a cache per tag, where it makes sense to do so for your use case.replace, replace_first and replace_last filters when they receive a "safe" string wrapped in Markup().reject, has, find and find_index.doc tag.Also see the migration guide.
liquid.parse(source), liquid.render(source, **data) and liquid.render_async(source, **data). These are shorthand functions that use liquid.DEFAULT_ENVIRONMENT.liquid.Environment.parse to liquid.Environment._parse, which returns a list of nodes, not a template.liquid.Environment.from_string as liquid.Environment.parse.liquid.Environment.render(source, **data) and liquid.Environment.render_async(source, **data). These are convenience methods equivalent to liquid.Environment.from_string(source).render(**data).liquid.Context to liquid.RenderContext.liquid.RenderContext constructor (previously liquid.Context) to require an instance of BoundTemplate as its only positional argument instead of an instance of Environment. All other arguments are now keyword only.liquid.exceptions.Error to liquid.exceptions.LiquidError.liquid.exceptions.TemplateNotFound to liquid.exceptions.TemplateNotFoundError.liquid.exceptions.NoSuchFilterFunc to liquid.exceptions.UnknownFilterError.BaseLoader.get_source and BaseLoader.get_source_async to accept and optional context keyword argument and arbitrary keyword arguments as "load context".BaseLoader.get_source_with_args and BaseLoader.get_source_with_context, and their async equivalents. BaseLoader.get_source now accepts optional context and load context arguments.TemplateSource (a named tuple) to be (text, name, uptodate, matter). It used to be (source, filename, uptodate, matter)liquid.expression.*. Now built-in expressions live in liquid.builtin.expressions.Identifier to Path.IdentifierPathElement. Path segments are now list[str | int | Path]].True, False, Nil, Empty and Blank. Each of these primitive expressions now require a token, so they can't be constant.liquid.token.Token to be a named tuple of (kind, value, index, source). It used to be (linenum, type, value).liquid.parse for your custom tags, you'll need to use functions/methods from liquid.builtin.expressions instead.liquid.parse.expect() and liquid.parse.expect_peek() in favour of TokenStream.expect() and TokenStream.expect_peek().liquid.expressions.TokenStream. Now there's only one TokenStream class, liquid.stream.TokenStream, reexported as liquid.TokenStream.liquid.expressions would generate and use plain tuples internally.TOKEN_RANGE_LITERAL token kind. The opening parenthesis of a range expression will use this kind to differentiate logical grouping parentheses from range expressions.TOKEN_OUTPUT in to two tokens, TOKEN_OUTPUT and TOKEN_EXPRESSION. Previously the value associated with TOKEN_OUTPUT would be the expression, now the expression follows in the next token, just like TOKEN_TAG.Here's a summary mapping from old expression parsing functions to the recommended new parsing functions/methods.
| Old | New |
|---|---|
tokenize_common_expression(str, linenum) |
liquid.builtin.expressions.tokenize(source, parent_token) |
*.tokenize(source, linenum) |
liquid.builtin.expressions.tokenize(source, parent_token) |
parse_common_expression(stream) |
liquid.builtin.expressions.parse_primitive(env, stream) |
parse_keyword_arguments(expr, linenum) |
liquid.builtin.expressions.KeywordArgument.parse(env, stream) |
parse_identifier(stream) |
liquid.builtin.expressions.Path.parse(env, stream) |
parse_unchained_identifier(stream) |
liquid.builtin.expressions.parse_identifier(env, stream) |
parse_string_or_identifier |
liquid.builtin.expressions.parse_string_or_path(env, stream) |
parse_unchained_identifier |
liquid.builtin.expressions.parse_name(env, stream) |
parse_boolean |
liquid.builtin.expressions.parse_primitive(env, stream) |
parse_nil |
liquid.builtin.expressions.parse_primitive(env, stream) |
parse_empty |
liquid.builtin.expressions.parse_primitive(env, stream) |
parse_blank |
liquid.builtin.expressions.parse_primitive(env, stream) |
parse_string_literal |
liquid.builtin.expressions.parse_primitive(env, stream) |
parse_integer_literal |
liquid.builtin.expressions.parse_primitive(env, stream) |
parse_float_literal |
liquid.builtin.expressions.parse_primitive(env, stream) |
Environment.parse_boolean_expression |
liquid.builtin.expressions.BooleanExpression.parse(env, stream) |
Environment.parse_filtered_expression |
liquid.builtin.expressions.FilteredExpression.parse(env, stream) |
Environment.parse_loop_expression |
liquid.builtin.expressions.LoopExpression.parse(env, stream) |
Added a shorthand_indexes class variable to liquid.Environment. When shorthand_indexes is set to True (default is False), array indexes in variable pa
Features
shorthand_indexes class variable to liquid.Environment. When shorthand_indexes is set to True (default is False), array indexes in variable paths need not be surrounded by square brackets. See #165.Fixed {% case %} / {% when %} behavior. When using `liquid.future.Environment`, we now render any number of {% else %} blocks and allow {% when %} tag
Fixes
{% case %} / {% when %} behavior. When using liquid.future.Environment, we now render any number of {% else %} blocks and allow {% when %} tags to appear after {% else %} tags. The default Environment continues to raise a LiquidSyntaxError in such cases.1 in the event of a syntax error. See issue #162.Changed
{% break %} and {% continue %} tag handling when they appear inside a {% tablerow %} tag. Now, when using liquid.future.Environment, interrupts follow Shopify/Liquid behavior introduced in #1818. Python Liquid's default environment is unchanged.Fixed handling of {% else %} tags that include text between else and the closing tag delimiter (%}). Previously we were treating such text as part of
Fixes
{% else %} tags that include text between else and the closing tag delimiter (%}). Previously we were treating such text as part of the {% else %} block. Now the default behavior is to raise a LiquidSyntaxError. When using liquid.future.Environment, we follow Shopify/Liquid behavior of silently ignoring {% else %} tag expressions, even in strict mode. See #150.liquid.future.Environment now silently ignores superfluous {% else %} and {% elsif %} blocks. The default environment continues to raise a LiquidSyntaxError if {% else %} or {% elsif %} appear after the first {% else %} tag. See #151.Fixed a bug with the LRU cache. We now raise a ValueError at construction time if a caching template loader is given a cache size less than 1. Previou
Fixes
ValueError at construction time if a caching template loader is given a cache size less than 1. Previously, in such cases, an IndexError would have been raised when attempting to write to the cache. See #148.Features
make_choice_loader(), a factory function that returns a ChoiceLoader or CachingChoiceLoader depending on its arguments. (docs, source)make_file_system_loader(), a factory function that returns a FileSystemLoader, FileExtensionLoader or CachingFileSystemLoader depending on its arguments. (docs, source)Fixed comparing strings with <, <=, > and >= in boolean expressions ({% if %} and {% unless %}). Previously we were raising a LiquidTypeError, now we
Fixes
<, <=, > and >= in boolean expressions ({% if %} and {% unless %}). Previously we were raising a LiquidTypeError, now we return the result of comparing two string by their lexicographical order. See #141.Features
CachingChoiceLoader, a template loader that chooses between a list of template loaders and caches parsed templates in memory. (docs, source)PackageLoader, a template loader that reads templates from Python packages. (docs, source)Dependencies
PackageLoader.Added an additional implementation of the split filter, which resolves some compatibility issues between Python Liquid's and the reference implementat
Fixes
Added an additional implementation of the split filter, which resolves some compatibility issues between Python Liquid's and the reference implementation. Previously, when given an empty string to split or when the string and the delimiter were equal, we used Python's str.split() behavior of producing one or two element lists containing empty strings. We now match Shopify/Liquid in returning an empty list for such cases. The new split filter will be enabled by default when using liquid.future.Environment, and can optionally be registered with liquid.Environment for those that don't mind the behavioral change. See #135.
Fixed unexpected errors from the date filter when it's given an invalid format string. Previously we were raising a liquid.exceptions.Error in response to a ValueError from strftime. We now raise a FilterArgumentError with its __cause__ set to the ValueError.
Fixed handling of "%s" date filter format strings. We now fall back to a string representation of datetime.timestamp() for platforms that don't support %s. Note that this is for "%s" exactly. We don't handle the more general case of %s appearing in a longer format string.
Optionally disable automatic suppression of whitespace only blocks with the Environment class attribute render_whitespace_only_blocks. (docs).
Features
Environment class attribute render_whitespace_only_blocks. (docs).node_class class attribute specifying the Node type the tag contributes to a templates AST. This is done for easier customization through Tag and Node subclassing.Fixed async loading of templates with the {% extends %} tag. Previously templates were being loaded synchronously, even when using render_async(). See
Removed is_up_to_date from liquid.BoundTemplate.__repr__. It was causing RuntimeWarnings with Python 3.11 when using an async template loader. Specifi
Fixes
is_up_to_date from liquid.BoundTemplate.__repr__. It was causing RuntimeWarnings with Python 3.11 when using an async template loader. Specifically warnings about coroutines that were never awaited.map filter. If given a nested array-like input, it now flattens it automatically. See #119.liquid tag when other liquid tags appear within it. See #123.Features
Fixed a bug where a class-based filter defining filter_async and setting with_context or with_environment to True would not be awaited. See #117.
Fixes
filter_async and setting with_context or with_environment to True would not be awaited. See #117.Build
.mypy_cache folders, making the distribution files significantly larger.Force the "wheel" build target to include py.typed.
Fixes
py.typed.liquid.__version__.Changed FileSystemLoader so that loaded templates can be pickled. See #107.
Fixes
FileSystemLoader so that loaded templates can be pickled. See #107.liquid.Environment template cache. Now, when given a cache_size of 0, the cache is disabled. See #108.Features
CachingFileSystemLoader, a template loader that handles its own cache rather than relying on the Environment template cache, which can't handle context-aware loaders. See #116.See CHANGELOG.
See CHANGELOG.
Fixes
BooleanExpression.macro names to be quoted or unquoted. Quoted and unquoted macro names are now equivalent when defining and/or calling a macro.Compatibility
raw tags. See Shopify/liquid #1683.See CHANGELOG.
See CHANGELOG.
Features
{% extends %} and {% block %} tags for template inheritance. These are extra tags that need to be registered with a liquid.Environment explicitly. (docs, source)sort_numeric filter. sort_numeric returns a new list with items from the input sequence sorted by any integers and/or floats found in the string representation of each item. (docs, source)Fixes
cycle tag when using liquid.future.Environment. We were misinterpreting unquoted cycle group names as strings rather than variables to be resolved, and not Liquid stringifying some cycled items before output. We've also rolled back changes to CycleNode.children() from version 1.7.0.LiquidSyntaxError in such cases. See #103.LiquidSyntaxError when given unbalanced parentheses. See #101.Compatibility
{% for %} tag now accepts a string literal as its iterable. Unlike Shopify/liquid, whether a string literal or a variable resolving to a string, the default Environment will iterate over characters in the string. liquid.future.Environment is now consistent with Shopify/liquid, in that it iterates over an "array" where the first an only item is the string. See #102.round filter is now consistent with Shopify/liquid and Ruby 3 when given non-integer arguments. See Shopify/liquid#1590.See CHANGELOG.
See CHANGELOG.
Fixes
assign, capture, etc.) in templates rendered with the {% render %} tag during contextual analysis. Previously these variables were not reported in the results of BoundTemplate.analyze_with_context(). See #92.liquid.future.Environment, an environment that aims for maximum compatibility with Ruby Liquid, without concern for backwards incompatible changes to template rendering behavior. liquid.Environment should be considered the most stable "standard" configuration, liquid.future.Environment sacrifices stability for improved compatibility with Ruby Liquid. See the known issues page.cycle nodes. Previously, CycleNode.children() erroneously included a cycle group name expression, if available.Features
BoundTemplate.analyze() and BoundTemplate.analyze_with_context(). See #91 and docs.BoundTemplate.analyze(). See #97 and docs.Environment.analyze_tags(). This form of tag analysis happens before a template is fully parsed, giving us the opportunity to find unknown, unexpected and unbalanced tags that might cause the parser to raise an exception or skip template blocks. See #98 and docs.Fixed static template analysis fails with {% break %} and {% continue %}. See #89.
Fixes
{% break %} and {% continue %}. See #89.See CHANGELOG.
See CHANGELOG.
Fixes
liquid.expression.Identifier, which is exposed in the results of liquid.BoundTemplate.analyze(). We now represent variable path elements containing a . as quoted strings inside square brackets. See #87.Features
liquid.BoundTemplate.analyze() now use instances of ReferencedVariable for their keys. ReferencedVariable is a str subclass that adds a parts property, being a tuple representation of the variable. See #87.Fixed case and when tag expression parsing. when expressions no longer fail when presented with a string containing a comma. Handling of comma and or
Fixes
case and when tag expression parsing. when expressions no longer fail when presented with a string containing a comma. Handling of comma and or separated "sub-expressions" is now consistent with the reference implementation. See #86.Feature release. See CHANGELOG.
Feature release. See CHANGELOG.
Features
The following non-standard tags and filters are reimplementations of those found in the Python Liquid Extra project, which is now receiving bugfix updates only. Unlike standard tags and filters, which are registered for you automatically, extra tags and filters must be explicitly registered with an Environment`. See https://jg-rp.github.io/liquid/extra/introduction.
Added an if tag that supports a logical not operator and grouping terms with parentheses. (docs, source)
Added drop-in replacements for the standard output statement, assign tag and echo tag that support inline conditional expressions. (docs, source)
Added macro and call tags that define parameterized Liquid snippets for reuse. (docs, source)
Added the with tag that extends the local namespace with block scoped variables. (docs, source)
Added the json, index, script_tag and stylesheet_tag filters. (docs, source)
Compatibility
for tag arguments can now be separated by commas as well as whitespace. See Shopify/liquid#1658Bug fix release. See CHANGELOG.
Bug fix release. See CHANGELOG.
Hot fix
TypeError when unhashable types were found in a render context's local namespace. See #79.Bug fixes and test against Python 3.11. See CHANGELOG.
Bug fixes and test against Python 3.11. See CHANGELOG.
Fixes
tablerowloop drop now exposes its row property. See #77.for and tablerow tag arguments can now be string representations of integers as well as integer literals and variables that resolve to integers. See #78.Compatibility
truncatewords filter no longer raises a FilterArgumentError if its argument is greater than 2147483648 and the number of words in the input string is less than the target number of words. This is inline with recent changes committed to the reference implementation of Liquid.slice filter now clamps its arguments to between -9223372036854775808 and 9223372036854775807, as does the reference implementation of Liquid.Bug fix release. See CHANGELOG.
Bug fix release. See CHANGELOG.
Hot fix
0.0 and decimal.Decimal("0") as False. Python considers these values to be falsy, Liquid does not. See #74.sys.get_int_max_str_digits if it is available and LIQUIDINTMAXSTRDIGITS is not set. Note that sys.get_int_max_str_digits is called once at startup, so Liquid's limit will change with sys.set_int_max_str_digits.Keep comment text for later static analysis when parsing {% comment %} block tags. See https://github.com/jg-rp/liquid/issues/70.
Fixes
Bug fixes. See CHANGELOG.
Bug fixes. See CHANGELOG.
Fixes
date filter to support parsing UNIX timestamps from integers and string representations of integers. For consistency with the reference implementation of Liquid, date now returns the input string unchanged if it can not be parsed. See #67.Context.copy(). See #68.Fixed a potential memory leak from using functools.lru_cache on a class method. See #63.
Fixes
functools.lru_cache on a class method. See #63.default filter. Liquid zero should not be equal to False. The default filter now returns 0 if its left value is zero. Before it would have return its default value. See #62.0 and false to be equal and 0 to be falsy. Python Liquid is now consistent with the reference implementation when comparing integers to booleans. See #65.Fixed a bug with the StrictDefaultFilter. It was failing to be strict when accessed by some filter decorators and helpers. Now the default filter will
Hot fix
StrictDefaultFilter. It was failing to be strict when accessed by some filter decorators and helpers. Now the default filter will immediately return its default value if its left value defines a force_liquid_default property and that property is truthy. See #62.Feature release. Resource limits.
Feature release. Resource limits.
Features
StrictDefaultUndefined, an undefined type that plays nicely with the default filter, is now built in. (docs)Environment. Those class attributes are context_depth_limit, loop_iteration_limit, local_namespace_limit and output_stream_limit. (docs)Fixes
StrictUndefined that, when extended, stopped if from looking at its own msg property. See #57.Allow render context customization by subclassing Context and BoundTemplate.
Features
Context and BoundTemplate.BoundTemplate.analyze_with_context(). Complementing static template analysis, released in version 1.2.0, contextual template analysis performs a template render, capturing information about template variable usage as it goes. (docs)Add typing-extensions dependency.
typing-extensions dependency.New inline comment tag {% # .. %}. See Shopify Liquid PR #1498
Features
{% # .. %}. See Shopify Liquid PR #1498BoundTemplate.analyze() and BoundTemplate.analyze_async() traverse a template's abstract syntax tree and report template variable usage. Static tree traversal (without rendering or evaluating expressions) is supported by the new, optional children() methods of liquid.expression.Expression and liquid.ast.Node. (docs)Fixes
liquid tags where it is common to put a newline immediately after "liquid".Fixed a bug where double pipe characters (||) in a filtered expression would cause an IndexError. A LiquidSyntaxError is now raised in such cases, inc
||) in a filtered expression would cause an IndexError. A LiquidSyntaxError is now raised in such cases, including the line number of the offending error.Environment.fromString to catch unexpected parsing errors. A Liquid Error will now be raised with a message of "unexpected liquid parsing error" and its __cause__ set to the offending exception.Fixed a bug where the where filter would incorrectly ignore an explicit false given as the target value. See #51.
where filter would incorrectly ignore an explicit false given as the target value. See #51.Prioritise object properties and keys named size, first and last over the special built-in properties of the same names. See #46.
size, first and last over the special built-in properties of the same names. See #46.uniq filter. It no longer raises an exception when given a key argument and a sequence containing objects that don't have that key/property. See #47.strip_html filter now removes style and script tag blocks in their entirety, including everything in between. See #45.remove_last and replace_last filters.Lazy forloop helper variables. Don't calculate index, rindex etc. unless accessed.
forloop helper variables. Don't calculate index, rindex etc. unless accessed.forloop.name, as per the reference implementation. forloop.name is the concatenation of the loop variable identifier and the target iterable identifier, or a string representation of a range literal, separated by a hyphen.divided_by filter. Given a float value and integer argument, it was incorrectly doing integer division.tablerowloop and tablerow HTML generation.Refactored expression lexers. New, subtly different, tag expression tokenizers are now in liquid.expressions. Built-in tags use these lexers indirectl
liquid.expressions. Built-in tags use these lexers indirectly via new specialized expression parsers. Older expression lexers and parsers will be maintained until at least Python Liquid version 2.0 for those that use them in custom tags. See #42.liquid.expressions, whereas before all expression parsing went through liquid.parse.ExpressionParser.parse_expression(). Built-in tags now use these new parsers. The more general parser will be maintained until at least Python Liquid Version 2.0. See #42.liquid.parse.Parser.parse_block() now accepts any container as its end argument. Benchmarks show that using a frozenset for end instead of a tuple gives a small performance improvement.get_source_with_context() and get_source_with_context_async() to liquid.loaders.BaseLoader. Custom loaders can now use the active render context to dynamically modify their search space when used from include or render, or any custom tag using Context.get_template_with_context().
Context.get_template_with_context() also accepts arbitrary keyword arguments that are passed along to get_source_with_context(). The build-in include and render tags add a tag argument with their tag name, so custom loaders can modify their search space depending on which tag was used.
See the Custom Loaders documentation for examples.Fixed a bug where a for loop's limit would be incorrect when using offset: continue multiple times (three or more for tags looping over the same seque
offset: continue multiple times (three or more for tags looping over the same sequence). See #41.Fixed a bug where blocks that contain whitespace only were being suppressed when the whitespace was explicitly output. Automatic whitespace suppressio
if, unlesss and for blocks that don't contain an output statement or echo tag, even if the output itself is whitespace. See #38..first and .last properties did not match that of the first and last filters. Now, if given a string, .first and .last will return an undefined, and the first and last filters will return None. See #34.Added new comment syntax. Disabled by default, enable shorthand comments with the template_comments argument to liquid.Template or liquid.Environment.
template_comments argument to liquid.Template or liquid.Environment. When True, anything between {# and #} will be considered a comment.forloop.length would be incorrect when using offsset: continue in a loop expression.Changed Context._tag_namespace to Context.tag_namespace.
Context._tag_namespace to Context.tag_namespace.- Fixed manifest error.
- Added py.typed
py.typedVersion bump. First stable release.
Version bump. First stable release.
The following behavioral changes are the result of feedback gained from exporting Python Liquid's "golden" test cases, and running them against Ruby L
The following behavioral changes are the result of feedback gained from exporting Python
Liquid's "golden" test cases, and running them against Ruby Liquid (the reference
implementation). Both Python Liquid version 0.11.0 and Ruby Liquid version 5.1.0 pass
all tests currently defined in liquid/golden/.
when expressions. See #31.join, concat, where, uniq and compact filters now use the new sequence_filter decorator. sequence_filter coerces filter left values to array-like objects. sequence_filter will also flatten nested array-like objects, just like the reference implementation.first, last and map filters now operate on any array-like objects. Previously they were limited to lists and tuples. Strings still don't work.uniq and compact filters now accept an optional argument. If an argument is provided, it should be the name of a property and the left value should be a sequence of objects.size filter now returns a default of 0 if its left value does not have a __len__ method.replace and replace_first filters now treat undefined arguments as an empty string.slice filter now works on lists, tuples and ranges, as well as strings.math_filter decorator would cast strings representations of negative integers to a float rather than an int.Range literals can now be assigned, compared and passed as arguments to include or render tags. They can also be filtered as if they were an array.
include or render tags. They can also be filtered as if they were an array.Changed named counter (increment and decrement) scoping. Unless a named counter is shadowed by an assign or capture, the counter will be in scope for
increment and decrement) scoping. Unless a named counter is shadowed by an assign or capture, the counter will be in scope for all subsequent Liquid expressions.{% increment %} to be a post-increment operation. {% decrement %} remains a pre-decrement operation.forloop.parentloop. Access parent forloop objects from nested loops.Fixed a bug where arguments to Template() where not being passed to the implicit environment properly (again).
Template() where not being passed to the implicit environment properly (again).sort and map filters were being ignored. Those filters can now raise a FilterError.Removed @abstractmethod from liquid.loaders.BaseLoader.get_source. Custom loaders are now free to implement either get_source or get_source_async or b
@abstractmethod from liquid.loaders.BaseLoader.get_source. Custom loaders are now free to implement either get_source or get_source_async or both. The BaseLoader implementation of get_source simply raises a NotImplementedError.liquid.loaders.TemplateSource.uptodate (as returned by get_source and get_source_async) can now be a coroutine function. This means async loaders can check a template's source for changes asynchronously.cache_size argument to Environment and Template for controlling the capacity of the default template cache.liquid.parser.ExpressionParser with END_EXPRESSION.Version bump. Last release before removing depreciated class-based filters.
Version bump. Last release before removing depreciated class-based filters.
Change log: https://github.com/jg-rp/liquid/blob/main/CHANGES.rst
Recursive use of the "render" tag now raises a ContextDepthError if MAX_CONTEXT_DEPTH is exceeded. This is now consistent with recursive "include".
ContextDepthError if MAX_CONTEXT_DEPTH is exceeded. This is now consistent with recursive "include".case/when and unless). If defined, the result of calling a drop's __liquid__ method will be used in those scenarios.base64_encode, base64_decode, base64_url_safe_encode and base64_url_safe_decode filters.Template.render_async is awaited, render and include tags will load templates asynchronously. Custom loaders should implement get_source_async.__getitem_async__, which is assumed to be an async version of __getitem__, it will be awaited instead of calling __getitem__.Your coding agent can read these notes before it upgrades. Set up the MCP server →