Skip to content

Releases: jg-rp/liquid

Version 2.0.1

17 Mar 07:34
Compare
Choose a tag to compare

Fixes

  • Fixed bad imports from typing_extensions.

Version 2.0.0

16 Mar 08:38
Compare
Choose a tag to compare

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 to liquid.Environment and liquid.Template. Template caching is now handled by template loaders.
  • Remove the 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.
  • Make markupsafe>=3 a dependency. Previously markupsafe was an optional dependency. Version 3 of markupsafe brings some subtle changes to the replace, replace_first and replace_last filters when they receive a "safe" string wrapped in Markup().
  • Add new filters reject, has, find and find_index.
  • Add the new doc tag.

API changes

Also see the migration guide.

Miscellaneous

  • Added liquid.parse(source), liquid.render(source, **data) and liquid.render_async(source, **data). These are shorthand functions that use liquid.DEFAULT_ENVIRONMENT.
  • Renamed liquid.Environment.parse to liquid.Environment._parse, which returns a list of nodes, not a template.
  • Aliased liquid.Environment.from_string as liquid.Environment.parse.
  • Added 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).
  • Renamed liquid.Context to liquid.RenderContext.
  • Change the 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.
  • Renamed liquid.exceptions.Error to liquid.exceptions.LiquidError.
  • Renamed liquid.exceptions.TemplateNotFound to liquid.exceptions.TemplateNotFoundError.
  • Renamed liquid.exceptions.NoSuchFilterFunc to liquid.exceptions.UnknownFilterError.

Template loaders

  • Changed BaseLoader.get_source and BaseLoader.get_source_async to accept and optional context keyword argument and arbitrary keyword arguments as "load context".
  • Removed 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.
  • 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 in liquid.builtin.expressions.
  • Renamed Identifier to Path.
  • Removed IdentifierPathElement. Path segments are now list[str | int | Path]].
  • Removed constant versions of True, False, Nil, Empty and Blank. 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 from liquid.builtin.expressions instead.
  • Removed liquid.parse.expect() and liquid.parse.expect_peek() in favour of TokenStream.expect() and TokenStream.expect_peek().
  • Removed liquid.expressions.TokenStream. Now there's only one TokenStream class, liquid.stream.TokenStream, reexported as liquid.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 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)

Version 1.13.0

08 Feb 14:16
Compare
Choose a tag to compare

Features

  • Added a 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.

Version 1.12.2

26 Dec 08:56
Compare
Choose a tag to compare

Fixes

  • Fixed {% 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.
  • 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 using liquid.future.Environment, interrupts follow Shopify/Liquid behavior introduced in #1818. Python Liquid's default environment is unchanged.

Version 1.12.1

13 Feb 08:12
Compare
Choose a tag to compare

Fixes

  • Fixed handling of {% 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.

Version 1.12.0

07 Feb 08:30
Compare
Choose a tag to compare

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, an IndexError would have been raised when attempting to write to the cache. See #148.

Features

  • Added make_choice_loader(), a factory function that returns a ChoiceLoader or CachingChoiceLoader depending on its arguments. (docs, source)
  • Added make_file_system_loader(), a factory function that returns a FileSystemLoader, FileExtensionLoader or CachingFileSystemLoader depending on its arguments. (docs, source)

Version 1.11.0

01 Feb 08:00
Compare
Choose a tag to compare

Fixes

  • Fixed comparing strings with <, <=, > 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

  • 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

Version 1.10.2

14 Dec 08:36
Compare
Choose a tag to compare

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.

Version 1.10.0

03 Sep 08:41
Compare
Choose a tag to compare

Features

  • Optionally disable automatic suppression of whitespace only blocks with the Environment class attribute render_whitespace_only_blocks. (docs).
  • All built-in and included "extra" tags now have a 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.

Version 1.9.4

13 Aug 11:19
Compare
Choose a tag to compare

Fixes

  • Fixed async loading of templates with the {% extends %} tag. Previously templates were being loaded synchronously, even when using render_async(). See #124.
  • Fixed handling of recursive {% extends %} tags during async static analysis. See #125.