Skip to content
Closed

AI spam #2177

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ dist/
htmlcov/
.tox/
docs/_build/
.venv/
6 changes: 5 additions & 1 deletion src/jinja2/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -1089,7 +1089,11 @@ def sync_do_slice(
end = offset + (slice_number + 1) * items_per_slice
tmp = seq[start:end]

if fill_with is not None and slice_number >= slices_with_extra:
if (
fill_with is not None
and slices_with_extra > 0
and slice_number >= slices_with_extra
):
tmp.append(fill_with)

yield tmp
Expand Down
84 changes: 84 additions & 0 deletions tests/test_slice_fill_fix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""Tests for slice filter fix: fill_with should not be applied when
iterable length is evenly divisible by slice count.

Regression test for https://github.com/pallets/jinja/issues/2118
"""

import pytest

from jinja2 import Environment


@pytest.fixture
def env():
return Environment()


class TestSliceFillWithEvenDivision:
"""slice(x, fill) when len % slices == 0 should not add fill values."""

def test_slice_4_items_4_slices_with_fill(self, env):
"""4 items into 4 slices: each gets exactly 1 item, no fill."""
tmpl = env.from_string("{{ [1, 2, 3, 4]|slice(4, 'foo')|list }}")
result = tmpl.render()
assert result == "[[1], [2], [3], [4]]"

def test_slice_6_items_3_slices_with_fill(self, env):
"""6 items into 3 slices: each gets exactly 2 items, no fill."""
tmpl = env.from_string("{{ [1, 2, 3, 4, 5, 6]|slice(3, 'x')|list }}")
result = tmpl.render()
assert result == "[[1, 2], [3, 4], [5, 6]]"

def test_slice_8_items_4_slices_with_fill(self, env):
"""8 items into 4 slices: each gets exactly 2 items, no fill."""
tmpl = env.from_string("{{ [1,2,3,4,5,6,7,8]|slice(4, 'z')|list }}")
result = tmpl.render()
assert result == "[[1, 2], [3, 4], [5, 6], [7, 8]]"

def test_slice_1_item_1_slice_with_fill(self, env):
"""1 item into 1 slice: no fill needed."""
tmpl = env.from_string("{{ [42]|slice(1, 'fill')|list }}")
result = tmpl.render()
assert result == "[[42]]"

def test_slice_10_items_5_slices_with_fill(self, env):
"""10 items into 5 slices: each gets exactly 2 items, no fill."""
tmpl = env.from_string("{{ [1,2,3,4,5,6,7,8,9,10]|slice(5, 'fill')|list }}")
result = tmpl.render()
assert result == "[[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]"


class TestSliceFillWithRemainder:
"""slice(x, fill) when len % slices != 0 should still fill correctly."""

def test_slice_5_items_3_slices_with_fill(self, env):
"""5 items into 3 slices: first 2 slices get 2 items, last gets 1 + fill."""
tmpl = env.from_string("{{ [1,2,3,4,5]|slice(3, 'x')|list }}")
result = tmpl.render()
assert result == "[[1, 2], [3, 4], [5, 'x']]"

def test_slice_7_items_3_slices_with_fill(self, env):
"""7 items into 3 slices: first slice gets 3, rest get 2+fill."""
tmpl = env.from_string("{{ [1,2,3,4,5,6,7]|slice(3, 'f')|list }}")
result = tmpl.render()
assert result == "[[1, 2, 3], [4, 5, 'f'], [6, 7, 'f']]"

def test_slice_3_items_4_slices_with_fill(self, env):
"""3 items into 4 slices: first 3 get 1 item each, last gets fill."""
tmpl = env.from_string("{{ [1,2,3]|slice(4, 'x')|list }}")
result = tmpl.render()
assert result == "[[1], [2], [3], ['x']]"


class TestSliceNoFill:
"""slice(x) without fill_with should work the same regardless."""

def test_slice_4_items_4_slices_no_fill(self, env):
tmpl = env.from_string("{{ [1, 2, 3, 4]|slice(4)|list }}")
result = tmpl.render()
assert result == "[[1], [2], [3], [4]]"

def test_slice_7_items_3_slices_no_fill(self, env):
tmpl = env.from_string("{{ [1,2,3,4,5,6,7]|slice(3)|list }}")
result = tmpl.render()
assert result == "[[1, 2, 3], [4, 5], [6, 7]]"
Loading