adamtheturtle/strict-kwargs

GitHub: adamtheturtle/strict-kwargs

一个用 Rust 编写的 Python 代码检查工具,用于检测并自动将位置参数调用重写为关键字参数调用。

Stars: 1 | Forks: 1

[![构建状态](https://static.pigsec.cn/wp-content/uploads/repos/cas/ce/ce733292a922c08274cf5a2096f8fa4cf01023bfa51a36ef6beecaaef371a9d9.svg)](https://github.com/adamtheturtle/strict-kwargs/actions) [![PyPI](https://badge.fury.io/py/strict-kwargs.svg)](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, 云安全监控, 代码规范, 可视化界面, 开发工具, 无后门, 网络流量审计, 逆向工具, 静态分析