Use configuration profiles¶
This how-to shows how to adopt the bundled profiles, compose several, point at a
local .toml, and read the merged result.
A profile is a named bundle of LaNorme settings you adopt with the extends
key, instead of copying the same toggles into every project. Use a profile to
turn on a coherent set of checks in one line, then override individual keys
locally where a project differs. For the full meaning of every key a profile can
set, see the configuration reference.
Adopt a single profile¶
Add extends to the [tool.lanorme] table in pyproject.toml (or to a
lanorme.toml / .lanorme.toml file):
[tool.lanorme]
extends = ["strict"]
extends takes one profile name or a list. A single name may also be given as
a bare string (extends = "strict").
The bundled profiles¶
Four profiles ship inside the package. One tightens severity, three configure an architecture style.
| Profile | What it does |
|---|---|
strict |
Turns on every opt-in (default-off) generic check and sets promote = ["ALL"], so all advisory warnings become build-failing errors. |
hexagonal |
Configures layer_deps for a four-layer ports-and-adapters backend and turns on port_coverage. |
clean |
Configures layer_deps for Clean Architecture's four layers (entities, use_cases, interface_adapters, frameworks). |
layered |
Configures layer_deps for classic N-tier layers (presentation, business, persistence). |
strict switches on the generic opt-in checks (named_args, test_style,
attribute_access, restating, similarity, prose) and promotes all
warnings. It does not turn on the architecture checks: layer_deps and
port_coverage stay off because strict carries no layout for them. Pick one
of hexagonal, clean or layered to enforce architecture, and compose it
with strict if you want both.
The architecture profiles are mutually exclusive in practice: each configures
layer_deps for a different layer layout, so extend exactly one of them.
Compose several profiles¶
List more than one name to merge them. The common pairing is strict severity plus an architecture style:
[tool.lanorme]
extends = ["strict", "hexagonal"]
This gives you every generic opt-in check, promote = ["ALL"], the hexagonal
layer rules, and port coverage, all from two profile names.
Extend a local .toml¶
An extends entry that ends in .toml, or contains a path separator, is read
as a file relative to the project root instead of a bundled name. Use this to
share one team standard across repositories:
[tool.lanorme]
extends = ["strict", "team-rules.toml"]
The file holds a bare [tool.lanorme]-style body (the keys directly, with no
wrapping table):
# team-rules.toml
promote = ["TYPE-004"]
[similarity]
enabled = true
An extends key inside a profile is ignored, so profiles do not chain.
How merging works¶
Profiles merge left to right, then your own keys merge on top, so a local key
always wins. Tables merge per key: a local [tool.lanorme.layer_deps] that sets
only transport_layers overrides that one key and leaves the rest of the
profile's layer_deps table intact.
flowchart LR
A["First profile<br/>(leftmost)"] --> B["Next profile<br/>(further right wins ties)"]
B --> C["Your [tool.lanorme]<br/>local keys (always win)"]
C --> D[Effective config]
Order matters when two profiles set the same key. In extends = ["strict",
"team-rules.toml"] above, team-rules.toml is to the right of strict, so its
promote = ["TYPE-004"] replaces strict's promote = ["ALL"]. Put the profile
whose value should win further right, or set the key in your own
[tool.lanorme] table to beat every profile.
Confirm the merged result¶
Run check with --show-config to print the discovered config and the
effective per-check settings, then exit without running any check. Given this
project config:
[tool.lanorme]
extends = ["strict", "hexagonal"]
ignore = ["NAMING-003"]
[tool.lanorme.prose]
enabled = false
the command reports the merged outcome:
$ lanorme check src --show-config
config file: /path/to/project/pyproject.toml [tool.lanorme]
project root: /path/to/project
[tool.lanorme]
ignore = ['NAMING-003']
promote = ['ALL']
checks (effective settings):
...
layer_deps source_root='' layers=<4 items> transport_layers=('api',) allowed_imports=<4 keys> composition_root=<4 items>
...
port_coverage source_root='' ports_dir='application/ports' adapter_roots=('infrastructure',) composition_root=<4 items> ...
prose enabled=False ... (opt-in, not enabled)
...
Read it as the merge in action:
promote = ['ALL']comes fromstrict.layer_depsandport_coverageare configured byhexagonal.ignorecomes from the local table.proseisenabled=False:strictturns prose on, but the local[tool.lanorme.prose]table wins.
The config file and project root paths vary per machine.
Note
An unknown profile name is a configuration error.
lanorme checkprints the available bundled names and exits with code 2 (usage or config error), the same exit code as malformed config.
Override CLI flags still apply¶
Command-line flags override config, including anything a profile sets. To run a
single category once without editing the profile, pass --select or
--ignore:
$ lanorme check src --ignore PORT
The --promote flag does the same for severity, so you can escalate or hold
back warnings for one run regardless of the profile's promote value.
Related¶
- Configuration reference for every
[tool.lanorme]key, includingextends,promoteandbaseline. - Rule reference for what each check flags and the per-check settings a profile configures.
A profile sets policy, not adoption pace. To roll a strict profile onto an
existing codebase without drowning in pre-existing findings, pair it with a
baseline: record current findings with lanorme baseline write, set the
baseline key, and only new findings report. See the baseline entry in the
configuration reference.