Python Sensei — Best Practices Enforcer
Version: 1.1.0 | Author: Shadows Company | License: MIT
WHEN TO TRIGGER
- - Writing new Python code
- Reviewing existing Python code
- User says "python review", "best practices", "clean up this python"
- Refactoring Python modules
- Setting up a new Python project
WHEN NOT TO TRIGGER
- - Quick scripts where quality doesn't matter
- User explicitly says "just make it work"
- Non-Python code
PREREQUISITES
Requires python or python3 on PATH for syntax checking (python -m py_compile) and test execution (python -m pytest).
Optional tools (auto-detected, recommendations adapt accordingly):
- - pytest — test execution (
pip install pytest) - mypy or pyright — static type checking
- ruff — fast linting and formatting (
pip install ruff)
The skill checks which tools are available and tailors its recommendations to the user's installed toolchain.
CODE STANDARDS
1. Module Structure
CODEBLOCK0
Rules:
- - Max 500 lines per module — split if larger
- Imports grouped: stdlib → third-party → local (blank line between each group)
- Constants at top, ALL_CAPS naming
- One class per file for complex classes
2. Functions
CODEBLOCK1
Rules:
- - Type hints on all public functions (params + return)
- Keyword-only args after
* for clarity - INLINECODE7 return type when failure is normal (not exceptions)
- Docstrings on public functions only
- Max 30 lines per function — extract helpers if larger
3. Data Models
CODEBLOCK2
Rules:
- -
@dataclass for simple models, Pydantic for validation-heavy models - INLINECODE9 for states (JSON-serializable)
- Always include
to_dict() for serialization - Immutable by default (
frozen=True when appropriate)
4. Error Handling
CODEBLOCK3
Rules:
- - Catch specific exceptions, never bare INLINECODE12
- Only validate at system boundaries (user input, external APIs)
- Trust internal code — do not add defensive checks everywhere
- Use
logging module, not print() for errors
5. Async Patterns
CODEBLOCK4
Rules:
- -
async with for resource management - INLINECODE16 for parallel I/O
- INLINECODE17 to handle partial failures
- Never mix sync and async I/O in the same function
6. Testing
CODEBLOCK5
Rules:
- - Test file: INLINECODE18
- Test names describe the scenario: INLINECODE19
- One assertion per test (prefer)
- Use
pytest.raises for expected exceptions - Use fixtures for shared setup
7. Project Setup
CODEBLOCK6
INLINECODE21 over setup.py. Pin major versions in requirements.txt.
ANTI-PATTERNS TO FLAG
| Anti-Pattern | Fix |
|---|
| INLINECODE24 | Explicit imports |
| Mutable default args |
field(default_factory=list) |
| Global mutable state | Dependency injection |
| Nested try/except | Extract and flatten |
| String concatenation for SQL | Parameterized queries |
|
type() checks |
isinstance() |
|
os.path |
pathlib.Path |
|
requests (sync) |
httpx (async-ready) |
SECURITY CONSIDERATIONS
This skill reads and writes Python source files within the working directory. It does not access files outside the project scope.
- - Commands executed:
python -m py_compile <file> for syntax checking, python -m pytest <test_file> for test execution. These run local project code — only use on trusted repositories or in sandboxed environments. - Data read: Source files in the working directory only. No access to secrets, credentials, or system files.
- Network access: None required. The skill operates entirely offline.
- Credentials: None stored or accessed.
- Persistence: All modifications are to source files in the working directory only. No global config changes.
- Sandboxing: Recommended to run in a virtual environment (
venv) to isolate dependencies.
OUTPUT FORMAT
Reviews and code output follow the standards defined above. Each review identifies specific anti-patterns with line references and provides corrected code blocks.
RULES
- 1. Type hints everywhere — public functions must have full type annotations
- 500 lines max — split large modules into focused sub-modules
- Test every module —
tests/test_{module}.py with descriptive test names - Async by default — use async for any I/O operation
- pathlib over os.path — modern Python path handling
- No print debugging — use
logging module with appropriate levels
Published by Shadows Company — "We work in the shadows to serve the Light."
Python Sensei — 最佳实践执行器
版本: 1.1.0 | 作者: Shadows Company | 许可证: MIT
触发时机
- - 编写新的 Python 代码
- 审查现有的 Python 代码
- 用户说python review、best practices、clean up this python
- 重构 Python 模块
- 设置新的 Python 项目
不触发时机
- - 质量无关紧要的快速脚本
- 用户明确说just make it work
- 非 Python 代码
前置条件
需要在 PATH 中存在 python 或 python3,用于语法检查(python -m py_compile)和测试执行(python -m pytest)。
可选工具(自动检测,建议会相应调整):
- - pytest — 测试执行(pip install pytest)
- mypy 或 pyright — 静态类型检查
- ruff — 快速代码检查和格式化(pip install ruff)
该技能会检查哪些工具可用,并根据用户已安装的工具链调整建议。
代码标准
1. 模块结构
python
模块文档字符串 — 一行描述用途。
标准库导入
import os
from pathlib import Path
第三方库导入
import httpx
from pydantic import BaseModel
本地导入
from .config import Settings
常量
MAX_RETRIES = 3
DEFAULT_TIMEOUT = 30
模块代码...
规则:
- - 每个模块最多 500 行 — 如果更大则拆分
- 导入分组:标准库 → 第三方库 → 本地库(每组之间空一行)
- 常量放在顶部,使用全大写命名
- 复杂类每个文件一个类
2. 函数
python
async def fetchuser(userid: str, *, include_profile: bool = False) -> User | None:
根据 ID 获取用户。
Args:
user_id: 唯一的用户标识符。
include_profile: 是否包含完整的个人资料数据。
Returns:
如果找到则返回 User 对象,否则返回 None。
Raises:
ConnectionError: 如果 API 无法访问。
规则:
- - 所有公共函数使用类型提示(参数 + 返回值)
- 使用 * 后的关键字参数以提高清晰度
- 当失败是正常情况时(非异常),返回类型为 None
- 仅对公共函数编写文档字符串
- 每个函数最多 30 行 — 如果更大则提取辅助函数
3. 数据模型
python
from dataclasses import dataclass, field
from enum import StrEnum
class Status(StrEnum):
ACTIVE = active
INACTIVE = inactive
PENDING = pending
@dataclass
class User:
id: str
name: str
status: Status = Status.ACTIVE
tags: list[str] = field(default_factory=list)
def to_dict(self) -> dict:
return {
id: self.id,
name: self.name,
status: self.status.value,
tags: self.tags,
}
规则:
- - 简单模型使用 @dataclass,验证密集型模型使用 Pydantic
- 状态使用 StrEnum(可 JSON 序列化)
- 始终包含 to_dict() 用于序列化
- 默认不可变(适当时使用 frozen=True)
4. 错误处理
python
正确:特定异常,最小化 try 块
try:
response = await client.get(url)
response.raise
forstatus()
except httpx.TimeoutException:
logger.warning(请求超时:%s, url)
return None
except httpx.HTTPStatusError as e:
logger.error(HTTP %d:%s, e.response.status_code, url)
raise
错误:捕获所有异常
try:
do_everything()
except Exception:
pass # 永远不要这样做
规则:
- - 捕获特定异常,永远不要使用裸 except:
- 仅在系统边界进行验证(用户输入、外部 API)
- 信任内部代码 — 不要到处添加防御性检查
- 使用 logging 模块,不要使用 print() 处理错误
5. 异步模式
python
import asyncio
import httpx
async def fetch_all(urls: list[str]) -> list[dict]:
async with httpx.AsyncClient() as client:
tasks = [client.get(url) for url in urls]
responses = await asyncio.gather(*tasks, return_exceptions=True)
return [r.json() for r in responses if not isinstance(r, Exception)]
规则:
- - 使用 async with 进行资源管理
- 使用 asyncio.gather() 进行并行 I/O
- 使用 return_exceptions=True 处理部分失败
- 永远不要在同一个函数中混合同步和异步 I/O
6. 测试
python
import pytest
class TestUserService:
def testcreateuserwithvalid_data(self):
user = create_user(name=Alice, email=alice@example.com)
assert user.name == Alice
assert user.status == Status.ACTIVE
def testcreateuserrejectsempty_name(self):
with pytest.raises(ValueError, match=name cannot be empty):
create_user(name=, email=alice@example.com)
@pytest.mark.asyncio
async def testfetchuserreturnsnoneformissing(self):
result = await fetch_user(nonexistent-id)
assert result is None
规则:
- - 测试文件:tests/test{module}.py
- 测试名称描述场景:test[action][condition][expected]
- 每个测试一个断言(推荐)
- 使用 pytest.raises 处理预期异常
- 使用 fixtures 进行共享设置
7. 项目设置
project/
src/
project_name/
init.py
main.py
config.py
models.py
tests/
test_main.py
test_models.py
pyproject.toml
requirements.txt
.gitignore
使用 pyproject.toml 替代 setup.py。在 requirements.txt 中锁定主版本号。
需要标记的反模式
| 反模式 | 修复方法 |
|---|
| import * | 显式导入 |
| 可变默认参数 |
field(default_factory=list) |
| 全局可变状态 | 依赖注入 |
| 嵌套 try/except | 提取并扁平化 |
| SQL 字符串拼接 | 参数化查询 |
| type() 检查 | isinstance() |
| os.path | pathlib.Path |
| requests(同步) | httpx(异步就绪) |
安全考虑
此技能读取和写入工作目录中的 Python 源文件。它不会访问项目范围之外的文件。
- - 执行的命令:python -m pycompile 用于语法检查,python -m pytest file> 用于测试执行。这些命令运行本地项目代码 — 仅在受信任的仓库或沙盒环境中使用。
- 读取的数据:仅工作目录中的源文件。不访问密钥、凭据或系统文件。
- 网络访问:不需要。该技能完全离线运行。
- 凭据:不存储或访问任何凭据。
- 持久性:所有修改仅针对工作目录中的源文件。不更改全局配置。
- 沙盒化:建议在虚拟环境(venv)中运行以隔离依赖项。
输出格式
审查和代码输出遵循上述定义的标准。每次审查都会识别特定的反模式,并附带行引用和修正后的代码块。
规则
- 1. 处处使用类型提示 — 公共函数必须具有完整的类型注解
- 最多 500 行 — 将大型模块拆分为专注的子模块
- 测试每个模块 — tests/test_{module}.py 使用描述性测试名称
- 默认使用异步 — 对任何 I/O 操作使用 async
- 使用 pathlib 替代 os.path — 现代 Python 路径处理
- 不要使用 print 调试 — 使用 logging 模块并设置适当的级别
由 Shadows Company 发布 — 我们在暗处工作,为光明服务。