chore: 提高测试覆盖率.

This commit is contained in:
2026-06-21 15:31:53 +08:00
parent 939cd724ec
commit 7de55614a6
6 changed files with 522 additions and 62 deletions
+90 -1
View File
@@ -20,7 +20,10 @@ PyFlowX 把"任务依赖"这件事做到极致简单:**参数名就是依赖
- **自动分层** —— Kahn 算法分组,同层任务可并行
- **重试与超时** —— 每个任务独立配置 `retries``timeout`
- **断点续跑** —— `MemoryBackend` / `JSONBackend`,成功结果可缓存复用
- **可观测** —— `on_event` 回调、`dry_run` 预览、Mermaid 可视化
- **命令任务** —— `cmd` 参数直接执行外部命令,支持列表/shell/可调用对象
- **条件执行** —— `conditions` 参数按平台、环境变量、应用安装等条件跳过任务
- **CLI 运行器** —— `CliRunner` 把多个图映射为命令行子命令,替代 Makefile
- **可观测** —— `on_event` 回调、`dry_run` 预览、`verbose` 生命周期日志、Mermaid 可视化
- **零运行时依赖** —— 仅依赖标准库(3.8 需 `graphlib_backport`
- **100% 测试覆盖** —— 分支覆盖率达 100%
@@ -67,15 +70,24 @@ print(report["double"]) # [2, 4, 6]
px.TaskSpec(
name="fetch_user", # 唯一标识
fn=fetch_user, # 同步或异步函数
cmd=["curl", "..."], # 或: 执行命令(覆盖 fn
depends_on=("auth",), # 依赖的任务名
args=(uid,), # 静态位置参数(追加在注入参数后)
kwargs={"timeout": 30}, # 静态关键字参数
retries=3, # 失败重试次数(0 = 仅一次)
timeout=30.0, # 超时秒数(None = 不限制)
tags=("api", "user"), # 自由标签,用于子图过滤
conditions=(is_prod,), # 条件函数列表(全部为 True 才执行)
cwd=Path("/tmp"), # 命令工作目录(仅 cmd 模式)
verbose=True, # 打印命令输出(仅 cmd 模式)
)
```
支持两种任务形态:
- **函数任务**`fn`):普通 Python 函数,参数名驱动自动注入
- **命令任务**`cmd`):执行外部命令,支持 `list[str]``str`shell)、`Callable` 三种形态
### Graph —— DAG 构建
```python
@@ -101,6 +113,7 @@ report = px.run(
strategy="async", # sequential | thread | async
max_workers=8, # thread 策略的线程池大小
dry_run=False, # True = 仅打印计划
verbose=False, # True = 打印任务生命周期日志
on_event=callback, # 状态转换回调
state=px.JSONBackend("state.json"), # 断点续跑后端
)
@@ -151,6 +164,82 @@ def fetch_user(uid: int) -> dict: # uid 来自 TaskSpec.args
所有策略都遵循 `retries``timeout`、上下文注入、状态后端,并发出 `TaskEvent`
## 命令任务
`TaskSpec``cmd` 参数支持执行外部命令,无需包装 Python 函数:
```python
graph = px.Graph.from_specs([
# 命令列表(推荐,参数无需转义)
px.TaskSpec("list_files", cmd=["ls", "-la"]),
# shell 字符串(支持管道、重定向)
px.TaskSpec("check_git", cmd="git status | head"),
# 带工作目录与超时
px.TaskSpec("build", cmd=["make", "all"], cwd=Path("/project"), timeout=300),
])
```
`verbose=True` 时打印执行的命令、工作目录、返回码与输出;`verbose=False` 时静默执行(失败信息仍包含 stderr)。
## 条件执行
`conditions` 参数让任务按条件跳过(标记为 `SKIPPED`):
```python
from pyflowx.conditions import IS_WINDOWS, BuiltinConditions
graph = px.Graph.from_specs([
# 仅在 Windows 上运行
px.TaskSpec("win_only", cmd=["dir"], conditions=(IS_WINDOWS,)),
# 仅在 git 已安装时运行
px.TaskSpec(
"git_check",
cmd=["git", "--version"],
conditions=(BuiltinConditions.HAS_INSTALLED("git"),),
),
# 组合条件
px.TaskSpec(
"prod_deploy",
fn=deploy,
conditions=(
BuiltinConditions.ENV_VAR_EQUALS("ENV", "prod"),
BuiltinConditions.HAS_INSTALLED("docker"),
),
),
])
```
内置条件:`IS_WINDOWS` / `IS_LINUX` / `IS_MACOS` / `IS_POSIX` / `PYTHON_VERSION` / `HAS_INSTALLED` / `ENV_VAR_EXISTS` / `ENV_VAR_EQUALS` / `NOT` / `AND` / `OR`
## CLI 运行器
`CliRunner` 把多个 Graph 映射为命令行子命令,适合构建项目专属构建工具(替代 Makefile):
```python
runner = px.CliRunner(
strategy="sequential",
description="My Build Tool",
graphs={
"clean": clean_graph,
"build": build_graph,
"test": test_graph,
},
)
runner.run_cli() # 解析 sys.argv 并执行
```
命令行用法:
```bash
python build.py clean # 执行 clean 图
python build.py build --strategy thread # 覆盖执行策略
python build.py test --dry-run # 仅打印执行计划
python build.py --list # 列出所有命令
python build.py --quiet # 静默模式
```
`verbose=True`(默认)时打印任务生命周期(开始/成功/失败/跳过)与命令输出;`--quiet` 关闭。
## 示例
仓库 `examples/` 目录包含完整示例: