Releases: jg-rp/liquid
Version 2.0.1
Version 2.0.0
This is a major release with several breaking changes. As well as API changes listed below, we:
- Drop support for Python version 3.7 and 3.8.
- Promote rendering behavior from
liquid.future.Environment
to be the default, so as to improve Shopify/liquid compatibility by default. - Fix variable/identifier/path parsing described in issue #39.
- Improve Liquid syntax error messages and exposes source index, line numbers and column numbers through methods on Liquid exceptions. See #53.
- Change comment tag parsing to better match Shopify/Liquid. See #133.
- Remove
BoundTemplate.analyze_with_context()
. Shout if you need contextual analysis and we'll restore this feature. - Remove the
cache_size
argument toliquid.Environment
andliquid.Template
. Template caching is now handled by template loaders. - Remove the
expression_cache_size
argument toliquid.Environment
andliquid.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. - Make markupsafe>=3 a dependency. Previously markupsafe was an optional dependency. Version 3 of markupsafe brings some subtle changes to the
replace
,replace_first
andreplace_last
filters when they receive a "safe" string wrapped inMarkup()
. - Add new filters
reject
,has
,find
andfind_index
. - Add the new
doc
tag.
API changes
Also see the migration guide.
Miscellaneous
- Added
liquid.parse(source)
,liquid.render(source, **data)
andliquid.render_async(source, **data)
. These are shorthand functions that useliquid.DEFAULT_ENVIRONMENT
. - Renamed
liquid.Environment.parse
toliquid.Environment._parse
, which returns a list of nodes, not a template. - Aliased
liquid.Environment.from_string
asliquid.Environment.parse
. - Added
liquid.Environment.render(source, **data)
andliquid.Environment.render_async(source, **data)
. These are convenience methods equivalent toliquid.Environment.from_string(source).render(**data)
. - Renamed
liquid.Context
toliquid.RenderContext
. - Change the
liquid.RenderContext
constructor (previouslyliquid.Context
) to require an instance ofBoundTemplate
as its only positional argument instead of an instance ofEnvironment
. All other arguments are now keyword only. - Renamed
liquid.exceptions.Error
toliquid.exceptions.LiquidError
. - Renamed
liquid.exceptions.TemplateNotFound
toliquid.exceptions.TemplateNotFoundError
. - Renamed
liquid.exceptions.NoSuchFilterFunc
toliquid.exceptions.UnknownFilterError
.
Template loaders
- Changed
BaseLoader.get_source
andBaseLoader.get_source_async
to accept and optionalcontext
keyword argument and arbitrary keyword arguments as "load context". - Removed
BaseLoader.get_source_with_args
andBaseLoader.get_source_with_context
, and their async equivalents.BaseLoader.get_source
now accepts optional context and load context arguments. - Changed
TemplateSource
(a named tuple) to be (text, name, uptodate, matter). It used to be (source, filename, uptodate, matter)
Builtin expressions
- Removed
liquid.expression.*
. Now built-in expressions live inliquid.builtin.expressions
. - Renamed
Identifier
toPath
. - Removed
IdentifierPathElement
. Path segments are nowlist[str | int | Path]]
. - Removed constant versions of
True
,False
,Nil
,Empty
andBlank
. Each of these primitive expressions now require a token, so they can't be constant.
Tag expression parsing
- Changed
liquid.token.Token
to be a named tuple of (kind, value, index, source). It used to be (linenum, type, value). - Removed legacy expression parsing functions. If you're importing anything from
liquid.parse
for your custom tags, you'll need to use functions/methods fromliquid.builtin.expressions
instead. - Removed
liquid.parse.expect()
andliquid.parse.expect_peek()
in favour ofTokenStream.expect()
andTokenStream.expect_peek()
. - Removed
liquid.expressions.TokenStream
. Now there's only oneTokenStream
class,liquid.stream.TokenStream
, reexported asliquid.TokenStream
. - All tokens are now named tuples. Previously functions in
liquid.expressions
would generate and use plain tuples internally. - Added the
TOKEN_RANGE_LITERAL
token kind. The opening parenthesis of a range expression will use this kind to differentiate logical grouping parentheses from range expressions. - Split tokens with kind
TOKEN_OUTPUT
in to two tokens,TOKEN_OUTPUT
andTOKEN_EXPRESSION
. Previously the value associated withTOKEN_OUTPUT
would be the expression, now the expression follows in the next token, just likeTOKEN_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) |
Version 1.13.0
Features
- Added a
shorthand_indexes
class variable toliquid.Environment
. Whenshorthand_indexes
is set toTrue
(default isFalse
), array indexes in variable paths need not be surrounded by square brackets. See #165.
Version 1.12.2
Fixes
- Fixed
{% case %}
/{% when %}
behavior. When usingliquid.future.Environment
, we now render any number of{% else %}
blocks and allow{% when %}
tags to appear after{% else %}
tags. The defaultEnvironment
continues to raise aLiquidSyntaxError
in such cases. - Fixed line numbers in some error messages. When parsing some Liquid expressions, we were always getting a line number of
1
in the event of a syntax error. See issue #162.
Changed
- Changed
{% break %}
and{% continue %}
tag handling when they appear inside a{% tablerow %}
tag. Now, when usingliquid.future.Environment
, interrupts follow Shopify/Liquid behavior introduced in #1818. Python Liquid's default environment is unchanged.
Version 1.12.1
Fixes
- Fixed handling of
{% else %}
tags that include text betweenelse
and the closing tag delimiter (%}
). Previously we were treating such text as part of the{% else %}
block. Now the default behavior is to raise aLiquidSyntaxError
. When usingliquid.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 aLiquidSyntaxError
if{% else %}
or{% elsif %}
appear after the first{% else %}
tag. See #151.
Version 1.12.0
Fixes
- 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. Previously, in such cases, anIndexError
would have been raised when attempting to write to the cache. See #148.
Features
- Added
make_choice_loader()
, a factory function that returns aChoiceLoader
orCachingChoiceLoader
depending on its arguments. (docs, source) - Added
make_file_system_loader()
, a factory function that returns aFileSystemLoader
,FileExtensionLoader
orCachingFileSystemLoader
depending on its arguments. (docs, source)
Version 1.11.0
Fixes
- Fixed comparing strings with
<
,<=
,>
and>=
in boolean expressions ({% if %}
and{% unless %}
). Previously we were raising aLiquidTypeError
, now we return the result of comparing two string by their lexicographical order. See #141.
Features
- Added
CachingChoiceLoader
, a template loader that chooses between a list of template loaders and caches parsed templates in memory. (docs, source) - Added
PackageLoader
, a template loader that reads templates from Python packages. (docs, source)
Dependencies
- Python Liquid now depends on importlib-resources >= 5.10. This is that backport of importlib.resources from Python's standard library. We use it in
PackageLoader
.
Version 1.10.2
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'sstr.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 newsplit
filter will be enabled by default when usingliquid.future.Environment
, and can optionally be registered withliquid.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 aliquid.exceptions.Error
in response to aValueError
from strftime. We now raise aFilterArgumentError
with its__cause__
set to theValueError
. -
Fixed handling of
"%s"
date filter format strings. We now fall back to a string representation ofdatetime.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.
Version 1.10.0
Features
- Optionally disable automatic suppression of whitespace only blocks with the
Environment
class attributerender_whitespace_only_blocks
. (docs). - All built-in and included "extra" tags now have a
node_class
class attribute specifying theNode
type the tag contributes to a templates AST. This is done for easier customization throughTag
andNode
subclassing.