adamtheturtle/strict-kwargs
GitHub: adamtheturtle/strict-kwargs
一个用 Rust 编写的 Python 代码检查工具,用于检测并自动将位置参数调用重写为关键字参数调用。
Stars: 1 | Forks: 1
[](https://github.com/adamtheturtle/strict-kwargs/actions)
[](https://badge.fury.io/py/strict-kwargs)
# strict-kwargs
尽可能强制使用关键字参数。
`strict-kwargs` 是一个用 Rust 实现的独立 CLI。
例如,如果我们有一个接受两个常规参数的函数,有三种调用它的方式。
使用此工具,仅接受使用关键字参数的形式。
```
"""Showcase errors when calling a function without naming the arguments."""
def add(a: int, b: int) -> int:
"""Add two numbers."""
return a + b
add(a=1, b=2) # OK
add(1, 2) # strict-kwargs reports this; strict-kwargs check --fix can rewrite it
add(1, b=2) # strict-kwargs reports this; strict-kwargs check --fix can rewrite it
```
## 为什么?
- 就像 `black` 或 `ruff format` 这样的格式化工具一样,这能让你不再争论某个特定的函数调用是否应该使用关键字参数。
- 位置参数一开始可能没问题。
随着添加的参数越来越多,如果没有人在重构时将它们改为关键字参数,调用可能会变得不清晰。
- 当使用关键字参数时,类型检查器能提供更好的错误提示。
例如,对于位置参数,你可能会看到 `Argument 5 to "add" has incompatible type "str"; expected "int"`。
这要求你计算参数的数量才能看出哪个是错的。
使用命名参数,你会得到 `Argument "e" to "add" has incompatible type "str"; expected "int"`。
## 安装说明
```
uv tool install strict-kwargs
```
或者:
```
pip install strict-kwargs
```
这已在 Python 3.11+ 上进行了测试。
## 用法
```
strict-kwargs check . # check a directory
strict-kwargs check --output-format json . # emit check diagnostics as JSON
strict-kwargs check --output-format github . # emit GitHub Actions annotations
strict-kwargs check --fix . # rewrite positional args in place
strict-kwargs check --diff . # preview fixes, write nothing
strict-kwargs check --fix --unsafe-fixes . # include behavior-changing fixes
strict-kwargs check --python .venv . # point type resolution at an environment
strict-kwargs check --cache-dir .strict-kwargs-cache . # enable the diagnostic cache
```
退出代码如下:
- `0`:无误
- `1`:发现违规
- `2`:操作错误
### 输出
- `full`:默认的检查输出,将 Ruff 风格的诊断信息和摘要写入标准输出(stdout)。
- `json` 和 `github`:将诊断信息写入标准输出(stdout),以便机器读取时不会混入操作信息。
- 警告和操作错误始终写入标准错误(stderr)。
- `check --diff` 将统一差异(unified diff)写入标准输出(stdout),并将其摘要写入标准错误(stderr)。
### 修复行为
`check --fix` 仅重写那些能明确知道目标参数名称的调用。
有歧义的调用会被视为已拒绝(declined)。
默认情况下,`check --fix` 会重写:
- 单签名的调用
- 重载的调用,前提是能选择一个精确的重载分支(overload arm),并且重写后的参数类型足够精确
合成的构造函数(Synthesized constructors)被视为不安全的修复,因为当类构造过程被自定义时,生成的构造函数模型可能与运行时行为不一致。
- `--unsafe-fixes`:包含其签名是从字段合成的 dataclass 和 `NamedTuple` 构造函数调用。
### Python 环境
使用 `--python` 将第三方解析指向某个解释器、虚拟环境或 `sys.prefix`。
- 缺失的路径会引发错误。
- 如果 `--python` 指定的路径缺失,会发出警告并忽略。
## pre-commit
```
repos:
- repo: https://github.com/adamtheturtle/strict-kwargs-pre-commit
rev: 2026.6.8.post1 # pin to a release tag
hooks:
- id: strict-kwargs
```
## 配置
配置位于 `pyproject.toml` 中:
```
[tool.strict_kwargs]
required_version = ">=2026.5.19-post.3"
ignore_names = ["main.func", "builtins.str"]
src = ["src"]
namespace_packages = ["src/airflow/providers"]
extend_exclude = ["generated", "vendor"]
force_exclude = true
cache_dir = ".strict-kwargs-cache"
fix_synthesized_constructors = true
output_format = "full" # or "json", "github"
```
设置 `required_version` 可以让较旧或不兼容的 `strict-kwargs` 二进制程序在读取此项目配置时快速失败。
支持的说明符包括确切版本(如 `2026.5.19-post.3`)和最低版本(如 `>=2026.5.19-post.3`)。
请使用 `strict-kwargs --version` 报告的版本号。
### 忽略的函数
对于仍应允许使用位置参数的函数,请使用 `ignore_names`。
这对于那些使用关键字参数会显得很奇怪的内置函数(builtins)特别有用。
例如,`str(object=1)` 就不符合习惯用法。
### 抑制单个发现
在报告诊断信息的那一行(违规调用的第一行)添加 Ruff 风格的 `# noqa` 注释即可抑制该提示:
```
func(1, 2, 3) # noqa: KW001
```
- `# noqa: KW001` 仅抑制 `KW001`。如果指令指定了其他代码(例如 `# noqa: E501`),该调用依然会被报告。
- 单独的 `# noqa` 会抑制该行上的所有发现,这与 Ruff 的行为一致。
- 被抑制的调用也会被 `--fix` 跳过,因此带有 `# noqa` 的调用永远不会被重写。
对于跨多行的调用,请将注释放在第一行——也就是 `path:line:col` 输出所指向的那一行:
```
func( # noqa: KW001
1,
2,
3,
)
```
#### 将 `# noqa` 与 Ruff 结合使用
如果你在运行 Ruff 时启用了 `RUF100`(未使用的 `noqa`),请优先使用带代码的形式 `# noqa: KW001`:Ruff 会原样保留那些它不认识的代码指令,但会移除它认为未使用的单独的 `# noqa`。为了防止 `KW001` 在与 Ruff 代码共享指令时(例如 `# noqa: E501, KW001`)被移除,请将其声明为外部代码:
```
[tool.ruff.lint]
external = ["KW001"]
```
### 源码发现
将 `src` 设置为需要进行以下操作的源代码目录:
- 搜索第一方导入(first-party imports)
- 在推导模块名称时进行剥离(strip)
相对路径会相对于项目根目录进行解析。
例如,`src = ["src"]` 会将 `src/pkg/mod.py` 映射为 `pkg.mod`,同时保留仓库根目录作为备选的源码根路径。
将 `namespace_packages` 设置为在进行模块解析时应被视为命名空间包的目录,即使它们没有 `__init__.py`。
### 排除项
使用 `extend_exclude` 可在目录运行期间跳过生成的或第三方提供的 Python 文件。
- 模式使用相对于项目根目录的 `.gitignore` 风格匹配。
- 默认情况下,排除项仅应用于目录遍历。
- 显式传递的文件(例如 `strict-kwargs check generated/api.py`)仍会被检查。
- 设置 `force_exclude = true` 可将排除项也应用于显式传递的文件。
这在 pre-commit 直接传递已更改文件时非常有用。
- 针对点目录(dot-directories)、`venv` 和 `__pycache__` 的内置跳过规则仍然保持启用。
### 缓存
设置 `cache_dir` 可以为 `strict-kwargs` 检查启用持久化诊断缓存。
`pyproject.toml` 中的相对 `cache_dir` 值会相对于项目根目录进行解析。
缓存位置的优先级依次为:
1. `--cache-dir`
2. `[tool.strict_kwargs].cache_dir`
3. `STRICT_KWARGS_CACHE_DIR`
如果均未设置,则禁用缓存。
### 修复默认值
设置 `fix_synthesized_constructors = true` 可以让 `strict-kwargs check --fix` 包含 dataclass 和 `NamedTuple` 构造函数的重写,而无需每次都传递 `--unsafe-fixes`。
要查找需要忽略的函数名称,请设置以下配置:
```
[tool.strict_kwargs]
debug = true
```
然后运行 `strict-kwargs check` 并查看调试输出。
## 与 mypy-strict-kwargs 的对比
[mypy-strict-kwargs](https://github.com/adamtheturtle/mypy-strict-kwargs) 是一个 `mypy` 插件,用于在类型检查期间强制执行相同的规则。
如果你符合以下情况,请使用 `strict-kwargs`:
- 使用 [ty](https://docs.astral.sh/ty/) 进行类型检查
- 倾向于使用不带插件的独立 linter
- 希望通过 `strict-kwargs check --fix` 进行自动重写
标签:Python, Rust, SOC Prime, 云安全监控, 代码规范, 可视化界面, 开发工具, 无后门, 网络流量审计, 逆向工具, 静态分析