135 lines
3.8 KiB
Python
135 lines
3.8 KiB
Python
import functools
|
|
import logging
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from pytest import fixture
|
|
|
|
import ray
|
|
from ray.data._internal.progress.progress_bar import ProgressBar
|
|
|
|
|
|
@fixture(params=[True, False])
|
|
def enable_tqdm_ray(request):
|
|
context = ray.data.DataContext.get_current()
|
|
original_use_ray_tqdm = context.use_ray_tqdm
|
|
context.use_ray_tqdm = request.param
|
|
yield request.param
|
|
context.use_ray_tqdm = original_use_ray_tqdm
|
|
|
|
|
|
def test_progress_bar(enable_tqdm_ray):
|
|
total = 10
|
|
# Used to record the total value of the bar at close
|
|
total_at_close = 0
|
|
|
|
def patch_close(bar):
|
|
nonlocal total_at_close
|
|
total_at_close = 0
|
|
original_close = bar.close
|
|
|
|
@functools.wraps(original_close)
|
|
def wrapped_close():
|
|
nonlocal total_at_close
|
|
total_at_close = bar.total
|
|
|
|
bar.close = wrapped_close
|
|
|
|
# Test basic usage
|
|
pb = ProgressBar("", total, "unit", enabled=True)
|
|
assert pb._bar is not None
|
|
patch_close(pb._bar)
|
|
for _ in range(total):
|
|
pb.update(1)
|
|
pb.close()
|
|
|
|
assert pb._progress == total
|
|
assert total_at_close == total
|
|
|
|
# Test if update() exceeds the original total, the total will be updated.
|
|
pb = ProgressBar("", total, "unit", enabled=True)
|
|
assert pb._bar is not None
|
|
patch_close(pb._bar)
|
|
new_total = total * 2
|
|
for _ in range(new_total):
|
|
pb.update(1)
|
|
pb.close()
|
|
|
|
assert pb._progress == new_total
|
|
assert total_at_close == new_total
|
|
|
|
# Test that if the bar is not complete at close(), the total will be updated.
|
|
pb = ProgressBar("", total, "unit")
|
|
assert pb._bar is not None
|
|
patch_close(pb._bar)
|
|
new_total = total // 2
|
|
for _ in range(new_total):
|
|
pb.update(1)
|
|
pb.close()
|
|
|
|
assert pb._progress == new_total
|
|
assert total_at_close == new_total
|
|
|
|
# Test updating the total
|
|
pb = ProgressBar("", total, "unit", enabled=True)
|
|
assert pb._bar is not None
|
|
patch_close(pb._bar)
|
|
new_total = total * 2
|
|
pb.update(0, new_total)
|
|
|
|
assert pb._bar.total == new_total
|
|
pb.update(total + 1, total)
|
|
assert pb._bar.total == total + 1
|
|
pb.close()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"name, expected_description, max_line_length, should_emit_warning",
|
|
[
|
|
("Op", "Op", 2, False),
|
|
("Op->Op", "Op->Op", 5, False),
|
|
("Op->Op->Op", "Op->...->Op", 9, True),
|
|
("Op->Op->Op", "Op->Op->Op", 10, False),
|
|
# Test case for https://github.com/ray-project/ray/issues/47679.
|
|
("spam", "spam", 1, False),
|
|
],
|
|
)
|
|
def test_progress_bar_truncates_chained_operators(
|
|
name,
|
|
expected_description,
|
|
max_line_length,
|
|
should_emit_warning,
|
|
caplog,
|
|
propagate_logs,
|
|
):
|
|
with patch.object(ProgressBar, "MAX_NAME_LENGTH", max_line_length):
|
|
pb = ProgressBar(name, None, "unit")
|
|
|
|
assert pb.get_description() == expected_description
|
|
if should_emit_warning:
|
|
assert any(
|
|
record.levelno == logging.WARNING
|
|
and "Truncating long operator name" in record.message
|
|
for record in caplog.records
|
|
), caplog.records
|
|
|
|
|
|
def test_progress_bar_tqdm_not_installed(enable_tqdm_ray):
|
|
"""Test behavior when tqdm package is not installed."""
|
|
with patch("sys.stdout.isatty", return_value=True):
|
|
# Mock tqdm not being installed
|
|
with patch("ray.data._internal.progress.progress_bar.tqdm", None):
|
|
pb = ProgressBar("test", 100, "unit", enabled=True)
|
|
if enable_tqdm_ray:
|
|
# tqdm_ray still works (part of Ray, no tqdm dependency)
|
|
assert pb._bar is not None
|
|
else:
|
|
# No progress bar available (interactive, so no logging fallback)
|
|
assert pb._bar is None
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
|
|
sys.exit(pytest.main(["-v", __file__]))
|