bump version to 0.2.9
Release / build (push) Failing after 16m3s
Release / publish-pypi (push) Has been skipped
Release / release (push) Has been skipped

This commit is contained in:
2026-06-27 16:42:10 +08:00
parent 7fa97a01e3
commit 65dcbcbf62
9 changed files with 75 additions and 21 deletions
+41
View File
@@ -3,6 +3,7 @@
from __future__ import annotations
import asyncio
import logging
import tempfile
import threading
import time
@@ -93,6 +94,46 @@ def test_retries_then_succeeds() -> None:
assert attempts["n"] == 3
def test_retries_with_delay() -> None:
"""测试带delay的重试会实际等待。"""
attempts = {"n": 0}
start_time = time.time()
def flaky() -> str:
attempts["n"] += 1
if attempts["n"] < 2:
raise RuntimeError("not yet")
return "ok"
graph = px.Graph.from_specs([
px.TaskSpec("flaky", flaky, retry=px.RetryPolicy(max_attempts=2, delay=0.1)),
])
report = px.run(graph, strategy="sequential")
elapsed = time.time() - start_time
assert report.success
assert elapsed >= 0.1 # 应有至少0.1秒的等待时间
assert attempts["n"] == 2
def test_timeout_then_retry_async(caplog: pytest.LogCaptureFixture) -> None:
"""测试超时后可以重试,并记录warning日志。"""
async def slow_task() -> str:
await asyncio.sleep(10) # 会触发超时
return "ok"
graph = px.Graph.from_specs([
px.TaskSpec("slow", slow_task, timeout=0.2, retry=px.RetryPolicy(max_attempts=2)),
])
with caplog.at_level(logging.WARNING, logger="pyflowx"):
with pytest.raises(px.TaskFailedError) as exc_info:
_ = px.run(graph, strategy="async")
assert exc_info.value.attempts == 2
assert "timed out" in str(exc_info.value.cause)
# 应有超时重试的warning日志
assert any("timed out" in r.message for r in caplog.records)
def test_retries_exhausted() -> None:
def always_fail() -> None:
raise RuntimeError("nope")
-7
View File
@@ -490,13 +490,6 @@ def test_soft_depends_on_skipped_injects_none() -> None:
assert report["b"] == "skipped=None"
def test_soft_depends_on_with_defaults_for_missing() -> None:
"""软依赖引用不存在的任务时使用 defaults(但当前实现会校验软依赖必须存在)。"""
# 注意:当前实现中,软依赖也必须在图中存在
# 所以无法测试软依赖缺失的场景
# 只能测试软依赖成功时注入其值的情况
# ---------------------------------------------------------------------- #
# hooks 异常处理测试
# ---------------------------------------------------------------------- #
+15
View File
@@ -191,6 +191,21 @@ def test_json_backend_non_dict_content_ignored(tmp_path: Path) -> None:
assert dict(b.load()) == {}
def test_json_backend_old_format_migration(tmp_path: Path) -> None:
"""旧格式JSON(纯值)应被迁移为新格式(带ts)。"""
path = tmp_path / "state.json"
# 写入旧格式:纯值
old_data = {"a": 1, "b": "value"}
_ = path.write_text(json.dumps(old_data))
b = JSONBackend(str(path))
# 读取后应有ts字段
assert "a" in b._store
assert "value" in b._store["a"]
assert "ts" in b._store["a"]
assert b._store["a"]["value"] == 1
# ---------------------------------------------------------------------- #
# JSONBackend TTL 测试
# ---------------------------------------------------------------------- #
+6
View File
@@ -37,6 +37,12 @@ def test_spec_zero_timeout_rejected() -> None:
TaskSpec("a", _fn, timeout=0)
def test_spec_negative_timeout_rejected() -> None:
"""负数timeout应被拒绝。"""
with pytest.raises(ValueError, match="timeout"):
TaskSpec("a", _fn, timeout=-1.0)
def test_spec_self_dependency_rejected() -> None:
with pytest.raises(ValueError, match="depend on itself"):
TaskSpec("a", _fn, depends_on=("a",))