Skip to main content

Enforce using keyword arguments where possible.

Project description

Build Status PyPI

strict-kwargs

Enforce using keyword arguments where possible.

strict-kwargs is a standalone CLI implemented in Rust. It parses Python with Ruff's Python parser and AST crates, then uses its own resolver plus ty for type-aware call resolution where static names alone are not enough.

For example, if we have a function which takes two regular arguments, there are three ways to call it. With this tool, only the form where keyword arguments are used is accepted.

"""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
add(1, b=2)  # strict-kwargs reports this

Why?

  • In the same spirit as a formatter - think black or ruff format - this lets you stop spending time discussing whether a particular function call should use keyword arguments.
  • Sometimes positional arguments are best at first, and then more and more are added and code becomes unclear, without anyone stopping to refactor to keyword arguments.
  • Type checkers give better errors when keyword arguments are used. For example, with positional arguments, you may see, Argument 5 to "add" has incompatible type "str"; expected "int". This requires that you count the arguments to see which one is wrong. With named arguments, you get Argument "e" to "add" has incompatible type "str"; expected "int".

How it works

strict-kwargs has two resolution layers:

  • A built-in resolver parses checked files, first-party modules, vendored typeshed stubs, and discovered site-packages using Ruff's Python parser and AST crates.
  • For calls that need richer inference, strict-kwargs asks ty's language server for hover and definition information. ty is a required dependency of the Python package so results do not depend on whether it happens to be installed separately.

The fixer uses the same detection path, but only rewrites calls when the target parameter names are known unambiguously.

Installation

uv tool install strict-kwargs

or:

pip install strict-kwargs

This is tested on Python 3.11+.

Usage

strict-kwargs .                 # check a directory
strict-kwargs --output-format json .    # emit check diagnostics as JSON
strict-kwargs --output-format github .  # emit GitHub Actions annotations
strict-kwargs fix .             # rewrite positional args to keyword args in place
strict-kwargs fix --diff .      # preview the rewrite, write nothing
strict-kwargs fix --fix-synthesized-constructors .  # opt into one declined category
strict-kwargs --python .venv .  # point type resolution at an environment
strict-kwargs --cache-dir .strict-kwargs-cache .  # enable the diagnostic cache

Exit codes are:

  • 0: clean
  • 1: violations found
  • 2: operational error

For check, the default full output format preserves the traditional human-readable diagnostics on stderr. json and github write diagnostics to stdout so machine consumers can read them without mixing in operational messages. Warnings and operational errors are always written to stderr.

fix only rewrites calls it can name unambiguously. Ambiguous calls are counted as declined. Single-signature calls are rewritten by default, including calls that require deeper type inference. Overloaded calls are rewritten by default only when analysis selects one precise overload arm and the rewritten argument types are precise enough. Synthesized constructors are the only opt-in category, because generated constructor models can differ from runtime behaviour when class construction is customized. fix --diff writes the unified diff to stdout and its summary to stderr.

  • --fix-synthesized-constructors: rewrite dataclass and NamedTuple constructors whose signatures were synthesized from fields. These can differ from runtime behaviour when class construction is customized.

Use --python to point third-party resolution at an interpreter, virtual environment, or sys.prefix. Missing paths are errors. A missing --python path is warned about and ignored.

pre-commit

repos:
  - repo: https://github.com/adamtheturtle/strict-kwargs-pre-commit
    rev: 2026.5.20  # pin to a release tag
    hooks:
      - id: strict-kwargs

Configuration

Configuration lives in 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"

Set required_version to make older or incompatible strict-kwargs binaries fail fast when they read this project configuration. Supported specifiers are exact versions, such as 2026.5.19-post.3, and minimum versions, such as >=2026.5.19-post.3. Use the version reported by strict-kwargs --version.

This is useful especially for builtins which can look strange with keyword arguments. For example, str(object=1) is not idiomatic. Set src to source-code directories that should be searched for first-party imports and stripped when deriving module names. Relative paths are resolved against the project root, so src = ["src"] maps src/pkg/mod.py to pkg.mod while preserving the repository root as a fallback source root. Set namespace_packages to directories that should be treated as namespace packages for module resolution even when they have no __init__.py. Use extend_exclude to skip generated or vendored Python files during directory runs. Patterns use .gitignore-style matching relative to the project root. By default, exclusions apply to directory traversal only: an explicitly passed file such as strict-kwargs generated/api.py is still checked. Set force_exclude = true to apply exclusions to explicitly passed files too, which is useful when pre-commit passes changed files directly. The built-in skips for dot-directories, venv, and __pycache__ remain enabled. Set cache_dir to enable the persistent diagnostic cache for strict-kwargs checks. Relative cache_dir values in pyproject.toml are resolved against the project root. The cache location precedence is: --cache-dir, then [tool.strict_kwargs].cache_dir, then STRICT_KWARGS_CACHE_DIR. If none are set, the cache is disabled. Set fix_synthesized_constructors = true to make strict-kwargs fix rewrite dataclass and NamedTuple constructors without passing --fix-synthesized-constructors each time.

To find the name of a function to ignore, set the following configuration:

[tool.strict_kwargs]
debug = true

Then run strict-kwargs and look for the debug output.

Comparison with mypy-strict-kwargs

mypy-strict-kwargs is a mypy plugin that enforces the same rule during type checking.

Use strict-kwargs if you type-check with ty, if you prefer a standalone linter without plugins, or if you want automatic rewrites with strict-kwargs fix.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

strict_kwargs-2026.5.20-py3-none-win_amd64.whl (2.6 MB view details)

Uploaded Python 3Windows x86-64

strict_kwargs-2026.5.20-py3-none-manylinux_2_39_x86_64.whl (2.9 MB view details)

Uploaded Python 3manylinux: glibc 2.39+ x86-64

strict_kwargs-2026.5.20-py3-none-macosx_11_0_arm64.whl (2.8 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

File details

Details for the file strict_kwargs-2026.5.20-py3-none-win_amd64.whl.

File metadata

File hashes

Hashes for strict_kwargs-2026.5.20-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 ef3c6c6d8691d7751f4633b11b863b8cf1e6b43b1d6d5f16a4093bbe64969562
MD5 0802aa4ee138ae9461b2a8a4c4b13bdc
BLAKE2b-256 1ee8a026016718974b81b0332dbfd8b82914a58e1895128aeeab701e4e65fc03

See more details on using hashes here.

Provenance

The following attestation bundles were made for strict_kwargs-2026.5.20-py3-none-win_amd64.whl:

Publisher: release.yml on adamtheturtle/strict-kwargs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file strict_kwargs-2026.5.20-py3-none-manylinux_2_39_x86_64.whl.

File metadata

File hashes

Hashes for strict_kwargs-2026.5.20-py3-none-manylinux_2_39_x86_64.whl
Algorithm Hash digest
SHA256 b4afeb630c9432503e1e9666e0eb548183989cae6e1e3894f6c4c60050af12fa
MD5 57bf0701f72ed743d9c4a8bd5404cf8c
BLAKE2b-256 0f9e21ac664032097bd79dfa72c2a35396b2b1eea2d9bb73e054303766020f7e

See more details on using hashes here.

Provenance

The following attestation bundles were made for strict_kwargs-2026.5.20-py3-none-manylinux_2_39_x86_64.whl:

Publisher: release.yml on adamtheturtle/strict-kwargs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file strict_kwargs-2026.5.20-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for strict_kwargs-2026.5.20-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 669b39fd5a41bad408656aa32d8fd408f968f2cd7ad7282317fd65e1681c3534
MD5 e266360a5ed0b07233a209532aabef72
BLAKE2b-256 c981fd660257f151101038ac8fc244fba75ecc8b282ef774407c7a786834f8a4

See more details on using hashes here.

Provenance

The following attestation bundles were made for strict_kwargs-2026.5.20-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on adamtheturtle/strict-kwargs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page