Skip to main content

nginx-lint-plugin (Python SDK)

Python SDK for writing and testing nginx-lint WASM plugins. The Python counterpart of the TypeScript SDK at plugins/typescript/nginx-lint-plugin, built as a single maturin mixed Rust/Python project: one wheel ships the pure-Python SDK, the componentize-py bindings, and the Rust parser compiled as a native module.

Layout

  • python/nginx_lint_plugin/ — the SDK package. Everything a plugin needs is re-exported from its root (Plugin, Config, LintError, Fix, Severity, …), so plugin code never imports from the generated bindings directly. It ships a PEP 561 py.typed marker, so mypy and pyright use the annotations.
    • builders — plugin_spec() and error_builder(), mirroring the Rust SDK's PluginSpec::new() and spec().error_builder(). The generated dataclasses have no defaults, so without these a spec means spelling out all eleven fields and every error repeats the plugin's rule and category.
    • testing — parse_config() and PluginTestRunner for plain-pytest unit tests against the real Rust parser, plus apply_fixes() and PluginTestRunner.assert_fixed() to check what a rule's fixes actually produce, through the same applier nginx-lint --fix uses
    • config_builder — reconstructs method-based Config/Directive objects (matching the componentize-py binding surface, e.g. directive.is_(...)) from parser output or a host snapshot
    • _native — the Rust parser bridge (built by maturin from src/lib.rs; only testing imports it, so the rest of the SDK stays bundleable into a WASM component). Built against the stable ABI (abi3-py311), so one wheel per platform covers every Python ≥ 3.11.
    • API_VERSION — the plugin API version, kept in sync with crates/nginx-lint-plugin
  • python/wit_world/, python/componentize_py_types.py — componentize-py bindings generated from wit/nginx-lint-plugin.wit by make bindings, placed as top-level modules so the same imports resolve inside a componentized plugin (the Python analog of the TS SDK's dist/generated). Like the TS SDK's, they are not committed — regenerated before every install, so they cannot drift from the WIT. They still ship in the wheel and sdist via tool.maturin.include, which applies regardless of .gitignore.
  • Cargo.toml / src/lib.rs — the native parser module (its own cargo workspace, excluded from the repository's root workspace; the crate version is the wheel version, kept in sync with the repository version). It depends on nginx-lint-parser and nginx-lint-common by exact version rather than by path so that the sdist stands alone; inside this repository ../.cargo/config.toml patches both back to the working tree, and that file explains why.

Install

Both targets regenerate the bindings and copy the WIT in first, which needs the componentize-py CLI; make develop also needs maturin. Both are in the dev dependency group:

cd plugins/python/nginx-lint-plugin
pip install --group dev

make install   # pip install .
make develop   # editable install for SDK work (maturin develop)
make test      # pytest

Outside this repository the SDK is a plain dependency — pip install nginx-lint-plugin is all a plugin author needs, for both testing and building. The WIT ships inside the package, so componentize-py has an interface definition to build against:

componentize-py -d "$(python -c 'import nginx_lint_plugin as p; print(p.wit_dir())')" \
    -w plugin componentize app -o plugin.wasm --stub-wasi \
    -p . -p "$(python -c 'import nginx_lint_plugin as p, pathlib; print(pathlib.Path(p.__file__).parent.parent)')"

The second -p is only needed for editable installs, whose .pth link componentize-py does not follow; it is harmless otherwise. See ../server-tokens-enabled-py/Makefile for the same commands in a form you can copy.

Writing a plugin

from nginx_lint_plugin import Config, LintError, Plugin, plugin_spec, error_builder


class WitWorld(Plugin):          # the class must keep this name
    def spec(self):
        return plugin_spec("my-rule", "style", "What it checks",
                           severity="warning")

    def check(self, cfg: Config, path: str) -> list[LintError]:
        err = error_builder(self.spec())
        return [
            err.warning_at("autoindex should be off", ctx.directive,
                           fixes=[ctx.directive.replace_with("autoindex off;")])
            for ctx in cfg.all_directives_with_context()
            if ctx.directive.is_("autoindex") and ctx.directive.first_arg_is("on")
        ]

Testing a plugin

Tests are ordinary pytest. Parsing goes through the same Rust parser the production linter uses:

from app import WitWorld
from nginx_lint_plugin.testing import PluginTestRunner, parse_config

plugin = WitWorld()
runner = PluginTestRunner(plugin.spec, plugin.check)

def test_detects_server_tokens_on():
    runner.assert_errors("http {\n    server_tokens on;\n}", 1)

def test_include_context():
    cfg = parse_config("server_tokens on;", include_context=["http"])
    assert len(plugin.check(cfg, "test.conf")) == 1

def test_fix():
    # Asserting on the applied output, not just the reported findings: a fix
    # the linter normalizes into a different operation than intended shows up
    # here rather than in a user's config.
    runner.assert_fixed(
        "http {\n    server_tokens on;\n}\n",
        "http {\n    server_tokens off;\n}\n",
    )

The same WitWorld class runs unmodified under pytest and inside the WASM component — the test Config/Directive objects reproduce the exact method surface of the componentize-py bindings.

Why a native module instead of the parser WASM component?

The TS SDK runs the parser as a WASM component inside Node (via jco). Python currently has no maintained component-model runtime — wasmtime-py removed its bindgen support — so this SDK compiles the parser natively via pyo3 instead. Same parser code, same output shape. If wasmtime-py regrows component support, the WASM path can return without changing the test-writing API.

Metadata

Release files for nginx-lint-plugin 0.20.0

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

Source distribution (sdist)

Source distribution for nginx-lint-plugin 0.20.0
File Size Uploaded
nginx_lint_plugin-0.20.0.tar.gz 29.7 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for nginx-lint-plugin 0.20.0
File
nginx_lint_plugin-0.20.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 abi3 Linux glibc 2.17+ x86-64 Details
nginx_lint_plugin-0.20.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl CPython 3.11 abi3 Linux glibc 2.17+ ARM64 Details
nginx_lint_plugin-0.20.0-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
nginx_lint_plugin-0.20.0-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 1.6 MB

Release files / nginx_lint_plugin-0.20.0.tar.gz

Download URL nginx_lint_plugin-0.20.0.tar.gz
Size 29.7 kB
Tags Source
SHA-256 checksum
How to use checksums
809adb95f36794b6a07b26337920df2c51128810dda32119409980059d420f33
BLAKE2b-256 checksum
How to use checksums
83eef27777693bfd51a1e5c9056e4c9eeb746b5f908c91e1dbc294379848a459
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 31, 2026.

Transparency log

Release files / nginx_lint_plugin-0.20.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL nginx_lint_plugin-0.20.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 430.7 kB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
2af364354f1ae6d838cef6b9d098ff2277ed9ccfb44fb95b521aaf15f4c6457c
BLAKE2b-256 checksum
How to use checksums
2ba2de82bff7d53717213fac42e718d6db500a3d76fdf0d6d4b2d2ca2cbd315c
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 31, 2026.

Transparency log

Release files / nginx_lint_plugin-0.20.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

Download URL nginx_lint_plugin-0.20.0-cp311-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Size 392.4 kB
Tags CPython 3.11 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
548eb78daf051281086011a0dfb2b38239f624e850663f9e0b38dc1aa903bbd5
BLAKE2b-256 checksum
How to use checksums
9f1f6cf2bef8c4e8885edf42124bdab69bfbb8988c67d90d7da483877de3f0f7
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 31, 2026.

Transparency log

Release files / nginx_lint_plugin-0.20.0-cp311-abi3-macosx_11_0_arm64.whl

Download URL nginx_lint_plugin-0.20.0-cp311-abi3-macosx_11_0_arm64.whl
Size 353.1 kB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
83ad78340ee29de7cef51b114bc1d07fe9e89f16bae654ff80046b799d6d86d0
BLAKE2b-256 checksum
How to use checksums
8763ccf531a4068ebddb1ef455a1f2e4e8b9d076ed69af1fd98ef39066d431b5
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 31, 2026.

Transparency log

Release files / nginx_lint_plugin-0.20.0-cp311-abi3-macosx_10_12_x86_64.whl

Download URL nginx_lint_plugin-0.20.0-cp311-abi3-macosx_10_12_x86_64.whl
Size 358.1 kB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
cc3426f65e1b19450ce4fb789d48ae564258ddd93f56cb39733f2726ebd20980
BLAKE2b-256 checksum
How to use checksums
2d7db408a5dcc377ecf192c0747833d50a0b0a960fb53510365939fc5b893697
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 31, 2026.

Transparency log

Release history Release notifications | RSS feed

0.24.0

5 release files

0.23.0

5 release files

0.22.0

5 release files

0.21.0

5 release files

This release

0.20.0 This release

5 release files

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