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:
[tool.lanorme]
extends = ["strict"]
In a standalone lanorme.toml or .lanorme.toml, write the same keys at the
top level with no [tool.lanorme] header; a header there is silently ignored.
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 check that ships with its enabled switch off and sets promote = ["ALL"], so all advisory warnings become build-failing errors. |
hexagonal |
Sets layer_deps to a four-layer ports-and-adapters layout with explicit composition-root globs, and points port_coverage at infrastructure/ as the adapter root (the built-in default is infrastructure/services). |
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). |
The default-off checks strict enables are named_args, test_style,
attribute_access, restating, similarity, prose, docstrings,
naming_scope, suppressions, docs and naming_clean_code. Two of those
carry assumptions worth knowing before you adopt it:
suppressionsstarts with a budget of zero, so any existing# noqafails the build until you setmax_totalto today's count and ratchet it down. TheSUPPRESScodes cannot be silenced inline, only in config.docsexpects the Markdown underdocs/to follow a Diataxis layout, and is inert when that directory is absent. Setdocs_root,sectionsorknown_top_levelwhere your tree differs.
Any one of them can be switched back off with a local table such as
[tool.lanorme.docs] enabled = false, which wins over the profile because
tables merge key by key.
It does not add architecture rules. layer_deps and port_coverage have no
enabled switch and always run with their built-in hexagonal layout (domain,
application, infrastructure, api; ports under application/ports,
adapters under infrastructure/services), which only bites on a tree that
uses those directory names. Pick hexagonal, clean or layered to set the
layout your tree uses, 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 default-off check, promote = ["ALL"], the hexagonal
layer rules and adapter roots, 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 check
prints the available bundled names and exits with code 2 (usage or
config error), the same exit code as a config file that is not valid
TOML, an invalid config value, or a missing local profile file.
Command-line flags still override¶
Command-line flags override config, including anything a profile sets. To
include or skip a category for one run 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.