用途
该技能用于指导创建独立的 Python 脚本或单文件自动化工具。资料明确要求:在创建任何独立 Python 脚本或单文件自动化之前,应始终先加载本技能,不要直接编写 Python 脚本。
本技能是 myai 的 engineering-principles 的扩展,需先加载后者;using-my-skills 与 engineering-principles 假定已通过 myai bootstrap 加载。engineering-principles 提供与语言无关的工程哲学,本技能只覆盖 Python 特有的脚本模式:PEP 723 内联元数据、uv run --script、typer CLI 以及单文件约定。
主要能力与约定
单文件脚本使用 PEP 723 内联元数据声明依赖,并通过 uv run --script 执行。writing-python-code 中的全部类型安全与错误处理规则同样适用。
何时使用单脚本(PEP 723)而非完整项目,资料给出的判断依据包括:
- 单脚本:一个任务一个文件;不需要测试;用于模板化、生成或自动化;可直接运行 ./script.py;依赖写在脚本头部;约 500 行以内。
- 完整项目:多个功能;需要测试;带 UI 或 API 的应用;通过 uv run poe app 运行;依赖写在 pyproject.toml;会增长到约 500 行以上。
使用方式
目录布局示例:
app/
├── script.py # Self-contained with inline deps
├── template.html # Jinja2 templates (if generating text)
├── schema.json # Validation schema (if validating configs)
├── configs/ # Configuration files (if multiple are needed)
├── pyproject.toml # Tool config only (ruff, basedpyright)
└── .gitignore
脚本模板(保留原始代码):
#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.14"
# dependencies = [
# "typer>=0.12.0",
# "rusty-results>=1.1.1",
# # Add as needed:
# # "jinja2>=3.1.0", # For text output generation
# # "pyyaml>=6.0.0", # For YAML config loading
# # "jsonschema>=4.20.0", # For config validation
# ]
# ///
import sys
from pathlib import Path
from typing import Final, TypedDict, Required
import typer
from rusty_results import Result, Ok, Err
# =============================================================================
# Constants & Types
# =============================================================================
TEMPLATE_PATH: Final[Path] = Path(__file__).parent / "template.html"
class ItemConfig(TypedDict):
name: Required[str]
# ...
# =============================================================================
# Business Logic
# =============================================================================
def load_config(path: Path) -> Result[ItemConfig, str]: ...
def process_item(config: ItemConfig) -> Result[str, str]: ...
# =============================================================================
# CLI Interface
# =============================================================================
app = typer.Typer(help="Description", add_completion=False, context_settings={"help_option_names": ["-h", "--help"]})
@app.command()
def main_command() -> None:
result = do_work()
if result.is_err:
typer.echo(f"Error: {result.unwrap_err()}", err=True)
sys.exit(1)
typer.echo(result.unwrap())
if __name__ == "__main__":
try:
app()
except KeyboardInterrupt:
sys.exit(130) # No traceback on Ctrl+C
工具配置(pyproject.toml):不需要 [project] 段,只需 ruff 与 basedpyright 配置:
[tool.basedpyright]
pythonVersion = "3.14"
typeCheckingMode = "strict"
reportAny = "error"
[tool.ruff]
line-length = 120
target-version = "py314"
[tool.ruff.lint]
extend-select = ["E", "F", "I", "N", "UP", "S", "B", "A", "C4", "RUF"]
ignore = ["S101", "B008", "RUF001"]
CLI 说明:所有使用 uv 的脚本都应使用 typer。仅当脚本必须在没有任何外部依赖的情况下运行(仅标准库、不使用 uv)时,才使用 argparse。始终向 typer.Typer() 传入 context_settings={"help_option_names": ["-h", "--help"]},因为 typer 默认只支持 --help,而用户期望 -h 也能工作。
Ctrl+C 处理:脚本在 Ctrl+C 时不得输出 traceback。上述模板入口捕获 KeyboardInterrupt 并以退出码 130 退出(Unix 约定:128 + 信号 2)。如果脚本会派生子进程,应始终使用 start_new_session=True,以便 Ctrl+C 能终止整个进程树;子进程关闭模式参见 setting-up-python-projects 技能。
适用场景
适用于一次性任务、模板化与文本生成、配置校验、单文件自动化等场景,尤其是脚本规模在约 500 行以内、无需测试的情况。
限制与相关技能
当脚本增长到约 500 行以上并需要完整项目布局时,应改用 setting-up-python-projects 技能。相关技能还包括:engineering-principles(父技能,与语言无关的哲学)、writing-python-code(Python 特有编码规则,同样适用于脚本,涵盖类型系统、错误处理、异步模式)。
关于收费、价格、平台支持范围等具体信息,资料暂未提供。