Releases: jg-rp/liquid
Version 2.1.0
Features
- Added the
escapejsfilter for escaping characters for use in JavaScript string literals. Whereas the standardescapefilter replaces&,<,>,'and"with their equivalent HTML escape sequence,escapejsreplaces control characters and potentially dangerous symbols with their corresponding Unicode escape sequences.
Docs
- Improved documentation for HTML auto escaping and the
escapefilter.
Version 2.0.2
- Fixed static analysis of filters in ternary expressions. See #180.
- Fixed static analysis of macro blocks. Previously
argsandkwargswere considered "global". See #181. - Fixed looping over non-iterable objects with the
{% for %}tag. We were raising aLiquidTypeErrorwhen we should have been defaulting to an empty iterable, as Shopify/liquid does.
Version 2.0.1
Fixes
- Fixed bad imports from
typing_extensions.
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) |
Version 1.13.0
Features
- Added a
shorthand_indexesclass variable toliquid.Environment. Whenshorthand_indexesis 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 defaultEnvironmentcontinues to raise aLiquidSyntaxErrorin such cases. - Fixed line numbers in some error messages. When parsing some Liquid expressions, we were always getting a line number of
1in 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 betweenelseand 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.Environmentnow silently ignores superfluous{% else %}and{% elsif %}blocks. The default environment continues to raise aLiquidSyntaxErrorif{% 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
ValueErrorat construction time if a caching template loader is given a cache size less than 1. Previously, in such cases, anIndexErrorwould have been raised when attempting to write to the cache. See #148.
Features
- Added
make_choice_loader(), a factory function that returns aChoiceLoaderorCachingChoiceLoaderdepending on its arguments. (docs, source) - Added
make_file_system_loader(), a factory function that returns aFileSystemLoader,FileExtensionLoaderorCachingFileSystemLoaderdepending 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
splitfilter, 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 newsplitfilter will be enabled by default when usingliquid.future.Environment, and can optionally be registered withliquid.Environmentfor those that don't mind the behavioral change. See #135. -
Fixed unexpected errors from the
datefilter when it's given an invalid format string. Previously we were raising aliquid.exceptions.Errorin response to aValueErrorfrom strftime. We now raise aFilterArgumentErrorwith 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%sappearing in a longer format string.