topmark.config.model¶
Configuration model and merge policy.
This module defines
FrozenConfig: an immutable layered configuration snapshot used by processing steps.MutableConfig: a mutable builder used during discovery/merge; it can be frozen into an immmutableFrozenConfigand thawed back for edits.
Scope
- In scope: data shapes, defaulting rules at the field level, merge policy
(
MutableConfig.merge_with()), and freeze/thaw mechanics. - Out of scope: filesystem discovery, TOML I/O, and whole-source TOML schema validation. Those belong in dedicated modules to keep this model import-light and avoid import cycles, e.g.:
- TOML document handling
- Layered config handling:
Immutability
FrozenConfigstores tuples/frozensets and isfrozen=Trueto prevent accidental mutation at runtime. UseFrozenConfig.thaw()→ edit →MutableConfig.freeze()for safe updates.
Path semantics
- Path-to-file options declared in config are normalized against that config file's directory.
- CLI path-to-file options are normalized against the invocation CWD.
relative_toinfluences header metadata (e.g.,file_relpath) only, not glob expansion.
Testing guidance
- Unit-test merge behavior with synthetic builders (no I/O).
- Exercise TOML/discovery paths in
loader/discoverytests.
Validation semantics
- Config validity is evaluated across staged config-loading validation logs: TOML-source diagnostics, merged-config diagnostics, and runtime-applicability diagnostics.
- In non-strict mode, validation fails only when at least one stage contains an error diagnostic.
- In strict mode, validation fails when any stage contains either a warning or an error diagnostic.
FrozenConfig
dataclass
¶
FrozenConfig(
*,
policy,
policy_by_type,
config_files,
header_fields,
field_values,
align_fields,
relative_to_raw,
relative_to,
files,
include_from,
exclude_from,
files_from,
include_pattern_groups,
exclude_pattern_groups,
include_file_types,
exclude_file_types,
validation_logs,
)
Immutable layered configuration for TopMark.
This snapshot is produced by
MutableConfig.freeze()
after merging defaults, project files, extra config files, and config-like API
overrides. Collections are immutable (tuple/frozenset) to prevent
accidental mutation during processing.
Use FrozenConfig.thaw()
to obtain a mutable builder for edits,
and MutableConfig.freeze()
to return to an immutable layered snapshot.
Layered merging with clear precedence is provided by the config-resolution helpers in topmark.config.resolution.
Attributes:
| Name | Type | Description |
|---|---|---|
policy |
FrozenPolicy
|
Global, resolved, immutable runtime policy (plain booleans), applied after discovery. |
policy_by_type |
Mapping[str, FrozenPolicy]
|
Per-file-type resolved policy overrides (plain booleans), applied after discovery. |
config_files |
tuple[Path | SyntheticConfigSource, ...]
|
List of paths or identifiers for config sources used. |
header_fields |
tuple[str, ...]
|
List of header fields from the [header] section. |
field_values |
Mapping[str, str]
|
Mapping of field names to their string values from [fields]. |
align_fields |
bool | None
|
Whether to align fields, from [formatting]. |
relative_to_raw |
str | None
|
Original string from config, API or CLI. |
relative_to |
Path | None
|
Base path used only for header metadata (e.g., file_relpath). Note: Glob expansion and filtering are resolved relative to their declaring source (config file dir or CWD for CLI), not relative_to. |
files |
tuple[str, ...]
|
List of files to process. |
include_from |
tuple[PatternSource, ...]
|
Files containing include patterns. |
exclude_from |
tuple[PatternSource, ...]
|
Files containing exclude patterns. |
files_from |
tuple[PatternSource, ...]
|
Paths to files that list newline-delimited candidate file paths to add before filtering. |
include_pattern_groups |
tuple[PatternGroup, ...]
|
Glob patterns to include. |
exclude_pattern_groups |
tuple[PatternGroup, ...]
|
Glob patterns to exclude. |
include_file_types |
frozenset[str]
|
Whitelist of file type identifiers to restrict file discovery. |
exclude_file_types |
frozenset[str]
|
Blacklist of file type identifiers to exclude from file discovery. |
validation_logs |
FrozenValidationLogs
|
Stage-aware diagnostics collected during config loading and preflight validation. |
Policy resolution
- Public/API overlays are applied to a mutable draft after discovery and before
freezing to this immutable
FrozenConfig. Per-type policies override the global policy for matching file types. - All entries in
policy_by_typeare resolved against the globalpolicyduringMutableConfig.freeze; at runtime the pipeline simply selects the appropriateFrozenPolicyviatopmark.config.policy.effective_frozen_policywithout further merging.
is_valid ¶
Return whether this config is valid.
Validity follows the staged config-loading validation semantics described in this module.
Here, strict is the effective resolved strictness used for
config/preflight validation. Callers typically derive it from
strict after applying TOML resolution and any CLI/API
override precedence.
A similar helper exists on MutableConfig.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
strict
|
bool | None
|
Effective strictness for config/preflight validation. |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in src/topmark/config/model.py
ensure_valid ¶
Raise ConfigValidationError if this config is not valid.
Validity follows the staged config-loading validation semantics described in this module.
Here, strict is the effective resolved strictness used for
config/preflight validation. Callers typically derive it from
strict after applying TOML resolution and any CLI/API
override precedence.
A similar helper exists on MutableConfig.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
strict
|
bool | None
|
Effective strictness for config/preflight validation. |
None
|
Raises:
| Type | Description |
|---|---|
ConfigValidationError
|
If the config is invalid. |
Source code in src/topmark/config/model.py
thaw ¶
Return a mutable copy of this immutable config.
Symmetry
Mirrors MutableConfig.freeze().
Prefer thaw→edit→freeze rather than mutating a runtime
FrozenConfig.
Returns:
| Type | Description |
|---|---|
MutableConfig
|
A mutable builder initialized from this snapshot. |
Source code in src/topmark/config/model.py
MutableConfig
dataclass
¶
MutableConfig(
*,
policy=MutablePolicy(),
policy_by_type=(lambda: {})(),
config_files=(lambda: [])(),
header_fields=(lambda: [])(),
field_values=(lambda: {})(),
align_fields=None,
relative_to_raw=None,
relative_to=None,
files=(lambda: [])(),
include_from=(lambda: [])(),
exclude_from=(lambda: [])(),
files_from=(lambda: [])(),
include_pattern_groups=(lambda: [])(),
exclude_pattern_groups=(lambda: [])(),
include_file_types=(lambda: set[str]())(),
exclude_file_types=(lambda: set[str]())(),
validation_logs=MutableValidationLogs(),
)
Mutable configuration used during discovery and merging.
This builder collects layered config from defaults, project files, extra files,
and config-like API overrides. It remains convenient to mutate (list/set),
then produces an immutable FrozenConfig via freeze.
TOML I/O is delegated to topmark.config.io to keep
this class focused on merge policy.
Attributes:
| Name | Type | Description |
|---|---|---|
policy |
MutablePolicy
|
Optional global policy overrides (public shape). |
policy_by_type |
dict[str, MutablePolicy]
|
Optional per-type policy. |
config_files |
list[Path | SyntheticConfigSource]
|
List of paths or identifiers for config sources used. |
header_fields |
list[str]
|
List of header fields from the [header] section. |
field_values |
dict[str, str]
|
Mapping of field names to their string values from [fields]. |
align_fields |
bool | None
|
Whether to align fields, from [formatting]. |
relative_to_raw |
str | None
|
Original string from config or CLI |
relative_to |
Path | None
|
Base path used only for resolving header metadata (e.g., |
files |
list[str]
|
List of files to process. |
include_from |
list[PatternSource]
|
Files containing include patterns. |
exclude_from |
list[PatternSource]
|
Files containing exclude patterns. |
files_from |
list[PatternSource]
|
Paths to files that list newline-delimited candidate file paths to add before filtering. |
include_pattern_groups |
list[PatternGroup]
|
Glob patterns to include. |
exclude_pattern_groups |
list[PatternGroup]
|
Glob patterns to exclude. |
include_file_types |
set[str]
|
file type identifiers to process. |
exclude_file_types |
set[str]
|
file type identifiers to exclude. |
validation_logs |
MutableValidationLogs
|
Stage-aware diagnostics collected during config loading and preflight validation. |
is_valid ¶
Return whether this mutable config is valid.
Validity follows the staged config-loading validation semantics described in this module.
Here, strict is the effective resolved strictness used for
config/preflight validation. Callers typically derive it from
strict after applying TOML resolution and any CLI/API
override precedence.
A similar helper exists on FrozenConfig.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
strict
|
bool | None
|
Effective strictness for config/preflight validation. |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
|
Source code in src/topmark/config/model.py
ensure_valid ¶
Raise ConfigValidationError if this mutable config is not valid.
Validity follows the staged config-loading validation semantics described in this module.
Here, strict is the effective resolved strictness used for
config/preflight validation. Callers typically derive it from
strict after applying TOML resolution and any CLI/API
override precedence.
A similar helper exists on FrozenConfig.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
strict
|
bool | None
|
Effective strictness for config/preflight validation. |
None
|
Raises:
| Type | Description |
|---|---|
ConfigValidationError
|
If the mutable config is invalid. |
Source code in src/topmark/config/model.py
freeze ¶
Freeze this mutable builder into an immutable FrozenConfig.
This method applies final sanitation and normalizes internal container
types before constructing the immutable FrozenConfig
snapshot.
Source code in src/topmark/config/model.py
merge_with ¶
Return a new draft that merges self with a higher-precedence other draft.
Merge behavior is field-specific rather than uniformly "last wins". The current policy follows TopMark's layered-config mental model:
- provenance and diagnostics accumulate
- behavioral/configuration fields usually use nearest-wins semantics
- mapping fields usually overlay keys
- discovery pattern groups accumulate across layers
- runtime/execution intent is out of scope for layered config merging
Current merge groups
Provenance and diagnostics:
- config_files: append
- validation_logs: append within each validation stage
Behavioral config:
- header_fields: replace when other provides a non-empty list
- align_fields: replace only when explicitly set in other
- relative_to_raw, relative_to: replace only when explicitly set in other
Policy:
- policy: tri-state field merge via MutablePolicy.merge_with()
- policy_by_type: key-wise merge, then tri-state merge per key
Field values:
- field_values: key-wise overlay; other wins on overlapping keys
Discovery inputs:
- include_pattern_groups, exclude_pattern_groups: append
- include_from, exclude_from, files_from: append
- files: replace when other provides a non-empty list
Discovery filters:
- include_file_types, exclude_file_types: replace when other
provides a non-empty set
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other
|
MutableConfig
|
Higher-precedence config whose values should be merged on top of this draft. |
required |
Returns:
| Type | Description |
|---|---|
MutableConfig
|
A new mutable configuration representing the merged result. |
Source code in src/topmark/config/model.py
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 | |
sanitize ¶
Normalize and sanitize draft config in-place.
This step enforces downstream invariants expected by config resolution,
runtime processing, and related components such as the file resolver,
pipeline, and CLI. It is intended to be called just before freezing into
an immutable FrozenConfig.
Sanitization may drop or rewrite invalid entries and records diagnostics describing those recoveries. These diagnostics are part of the runtime-applicability validation stage and continue to participate in config/preflight validity checks, including strict config checking.
Current rules
- include_from / exclude_from / files_from entries must refer to
concrete files, not glob-style paths. Any
PatternSource.pathcontaining glob metacharacters (*, ?, [, ]) is ignored with a warning. - include_file_types / exclude_file_types entries are resolved from public local-or-qualified identifiers to canonical qualified keys.
- policy_by_type entries are resolved from public local-or-qualified identifiers to canonical qualified keys.
Future extensions may
- validate relative_to vs. config_files,
- check existence of pattern files,
- normalize duplicate patterns or sources.
Source code in src/topmark/config/model.py
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 | |
sanitized_config ¶
Sanitize a FrozenConfig object.
Thaws the FrozenConfig into a
MutableConfig, sanitizes and freezes again.
Sanitization may add staged validation diagnostics, and those diagnostics participate in later config/preflight validity checks.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
FrozenConfig
|
The |
required |
Returns:
| Type | Description |
|---|---|
FrozenConfig
|
The sanitized |