Skip to content

Commit

Permalink
Merge branch 'main' into line_numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
jg-rp committed Dec 25, 2024
2 parents bcd515f + 415f6d9 commit a60e24a
Show file tree
Hide file tree
Showing 17 changed files with 211 additions and 87 deletions.
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: jg-rp
10 changes: 7 additions & 3 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.7.17", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]
exclude:
- os: macos-latest
python-version: "3.7"
python-version: "3.7.17"
- os: windows-latest
python-version: "3.7"
python-version: "3.7.17"
- os: macos-latest
python-version: "3.8"
- os: windows-latest
python-version: "3.8"
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
Expand Down
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

- Fixed `{% case %}` / `{% when %}` behavior. When using [`liquid.future.Environment`](https://jg-rp.github.io/liquid/api/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.

**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](https://github.com/Shopify/liquid/pull/1818). Python Liquid's default environment is unchanged.

## Version 1.12.1

**Fixes**
Expand Down
12 changes: 6 additions & 6 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
black==23.11.0
mkdocs-material==9.4.8
mkdocstrings-python==1.7.4
mkdocstrings==0.24.0
python-dateutil==2.8.2
typing_extensions==4.8.0
black==24.8.0
mkdocs-material==9.5.32
mkdocstrings-python==1.10.8
mkdocstrings==0.25.2
python-dateutil==2.9.0.post0
typing_extensions==4.12.2
1 change: 1 addition & 0 deletions liquid/builtin/filters/string.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Filter functions that operate on strings."""

from __future__ import annotations

import base64
Expand Down
3 changes: 2 additions & 1 deletion liquid/builtin/loaders/base_loader.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Base template loader."""

from __future__ import annotations

from abc import ABC
Expand Down Expand Up @@ -48,7 +49,7 @@ class BaseLoader(ABC): # noqa: B024
Attributes:
caching_loader (bool): Indicates if this loader implements its own cache.
Setting this sto `True` will cause the `Environment` to disable its cache
Setting this to `True` will cause the `Environment` to disable its cache
when initialized with a caching loader.
"""

Expand Down
43 changes: 39 additions & 4 deletions liquid/builtin/tags/tablerow_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
from liquid.ast import ChildNode
from liquid.ast import Node
from liquid.context import Context
from liquid.exceptions import BreakLoop
from liquid.exceptions import ContinueLoop
from liquid.expression import NIL
from liquid.expression import LoopExpression
from liquid.limits import to_int
Expand Down Expand Up @@ -156,6 +158,9 @@ def step(self) -> None:
class TablerowNode(Node):
"""Parse tree node for the built-in "tablerow" tag."""

interrupts = False
"""If _true_, handle `break` and `continue` interrupts inside a tablerow loop."""

__slots__ = ("tok", "expression", "block")

def __init__(
Expand Down Expand Up @@ -194,18 +199,33 @@ def render_to_output(self, context: Context, buffer: TextIO) -> Optional[bool]:
}

buffer.write('<tr class="row1">\n')
_break = False

with context.extend(namespace):
for item in tablerow:
namespace[name] = item
buffer.write(f'<td class="col{tablerow.col}">')
self.block.render(context=context, buffer=buffer)

try:
self.block.render(context=context, buffer=buffer)
except BreakLoop:
if self.interrupts:
_break = True
else:
raise
except ContinueLoop:
if not self.interrupts:
raise

buffer.write("</td>")

if tablerow.col_last and not tablerow.last:
buffer.write(f'</tr>\n<tr class="row{tablerow.row + 1}">')

buffer.write("</tr>\n")
if _break:
break

buffer.write("</tr>\n")
return True

async def render_to_output_async(
Expand All @@ -227,18 +247,33 @@ async def render_to_output_async(
}

buffer.write('<tr class="row1">\n')
_break = False

with context.extend(namespace):
for item in tablerow:
namespace[name] = item
buffer.write(f'<td class="col{tablerow.col}">')
await self.block.render_async(context=context, buffer=buffer)

try:
await self.block.render_async(context=context, buffer=buffer)
except BreakLoop:
if self.interrupts:
_break = True
else:
raise
except ContinueLoop:
if not self.interrupts:
raise

buffer.write("</td>")

if tablerow.col_last and not tablerow.last:
buffer.write(f'</tr>\n<tr class="row{tablerow.row + 1}">')

buffer.write("</tr>\n")
if _break:
break

buffer.write("</tr>\n")
return True

def children(self) -> List[ChildNode]:
Expand Down
4 changes: 1 addition & 3 deletions liquid/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,7 @@ class BuiltIn(Mapping[str, object]):
"""Mapping-like object for resolving built-in, dynamic objects."""

def __contains__(self, item: object) -> bool:
if item in ("now", "today"):
return True
return False
return item in ("now", "today")

def __getitem__(self, key: str) -> object:
if key == "now":
Expand Down
15 changes: 5 additions & 10 deletions liquid/expression.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Liquid expression objects."""

from __future__ import annotations

import sys
Expand Down Expand Up @@ -79,9 +80,7 @@ class Empty(Expression):
def __eq__(self, other: object) -> bool:
if isinstance(other, Empty):
return True
if isinstance(other, (list, dict, str)) and not other:
return True
return False
return isinstance(other, (list, dict, str)) and not other

def __repr__(self) -> str: # pragma: no cover
return "Empty()"
Expand All @@ -107,9 +106,7 @@ def __eq__(self, other: object) -> bool:
return True
if isinstance(other, (list, dict)) and not other:
return True
if isinstance(other, Blank):
return True
return False
return isinstance(other, Blank)

def __repr__(self) -> str: # pragma: no cover
return "Blank()"
Expand All @@ -131,9 +128,7 @@ class Continue(Expression):
__slots__ = ()

def __eq__(self, other: object) -> bool:
if isinstance(other, Continue):
return True
return False
return isinstance(other, Continue)

def __repr__(self) -> str: # pragma: no cover
return "Continue()"
Expand Down Expand Up @@ -1106,7 +1101,7 @@ def compare(left: object, op: str, right: object) -> bool: # noqa: PLR0911, PLR
right = right.__liquid__()

def _type_error(_left: object, _right: object) -> NoReturn:
if type(_left) != type(_right):
if type(_left) != type(_right): # noqa: E721
raise LiquidTypeError(f"invalid operator for types '{_left} {op} {_right}'")

raise LiquidTypeError(f"unknown operator: {type(_left)} {op} {type(_right)}")
Expand Down
2 changes: 2 additions & 0 deletions liquid/future/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from ..environment import Environment as DefaultEnvironment
from ..template import FutureBoundTemplate
from .filters import split
from .tags import InterruptingTablerowTag
from .tags import LaxCaseTag
from .tags import LaxIfTag
from .tags import LaxUnlessTag
Expand All @@ -31,3 +32,4 @@ def setup_tags_and_filters(self) -> None:
self.add_tag(LaxCaseTag)
self.add_tag(LaxIfTag)
self.add_tag(LaxUnlessTag)
self.add_tag(InterruptingTablerowTag)
2 changes: 2 additions & 0 deletions liquid/future/tags/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from ._case_tag import LaxCaseTag # noqa: D104
from ._if_tag import LaxIfTag
from ._tablerow_tag import InterruptingTablerowTag
from ._unless_tag import LaxUnlessTag

__all__ = (
"InterruptingTablerowTag",
"LaxCaseTag",
"LaxIfTag",
"LaxUnlessTag",
Expand Down
14 changes: 14 additions & 0 deletions liquid/future/tags/_tablerow_tag.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from liquid.builtin.tags.tablerow_tag import TablerowNode
from liquid.builtin.tags.tablerow_tag import TablerowTag


class InterruptingTablerowNode(TablerowNode):
"""A _tablerow_ node with interrupt handling enabled."""

interrupts = True


class InterruptingTablerowTag(TablerowTag):
"""A _tablerow_ tag that handles `break` and `continue` tags."""

node_class = InterruptingTablerowNode
55 changes: 55 additions & 0 deletions liquid/golden/tablerow_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,61 @@
"</tr>\n"
),
),
Case(
description="break from a tablerow loop",
template=(
r"{% tablerow n in (1..3) cols:2 %}"
r"{{n}}{% break %}{{n}}"
r"{% endtablerow %}"
),
expect='<tr class="row1">\n<td class="col1">1</td></tr>\n',
future=True,
),
Case(
description="continue from a tablerow loop",
template=(
r"{% tablerow n in (1..3) cols:2 %}"
r"{{n}}{% continue %}{{n}}"
r"{% endtablerow %}"
),
expect=(
'<tr class="row1">\n'
'<td class="col1">1</td>'
'<td class="col2">2</td>'
"</tr>\n"
'<tr class="row2">'
'<td class="col1">3</td>'
"</tr>\n"
),
future=True,
),
Case(
description="break from a tablerow loop inside a for loop",
template=(
r"{% for i in (1..2) -%}\n"
r"{% for j in (1..2) -%}\n"
r"{% tablerow k in (1..3) %}{% break %}{% endtablerow -%}\n"
r"loop j={{ j }}\n"
r"{% endfor -%}\n"
r"loop i={{ i }}\n"
r"{% endfor -%}\n"
r"after loop\n"
),
expect="\n".join(
[
r'\n\n<tr class="row1">',
r'<td class="col1"></td></tr>',
r'\nloop j=1\n\n<tr class="row1">',
r'<td class="col1"></td></tr>',
r'\nloop j=2\n\nloop i=1\n\n\n<tr class="row1">',
r'<td class="col1"></td></tr>',
r'\nloop j=1\n\n<tr class="row1">',
r'<td class="col1"></td></tr>',
r"\nloop j=2\n\nloop i=2\n\nafter loop\n",
]
),
future=True,
),
# Case(
# description="cols is non number string",
# template=(
Expand Down
1 change: 0 additions & 1 deletion liquid/parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -615,7 +615,6 @@ def parse_filter(self, stream: TokenStream) -> expression.Filter:
filter_name = stream.current.value
stream.next_token()

#
args = []
kwargs = {}

Expand Down
Loading

0 comments on commit a60e24a

Please sign in to comment.