refactor: 全面迁移至 Python 3.9+ 原生泛型类型语法
- 将所有 `Optional[T]` 替换为 `T | None` - 将所有 `List[T]`/`Dict[K, V]`/`Tuple[Ts, ...]` 替换为对应原生泛型 - 调整类型导入,移除冗余的 typing 导入项 - 更新项目依赖,添加 typing-extensions 兼容旧版本 Python - 重构部分函数签名与内部实现以匹配新类型语法
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
"""Tests for executors module edge cases."""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
import pyflowx as px
|
||||
from pyflowx.task import TaskStatus
|
||||
|
||||
# 跨平台的 echo 命令
|
||||
if sys.platform == "win32":
|
||||
ECHO_CMD = ["cmd", "/c", "echo"]
|
||||
else:
|
||||
ECHO_CMD = ["echo"]
|
||||
|
||||
|
||||
def test_execute_sync_with_timeout():
|
||||
"""Test execute task with timeout correctly."""
|
||||
# Note: timeout for Python functions only works in async strategy
|
||||
# For sync functions, timeout is not enforced in sequential strategy
|
||||
# This test verifies that the task runs without timeout error
|
||||
spec = px.TaskSpec("quick", fn=lambda: "result", timeout=10)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
|
||||
# Should succeed without timeout error
|
||||
report = px.run(graph, strategy="sequential")
|
||||
assert report.success
|
||||
|
||||
|
||||
def test_execute_async_with_timeout():
|
||||
"""Test execute async task with timeout correctly."""
|
||||
|
||||
async def slow_async_function():
|
||||
await asyncio.sleep(2)
|
||||
return "result"
|
||||
|
||||
spec = px.TaskSpec("slow_async", fn=slow_async_function, timeout=0.5)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
|
||||
# This should timeout
|
||||
with pytest.raises(px.TaskFailedError):
|
||||
px.run(graph, strategy="async")
|
||||
|
||||
|
||||
def test_verbose_event_callback_running():
|
||||
"""Test verbose event callback for RUNNING status."""
|
||||
# Create a graph with verbose callback
|
||||
spec = px.TaskSpec("test", fn=lambda: "result", verbose=True)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
report = px.run(graph, strategy="sequential")
|
||||
# Should print without error
|
||||
assert report.success
|
||||
|
||||
|
||||
def test_verbose_event_callback_success():
|
||||
"""Test verbose event callback for SUCCESS status."""
|
||||
# Create a graph with verbose callback
|
||||
spec = px.TaskSpec("test", fn=lambda: "result", verbose=True)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
report = px.run(graph, strategy="sequential")
|
||||
# Should print without error
|
||||
assert report.success
|
||||
|
||||
|
||||
def test_verbose_event_callback_failed():
|
||||
"""Test verbose event callback for FAILED status."""
|
||||
# Create a graph with verbose callback and failing task
|
||||
|
||||
def raise_error():
|
||||
raise ValueError("test error")
|
||||
|
||||
spec = px.TaskSpec("test", fn=raise_error, verbose=True)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
|
||||
# Should print without error
|
||||
with pytest.raises(px.TaskFailedError):
|
||||
px.run(graph, strategy="sequential")
|
||||
|
||||
|
||||
def test_verbose_event_callback_skipped():
|
||||
"""Test verbose event callback for SKIPPED status."""
|
||||
# Create a graph with verbose callback and skipped task
|
||||
spec = px.TaskSpec(
|
||||
"test",
|
||||
fn=lambda: "result",
|
||||
conditions=(lambda: False,),
|
||||
verbose=True,
|
||||
)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
report = px.run(graph, strategy="sequential")
|
||||
# Should print without error
|
||||
assert report.success
|
||||
|
||||
|
||||
def test_execute_sync_with_retries():
|
||||
"""Test execute task with retries."""
|
||||
|
||||
call_count = 0
|
||||
|
||||
def failing_function():
|
||||
nonlocal call_count
|
||||
call_count += 1
|
||||
if call_count < 3:
|
||||
raise ValueError("temporary error")
|
||||
return "success"
|
||||
|
||||
spec = px.TaskSpec("retry_test", fn=failing_function, retries=3)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
|
||||
# Should succeed after retries
|
||||
report = px.run(graph, strategy="sequential")
|
||||
assert report.success
|
||||
assert report.results["retry_test"].attempts == 3
|
||||
|
||||
|
||||
def test_execute_async_with_retries():
|
||||
"""Test execute async task with retries."""
|
||||
|
||||
call_count = 0
|
||||
|
||||
async def failing_async_function():
|
||||
nonlocal call_count
|
||||
call_count += 1
|
||||
if call_count < 3:
|
||||
raise ValueError("temporary error")
|
||||
return "success"
|
||||
|
||||
spec = px.TaskSpec("retry_async_test", fn=failing_async_function, retries=3)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
|
||||
# Should succeed after retries
|
||||
report = px.run(graph, strategy="async")
|
||||
assert report.success
|
||||
assert report.results["retry_async_test"].attempts == 3
|
||||
|
||||
|
||||
def test_execute_sync_skip_on_condition():
|
||||
"""Test execute task skips task when condition is false."""
|
||||
spec = px.TaskSpec(
|
||||
"skip_test",
|
||||
fn=lambda: "result",
|
||||
conditions=(lambda: False,),
|
||||
)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
|
||||
report = px.run(graph, strategy="sequential")
|
||||
assert report.success
|
||||
assert report.results["skip_test"].status == TaskStatus.SKIPPED
|
||||
|
||||
|
||||
def test_execute_async_skip_on_condition():
|
||||
"""Test execute async task skips task when condition is false."""
|
||||
spec = px.TaskSpec(
|
||||
"skip_async_test",
|
||||
fn=lambda: "result",
|
||||
conditions=(lambda: False,),
|
||||
)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
|
||||
report = px.run(graph, strategy="async")
|
||||
assert report.success
|
||||
assert report.results["skip_async_test"].status == TaskStatus.SKIPPED
|
||||
|
||||
|
||||
def test_execute_sync_with_error():
|
||||
"""Test execute task handles errors correctly."""
|
||||
|
||||
def error_function():
|
||||
raise ValueError("test error")
|
||||
|
||||
spec = px.TaskSpec("error_test", fn=error_function)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
|
||||
with pytest.raises(px.TaskFailedError):
|
||||
px.run(graph, strategy="sequential")
|
||||
|
||||
|
||||
def test_execute_async_with_error():
|
||||
"""Test execute async task handles errors correctly."""
|
||||
|
||||
async def error_async_function():
|
||||
raise ValueError("test error")
|
||||
|
||||
spec = px.TaskSpec("error_async_test", fn=error_async_function)
|
||||
graph = px.Graph.from_specs([spec])
|
||||
|
||||
with pytest.raises(px.TaskFailedError):
|
||||
px.run(graph, strategy="async")
|
||||
Reference in New Issue
Block a user