Skip to main content

Customs

A Rust lint tool that enforces Python import boundaries declared in pyproject.toml.

[tool.customs]
src-roots = ["src", "."]
ignore = ["examples", "tests"]

[tool.customs.module.my-service]
module = "my_project.apps.service"

[tool.customs.module.libraries-utils]
module = "my_project.libraries.utils"
allow = ["$submodules", "my_project.apps.service"]

Install

uv tool install customs-lint
# or: pip install customs-lint
customs check .

The VS Code extension starts customs lsp from the selected Python interpreter (the same customs-lint install you use for CI) and lints the active Python file on edit.

Commands

  • customs check [paths...] — lint files; exit 0 if clean, 1 on violations, 2 on tool errors
  • customs lsp — Language Server Protocol server on stdio

Configuration

Put a [tool.customs] table in pyproject.toml. Customs walks up from each file to the nearest pyproject.toml.

src-roots (default ["."]) — directories relative to that file, used to map a path to a module. The longest matching root wins. With ["src", "."], src/foo/bar.py is foo.bar, not src.foo.bar.

ignore — module prefixes of importing files to skip. tests skips tests and tests.test_foo, but not testsuite.

[tool.customs.module.<rule-name>] — a named rule. <rule-name> is your label; it appears in diagnostics (for example [my-service]).

  • module (required) — the controlled package. Imports of this module and its submodules are restricted.
  • allow — who may import that tree. Each entry is a module prefix (the named module and its submodules). $submodules means the controlled module and its own children. If allow is omitted, it defaults to ["$submodules"]. If you set allow yourself, $submodules is not implied; list it to keep internal imports allowed.

Development

System dependencies

You must have the following dependencies installed:

  • Rust and Cargo — stable toolchain, rustc 1.77 or newer. Install via rustup.
  • uv — Python package and environment manager (installs Python 3.12 from .python-version when needed).
  • Node.js 20+ and npm to build the VS Code extension.

Run tests

From the repo root, with Rust and Cargo on PATH:

cargo test --workspace

This runs the customs-core unit tests and the customs check integration tests against tests/fixtures/. To run one crate or one test:

cargo test -p customs-core
cargo test -p customs
cargo test -p customs-core longest_prefix_wins

Set up a virtual environment and build the wheel

From the repo root (Rust/Cargo must be on PATH):

uv sync --group dev
uv build --out-dir target/wheels

uv sync creates .venv, installs the locked dev group (maturin), and builds/installs customs into that environment. Wheels from uv build are written to target/wheels/.

Install the wheel into another environment

The distribution name is customs-lint; the installed executable is customs.

uv pip install target/wheels/customs_lint-*.whl

Invoke the CLI

Once the wheel is installed and the environment is active:

customs check .
customs check path/to/file.py
customs lsp   # stdio language server

customs check exits 0 if clean, 1 if it found forbidden imports, and 2 on tool or config errors.

Build the VS Code extension

The extension does not bundle customs. Install customs-lint in the workspace interpreter (or set customs.path). From the repo root:

cd editors/vscode
npm ci
npm run package

npm run package runs vsce package and produces editors/vscode/customs-0.1.0.vsix (version from package.json).

For local iteration without a VSIX, run npm run compile in editors/vscode.

Install the VS Code extension

code --install-extension editors/vscode/customs-0.1.0.vsix

Or use the Command Palette: Extensions: Install from VSIX… and select the .vsix file.

After install, open a Python file and select the project interpreter (the Python extension is required). The extension runs customs lsp from that environment, or from customs.path if you set it. If customs is missing, it reports an error and asks you to install customs-lint in that environment (uv pip install customs-lint or pip install customs-lint).

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.

customs_lint-0.1.1-py3-none-win_amd64.whl (1.6 MB view details)

Uploaded Python 3Windows x86-64

customs_lint-0.1.1-py3-none-manylinux_2_28_x86_64.whl (1.9 MB view details)

Uploaded Python 3manylinux: glibc 2.28+ x86-64

