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; exit0if clean,1on violations,2on tool errorscustoms 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).$submodulesmeans the controlled module and its own children. Ifallowis omitted, it defaults to["$submodules"]. If you setallowyourself,$submodulesis 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-versionwhen 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 Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file customs_lint-0.1.0.tar.gz.
File metadata
- Download URL: customs_lint-0.1.0.tar.gz
- Upload date:
- Size: 22.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.8.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ec71191a38452ab7a9ee93375e877f20d924f08b0921ea7d82e9d97a22168f6
|
|
| MD5 |
298e35375fcd4254b53aba7c4a19b10a
|
|
| BLAKE2b-256 |
582f7a6dd51beb8a60e7e00c27a113698caf14bcd6c9570c5d7459cf18d97c24
|
File details
Details for the file customs_lint-0.1.0-py3-none-win_amd64.whl.
File metadata
- Download URL: customs_lint-0.1.0-py3-none-win_amd64.whl
- Upload date:
- Size: 1.6 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.8.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7cd01f2a602c58a4c3f6528aeff21df4955806916c36c5086a766a6e34361c68
|
|
| MD5 |
f0bff9d48fdc7a8674b00d30b344e65b
|
|
| BLAKE2b-256 |
711eaab7123d6dee50df80d763f765142684f5ba8333a32d8ee81ae79fd9caeb
|
File details
Details for the file customs_lint-0.1.0-py3-none-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: customs_lint-0.1.0-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? No
- Uploaded via:
uv/0.8.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
99485fb72f092a8395deb4192582b53f8e86f8dbf1341a5dad82949de3c39ee6
|
|
| MD5 |
2e9f3e64e53f94258ca242066e6a5a8b
|
|
| BLAKE2b-256 |
8178f17e24636dddd022ef82858ac88695ecd4b256443021a52b99165652f317
|
File details
Details for the file customs_lint-0.1.0-py3-none-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: customs_lint-0.1.0-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? No
- Uploaded via:
uv/0.8.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b9f2cc809915a8ad4de0dc569d3ee7555c6949649e7e87d3a60c5c78fcbff3c5
|
|
| MD5 |
e087765a9a6312591d4c75c8c282c400
|
|
| BLAKE2b-256 |
7bdcbc060d97b5765a87c86e83168d33f470f44bfcf9ea65a3e8b4faabd36b5d
|
File details
Details for the file customs_lint-0.1.0-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: customs_lint-0.1.0-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 1.7 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.8.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ff74e914fddb239bddffa247c68e15b3ba0d7a21d5e631a79d9dcf06a9110d9d
|
|
| MD5 |
00fa40b37473e423c563db84e9a6ba6e
|
|
| BLAKE2b-256 |
776ce44f0e4e12ba77565cd955e8cf50548b4e93f17c755404aaeb9b72b53e58
|
File details
Details for the file customs_lint-0.1.0-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: customs_lint-0.1.0-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? No
- Uploaded via:
uv/0.8.22
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
04870b8588d55ad9d97aae6458f867428a02588a01a0d2c95f07e9c6b20aebff
|
|
| MD5 |
460a03551dea0be9750adf8016c11e67
|
|
| BLAKE2b-256 |
63b2902c103695e99a7ccc775e566f90e83603461d295deeae3cf902257b2c72
|