Home
A naming convention linter for Python projects. Define custom naming rules and enforce them with a single CLI command.
What It Does¶
- Define naming rules for variables, functions, classes, modules, and packages
- Apply rules to specific modules using pattern matching
- Integrate into CI or pre-commit to keep your naming conventions consistent
For Python developers who want to enforce team-specific naming conventions beyond what PEP 8 and ruff cover.
Key Features¶
| Feature | Description |
|---|---|
| Rule Types | Variable, function, class, module, and package naming rules |
| Filters | Narrow rules by return type, base class, decorator, and more |
| Naming Constraints | Prefix, suffix, regex, case convention, or derived from another element |
| Module Targeting | Apply rules to specific parts of your codebase using glob-style patterns |
| Inline Ignore | Suppress violations on specific lines with # pnl: ignore |
| Pre-commit | Drop-in integration with pre-commit hooks |
Quick Start¶
Install:
pip install python-naming-linter
Create .python-naming-linter.yaml in your project root:
rules:
- name: bool-method-prefix
type: function
filter: { return_type: bool }
naming: { prefix: [is_, has_, should_] }
- name: exception-naming
type: class
filter: { base_class: Exception }
naming: { regex: "^[A-Z][a-zA-Z]+(NotFound|Invalid|Denied|Conflict|Failed)Error$" }
apply:
- name: all
rules: [bool-method-prefix, exception-naming]
modules: "**"
Run:
pnl check
Output:
src/domain/service.py:12
[bool-method-prefix] validate (expected prefix: is_ | has_ | should_)
src/domain/exceptions.py:8
[exception-naming] FilterError (expected pattern: ^[A-Z][a-zA-Z]+(NotFound|Invalid|...)Error$)
Found 2 violation(s).
More Examples¶
Variable Naming — Match Type Annotation¶
Enforce that variable names match their type annotation in snake_case:
rules:
- name: attribute-matches-type
type: variable
filter: { target: attribute }
naming: { source: type_annotation, transform: snake_case }
apply:
- name: domain-layer
rules: [attribute-matches-type]
modules: contexts.*.domain
This catches repo: SubscriptionRepository — the name should be subscription_repository.
Combining Rules Per Layer¶
Apply different rules to different parts of your codebase:
apply:
- name: domain-layer
rules:
- attribute-matches-type
- bool-method-prefix
- domain-module-naming
modules: contexts.*.domain
- name: global-exceptions
rules: [exception-naming]
modules: "**"
Next Steps¶
- Installation — detailed install instructions
- Quick Start — step-by-step setup guide
- Configuration — full configuration reference
- Cookbook — real-world usage patterns