customs_lint-0.1.1-py3-none-manylinux_2_28_aarch64.whl (1.9 MB view details)

Uploaded Python 3manylinux: glibc 2.28+ ARM64

customs_lint-0.1.1-py3-none-macosx_11_0_arm64.whl (1.7 MB view details)

Uploaded Python 3macOS 11.0+ ARM64

customs_lint-0.1.1-py3-none-macosx_10_12_x86_64.whl (1.8 MB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file customs_lint-0.1.1-py3-none-win_amd64.whl.

File metadata

  • Download URL: customs_lint-0.1.1-py3-none-win_amd64.whl
  • Upload date:
  • Size: 1.6 MB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for customs_lint-0.1.1-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 762f58700605681f5cc26eaac8e83e1c2fb634dcf4a1ae7943cc66ec91657f19
MD5 c1e1ea4b085ed552f37beac46815fb6a
BLAKE2b-256 55a1f56ff5af6469580c7a30ff49bbc3000fd658171e0093ad19a2e2d1c3adb4

See more details on using hashes here.

File details

Details for the file customs_lint-0.1.1-py3-none-manylinux_2_28_x86_64.whl.

File metadata

  • Download URL: customs_lint-0.1.1-py3-none-manylinux_2_28_x86_64.whl
  • Upload date:
  • Size: 1.9 MB
  • Tags: Python 3, manylinux: glibc 2.28+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for customs_lint-0.1.1-py3-none-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 8ba5fa01351b7072e6ce18a44bc59f39bfaffff080ee3aa305787fcc3b78095f
MD5 a6ed48c80b3b8a3f82bf4633ccb5e7a0
BLAKE2b-256 f91ef717e38661f61ecc33cbd3d00403e56551e6f9e704be696888860d13884f

See more details on using hashes here.

File details

Details for the file customs_lint-0.1.1-py3-none-manylinux_2_28_aarch64.whl.

File metadata

  • Download URL: customs_lint-0.1.1-py3-none-manylinux_2_28_aarch64.whl
  • Upload date:
  • Size: 1.9 MB
  • Tags: Python 3, manylinux: glibc 2.28+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for customs_lint-0.1.1-py3-none-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 22e3b4400b9adbc9648b6c21b0828d19a9fff01296c2eed0ff49ac171fdbf3b3
MD5 b58c523eb996d02ec04aff0b91d19533
BLAKE2b-256 1cf02f1c9d3c249f3d8dc7da45cd457f696df7885af3d93dc69f9d2c9ac46708

See more details on using hashes here.

File details

Details for the file customs_lint-0.1.1-py3-none-macosx_11_0_arm64.whl.

File metadata

  • Download URL: customs_lint-0.1.1-py3-none-macosx_11_0_arm64.whl
  • Upload date:
  • Size: 1.7 MB
  • Tags: Python 3, macOS 11.0+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for customs_lint-0.1.1-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 467bcf446a0b2d71b7dc74983e4a06f388bda35c74f703292e6ee791754caa07
MD5 db5a5f2b25fa79c3f8158ee61e899457
BLAKE2b-256 cb2bfa30d14b8797e69e36933655354fa2ecac16ae828a8e19ec0a1c61392496

See more details on using hashes here.

File details

Details for the file customs_lint-0.1.1-py3-none-macosx_10_12_x86_64.whl.

File metadata

  • Download URL: customs_lint-0.1.1-py3-none-macosx_10_12_x86_64.whl
  • Upload date:
  • Size: 1.8 MB
  • Tags: Python 3, macOS 10.12+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for customs_lint-0.1.1-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 8e86ca909a94c97dde9062f5b438e1c2cb6b5f135f027b185475abf4c6bfb436
MD5 8a717ceeb2ceaed49f752fed2cc76c41
BLAKE2b-256 3cbaca4f784e7a4555889875ace0c83745dc37eee909d68ffb6cf8130cb1f63f

See more details on using hashes here.

Supported by

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