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.Environmentto 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_sizeargument toliquid.Environmentandliquid.Template. Template caching is now handled by template loaders. - Remove the
expression_cache_sizeargument toliquid.Environmentandliquid.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_firstandreplace_lastfilters when they receive a "safe" string wrapped inMarkup(). - Add new filters
reject,has,findandfind_index. - Add the new
doctag.
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.parsetoliquid.Environment._parse, which returns a list of nodes, not a template. - Aliased
liquid.Environment.from_stringasliquid.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.Contexttoliquid.RenderContext. - Change the
liquid.RenderContextconstructor (previouslyliquid.Context) to require an instance ofBoundTemplateas its only positional argument instead of an instance ofEnvironment. All other arguments are now keyword only. - Renamed
liquid.exceptions.Errortoliquid.exceptions.LiquidError. - Renamed
liquid.exceptions.TemplateNotFoundtoliquid.exceptions.TemplateNotFoundError. - Renamed
liquid.exceptions.NoSuchFilterFunctoliquid.exceptions.UnknownFilterError.
Template loaders
- Changed
BaseLoader.get_sourceandBaseLoader.get_source_asyncto accept and optionalcontextkeyword argument and arbitrary keyword arguments as "load context". - Removed
BaseLoader.get_source_with_argsandBaseLoader.get_source_with_context, and their async equivalents.BaseLoader.get_sourcenow 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
IdentifiertoPath. - Removed
IdentifierPathElement. Path segments are nowlist[str | int | Path]]. - Removed constant versions of
True,False,Nil,EmptyandBlank. Each of these primitive expressions now require a token, so they can't be constant.
Tag expression parsing
- Changed
liquid.token.Tokento 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.parsefor your custom tags, you'll need to use functions/methods fromliquid.builtin.expressionsinstead. - Removed
liquid.parse.expect()andliquid.parse.expect_peek()in favour ofTokenStream.expect()andTokenStream.expect_peek(). - Removed
liquid.expressions.TokenStream. Now there's only oneTokenStreamclass,liquid.stream.TokenStream, reexported asliquid.TokenStream. - All tokens are now named tuples. Previously functions in
liquid.expressionswould generate and use plain tuples internally. - Added the
TOKEN_RANGE_LITERALtoken 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_OUTPUTin to two tokens,TOKEN_OUTPUTandTOKEN_EXPRESSION. Previously the value associated withTOKEN_OUTPUTwould 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) |