Skip to main content

Build Status PyPI

strict-kwargs

Enforce using keyword arguments where possible.

strict-kwargs is a standalone CLI implemented in Rust.

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; strict-kwargs check --fix can rewrite it
add(1, b=2)  # strict-kwargs reports this; strict-kwargs check --fix can rewrite it

Why?

  • Like a formatter, such as black or ruff format, this lets you stop discussing whether a particular function call should use keyword arguments.
  • Positional arguments can be fine at first. As more are added, calls can become unclear without anyone stopping to refactor them 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".

Installation

uv tool install strict-kwargs

or:

pip install strict-kwargs

This is tested on Python 3.11+.

Usage

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

Exit codes are:

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

Output

  • full, the default check output, writes Ruff-style diagnostics and summaries to stdout.
  • 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.
  • check --diff writes the unified diff to stdout and its summary to stderr.

Fix behavior

check --fix only rewrites calls whose target parameter names are known unambiguously. Ambiguous calls are counted as declined.

By default, check --fix rewrites:

  • single-signature calls
  • overloaded calls, when one precise overload arm can be selected and the rewritten argument types are precise enough

Synthesized constructors are treated as unsafe fixes because generated constructor models can differ from runtime behaviour when class construction is customized.

  • --unsafe-fixes: include dataclass and NamedTuple constructor calls whose signatures were synthesized from fields.

Python environment

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.8.28.post2  # 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
error_on_unused_noqa = 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.

Ignored functions

Use ignore_names for functions that should still allow positional arguments. This is useful especially for builtins which can look strange with keyword arguments.

For example, str(object=1) is not idiomatic.

Suppressing individual findings

Add a Ruff-style # noqa comment to the line a diagnostic is reported on (the first line of the offending call) to suppress it:

func(1, 2, 3)  # noqa: KW001
  • # noqa: KW001 suppresses only KW001. A directive naming other codes (for example # noqa: E501) leaves the call reported.
  • A bare # noqa suppresses every finding on the line, matching Ruff.
  • Suppressed calls are skipped by --fix too, so a # noqa call is never rewritten.

For a call spanning multiple lines, put the comment on the first line, the line the path:line:col output points at:

func(  # noqa: KW001
    1,
    2,
    3,
)

Finding # noqa comments that are no longer needed

Set error_on_unused_noqa = true (or pass --error-on-unused-noqa) to report a KW002 error for every # noqa: KW001 directive that suppressed nothing:

main.py:3:12: KW002 Unused `noqa` directive (unused: `KW001`)

Only directives that name KW001 explicitly are reported. A bare # noqa, or one naming only other tools' codes, is left alone: strict-kwargs sees only its own rule, so it cannot tell whether such a directive is suppressing someone else's finding.

KW002 errors count towards the exit code of check. They belong to checking rather than fixing: --error-on-unused-noqa cannot be combined with --fix or --diff, and those modes neither report nor remove unused directives even when the rule is enabled in pyproject.toml. Enabling the rule makes suppressed calls cost a full check (including the ty fallback), so a run with many # noqa comments is somewhat slower.

Using # noqa alongside Ruff

If you also run Ruff with RUF100 (unused noqa) enabled, prefer the coded form # noqa: KW001: Ruff leaves a directive whose only codes it does not recognise untouched, but it will remove a bare # noqa it considers unused. To keep KW001 from being stripped when it shares a directive with a Ruff code (for example # noqa: E501, KW001), declare it as an external code:

[tool.ruff.lint]
external = ["KW001"]

Source discovery

Set src to source-code directories that should be:

  • searched for first-party imports
  • stripped when deriving module names

Relative paths are resolved against the project root. For example, 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.

Exclusions

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 check generated/api.py, is still checked.
  • Set force_exclude = true to apply exclusions to explicitly passed files too. This is useful when pre-commit passes changed files directly.
  • The built-in skips for dot-directories, venv, and __pycache__ remain enabled.

Cache

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:

  1. --cache-dir
  2. [tool.strict_kwargs].cache_dir
  3. STRICT_KWARGS_CACHE_DIR

