Skip to content

Commit

Permalink
[lib,test] Added ImageIterator.loop_no property
Browse files Browse the repository at this point in the history
- Add: Added `loop_no` and `_loop_no` to `ImageIterator` to expose iteration repeat countdown.
- Add: Added tests for `loop_no`.
- Change: `.tui.render.render_frames()` now uses `loop_no` instead of directly accessing the underlying generator's locals.
  • Loading branch information
AnonymouX47 committed Jun 24, 2022
1 parent ee64cee commit 7de6b4a
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [lib] `term_image.TermImageWarning`; pacage specific warning category ([#50]).
- [lib] `term_image.set_query_timeout()` to set global query timeout ([3b658f3]).
- [lib] Auto background color i.e using the terminal's default BG color for transparent images ([#54])
- [lib] `ImageIterator.loop_no` property.
- [cli] `--style` command-line option for render style selection ([#37]).
- [cli] `kitty` render style choice for the `--style` command-line option ([#39]).
- [cli] `--force-style` to bypass render style support checks ([#44]).
Expand Down
18 changes: 14 additions & 4 deletions term_image/image/common.py
Expand Up @@ -2004,6 +2004,7 @@ def __init__(
self._cached = (
cached if isinstance(cached, bool) else image.n_frames <= cached
) and repeat != 1
self._loop_no = None
self._animator = image._renderer(
self._animate, alpha, fmt, style_args, check_size=False
)
Expand Down Expand Up @@ -2033,11 +2034,20 @@ def __next__(self) -> None:
raise

def __repr__(self) -> None:
return "{}(image={!r}, repeat={}, format={!r}, cached={})".format(
return "{}(image={!r}, repeat={}, format={!r}, cached={}, loop_no={})".format(
type(self).__name__,
*self.__dict__.values(),
)

loop_no = property(
lambda self: self._loop_no,
doc="""Iteration repeat countdown
Changes on the first iteration of each loop, except for infinite iteration
where it's always ``-1``.
""",
)

def close(self) -> None:
"""Closes the iterator and releases resources used.
Expand Down Expand Up @@ -2097,7 +2107,7 @@ def _animate(
self._img = img # For cleanup
image = self._image
cached = self._cached
repeat = self._repeat
self._loop_no = repeat = self._repeat
if cached:
cache = [(None,) * 2] * image.n_frames

Expand All @@ -2119,7 +2129,7 @@ def _animate(
except EOFError:
image._seek_position = n = 0
if repeat > 0: # Avoid infinitely large negative numbers
repeat -= 1
self._loop_no = repeat = repeat - 1
if cached:
break
continue
Expand Down Expand Up @@ -2161,7 +2171,7 @@ def _animate(

image._seek_position = n = 0
if repeat > 0: # Avoid infinitely large negative numbers
repeat -= 1
self._loop_no = repeat = repeat - 1

# For consistency in behaviour
if img is image._source:
Expand Down
2 changes: 1 addition & 1 deletion term_image/tui/render.py
Expand Up @@ -321,7 +321,7 @@ def render_frames(
output.put(
(
next(animator),
animator._animator.gi_frame.f_locals["repeat"],
animator._loop_no,
image.tell(),
size,
image.rendered_size,
Expand Down
22 changes: 22 additions & 0 deletions tests/test_image_iterator.py
Expand Up @@ -228,6 +228,28 @@ def test_formatting():
assert next(image_it).partition("\n")[0] == " " * (_size[0] + 2)


def test_loop_no():
for cached in (False, True):
image_it = ImageIterator(gif_image, 2, cached=cached)
assert image_it.loop_no is None

next(image_it)
assert image_it.loop_no == 2
for _ in range(gif_image.n_frames - 1):
next(image_it)
assert image_it.loop_no == 2

next(image_it)
assert image_it.loop_no == 1
for _ in range(gif_image.n_frames - 1):
next(image_it)
assert image_it.loop_no == 1

with pytest.raises(StopIteration):
next(image_it)
assert image_it.loop_no == 0


def test_close():
image_it = ImageIterator(gif_image, 1)
next(image_it)
Expand Down

0 comments on commit 7de6b4a

Please sign in to comment.