If none are set, the cache is disabled.

Fix defaults

Set fix_synthesized_constructors = true to make strict-kwargs check --fix include dataclass and NamedTuple constructor rewrites without passing --unsafe-fixes each time.

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

[tool.strict_kwargs]
debug = true

Then run strict-kwargs check 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
  • prefer a standalone linter without plugins
  • want automatic rewrites with strict-kwargs check --fix

Metadata

Release files for strict-kwargs 2026.8.28.post2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distributions (wheels)

Table of built distributions (wheels) for strict-kwargs 2026.8.28.post2
File
strict_kwargs-2026.8.28.post2-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
strict_kwargs-2026.8.28.post2-py3-none-manylinux_2_39_x86_64.whl Python 3 none Linux glibc 2.39+ x86-64 Details
strict_kwargs-2026.8.28.post2-py3-none-manylinux_2_39_aarch64.whl Python 3 none Linux glibc 2.39+ ARM64 Details
strict_kwargs-2026.8.28.post2-py3-none-macosx_11_0_arm64.whl Python 3 none macOS 11.0+ ARM64 Details
strict_kwargs-2026.8.28.post2-py3-none-macosx_10_12_x86_64.whl Python 3 none macOS 10.12+ x86-64 Details

Total release size: 16.6 MB

Release files / strict_kwargs-2026.8.28.post2-py3-none-win_amd64.whl

Download URL strict_kwargs-2026.8.28.post2-py3-none-win_amd64.whl
Size 3.2 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
278ea3b4226edf7b1d986c6c58daa245ca5db781709447ab488a840ac8062184
BLAKE2b-256 checksum
How to use checksums
3489df89790f6a3c14964281e200d90b9153f2283dfa6dd49bc360083a6a8fba
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release files / strict_kwargs-2026.8.28.post2-py3-none-manylinux_2_39_x86_64.whl

Download URL strict_kwargs-2026.8.28.post2-py3-none-manylinux_2_39_x86_64.whl
Size 3.5 MB
Tags Linux glibc 2.39+ x86-64 Python 3
SHA-256 checksum
How to use checksums
450f3a75ef5041a6c364f00708e611915e2c0c15c1f385e3c821115222fe330c
BLAKE2b-256 checksum
How to use checksums
c48c0de9a03d6a6dc7d12febe68ae27be5c7bfca27f8c96a19a635b7aef9aa21
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release files / strict_kwargs-2026.8.28.post2-py3-none-manylinux_2_39_aarch64.whl

Download URL strict_kwargs-2026.8.28.post2-py3-none-manylinux_2_39_aarch64.whl
Size 3.4 MB
Tags Linux glibc 2.39+ ARM64 Python 3
SHA-256 checksum
How to use checksums
fe2e46aac30de7e8969c30f2db28912df5a51e0c5f71b7c610178dedb5ff2777
BLAKE2b-256 checksum
How to use checksums
c6a2a7cba32fabc14298820e9d136a3b52a5e33c848b653179497f9d18cd115f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release files / strict_kwargs-2026.8.28.post2-py3-none-macosx_11_0_arm64.whl

Download URL strict_kwargs-2026.8.28.post2-py3-none-macosx_11_0_arm64.whl
Size 3.3 MB
Tags Python 3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
28579c550ce3f9f0a8b77d111f8ac70a50636e218a1a403497f7bb6e9c05739f
BLAKE2b-256 checksum
How to use checksums
1b3773d6e97c64cf3296ff88d6bdc4e8e57fee074619dbae4480fcfb429d16b3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log

Release files / strict_kwargs-2026.8.28.post2-py3-none-macosx_10_12_x86_64.whl

Download URL strict_kwargs-2026.8.28.post2-py3-none-macosx_10_12_x86_64.whl
Size 3.3 MB
Tags Python 3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
7426ea32b2a89d76648c88e64e14787c252eaa62d0239671b4be055de8a4194b
BLAKE2b-256 checksum
How to use checksums
a91673ed35c34cc59eec39fa7fe86f067eabab5f78b30d552eba8eb06c9f01c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 28, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page