v4: close out all remaining v4 issues#278
Merged
Merged
Conversation
…218) - New hier_config.registry: register_driver()/unregister_driver()/ get_registered_platforms(). Custom platforms register by string name (case-insensitive, usable anywhere a Platform is accepted); built-in drivers can be overridden and restored. Built-ins register at import. Re-evaluated vs the issue's runtime Platform-enum extension: mutating Enum classes at runtime is fragile; a registry keyed by Platform | str provides the same capability safely. - Registered drivers carry their view via view_class, completing #229. - HConfig.from_text()/from_lines()/from_dump() classmethods replace get_hconfig()/get_hconfig_fast_load()/get_hconfig_from_dump()/ get_hconfig_fast_generic_load() (#218). get_hconfig_driver() and get_hconfig_view() remain standalone utilities. - HConfigDriverBase and HConfigDriverRules are exported as public API. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
) NegationDefaultWithRule, NegationDefaultWhenRule, and NegationSubRule collapse into one NegationRule model with a NegationStrategy enum (REPLACE, DEFAULT, REGEX_SUB) and a single `negation` list on HConfigDriverRules. Precedence is now explicit list order - first matching rule wins - instead of being encoded in method ordering. driver.negate_with() remains as the imperative extension hook (used by HP ProCurve) and reads REPLACE-strategy rules from the unified list. load_driver_rules() still accepts the v2 dict keys (negation_negate_with, negation_default_when, negation_sub) and maps them onto unified rules for Nautobot compatibility. Also silences pylint cyclic-import, which now only fires on the lazy (call-time) imports inside HConfig's classmethod constructors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… format detection (#215, #217, #186, #180, #181, #232) - #215: a ParentAllowsDuplicateChildRule with empty match_rules now applies to the root, unifying root-level duplicate handling with the existing child mechanism (children can never match an empty rule because lineage matching requires equal lengths). - #217: the diff/remediation/future/with_tags algorithms move from HConfigBase into hier_config/tree_algorithms.py as standalone functions (compute_difference, compute_remediation, compute_future, compute_with_tags); HConfigBase keeps thin delegating methods. - #186: _load_from_string_lines() is now a thin wrapper over a stateful _ConfigTextLoader class with focused methods for banner processing, line normalization, and hierarchy construction; drops the C901 noqa. - #180: HConfigDriverRules.remediation_transform_callbacks run on the remediation config in WorkflowRemediation.remediation_config. - #181: RemediationPlugin ABC (hier_config.plugins); user plugins are passed via WorkflowRemediation(plugins=...) and applied after driver callbacks. - #232: XML and JSON inputs are detected in HConfig.from_text() and rejected with a clear InvalidConfigError pointing at the supported set-style paths (JunOS/VyOS/Nokia SRL preprocessors). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
) Migrate README, docs/, and CLAUDE.md to the HConfig.from_* constructors, unified NegationRule, and the driver registry; add a Registering a Custom Driver section; consolidate the Unreleased changelog with the full v4 change set and the documented design decisions for #222, #223, and #224. Adds a regression test pinning that remediation() does not mutate its input configs (#224). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…S/XR views (#227, #230) ConfigViewInterfaceBase now holds only the core surface (name, description, enabled, ipv4_interfaces, is_loopback, is_svi, number, port_number, vrf, plus concrete helpers). Optional capabilities move to ABC mixins - InterfaceBundleViewMixin, InterfaceVlanViewMixin, InterfaceNACViewMixin, InterfacePhysicalViewMixin - so users check capability with isinstance() instead of catching NotImplementedError. HConfigViewBase.bundle_interface_views and module_numbers are capability-aware. All mixins are exported as public API. The EOS, NXOS, and XR views are completed to core + Bundle + Vlan (addresses in CIDR/mask/XR forms, VRF membership, dot1q subinterfaces, switchport access/trunk, Port-Channel/Bundle-Ether bundles, plus root view properties: interface_names_mentioned, ipv4_default_gw, location, stack_members, vlans). No NotImplementedError stubs remain in those views; NAC/Physical are simply not inherited where unsupported. IOS gains bundle_member_interfaces and a case-insensitive is_bundle fix; ProCurve gains a real bundle_id. Raise-only tests are replaced with behavior tests parsing real config snippets and per-platform capability assertions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- port_number now derives from the letter-stripped `number` property on all five platform views, fixing ValueError on slash-less names such as Port-channel10, Bundle-Ether10, and Trk1; regression tests added for IOS, EOS, NX-OS, and XR. - NegationRule validates per-strategy fields at construction: REPLACE requires `use`, REGEX_SUB requires `search` (empty `replace` stays valid for deletion-style substitutions). Previously a REPLACE rule with empty `use` silently fell through to swap_negation. - Align the NegationRule docstring with actual evaluation order (REPLACE rules are consulted first via driver.negate_with(), then remaining rules in list order). - Document that the driver registry is unsynchronized (register at startup) and that structured-format detection only guards from_text(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gins on callables Findings from four parallel cleanup reviews (reuse, simplification, efficiency, altitude) applied: - Hoist ~390 duplicated lines out of the five platform view files: concrete defaults for name/number/port_number/description/enabled/ is_loopback/is_svi on ConfigViewInterfaceBase; bundle_id and bundle_member_interfaces on InterfaceBundleViewMixin keyed by a _bundle_membership_prefix hook; native_vlan/tagged_vlans/tagged_all on InterfaceVlanViewMixin keyed by an _encapsulation_prefix hook; interface_names_mentioned/location/stack_members/vlans defaults on HConfigViewBase; shared parse_ipv4_interface() in platforms.functions. Platforms keep overrides only where behavior genuinely differs (HP ProCurve throughout; XR native_vlan). - Remove the pass-through _future/_with_tags/_remediation/_difference shims from HConfigBase; HConfig calls the tree_algorithms functions directly. - from_lines()/from_dump() build their empty tree via HConfig(driver) instead of routing "" through the full text pipeline; the structured- format guard now also covers the raw-str form of from_lines() and inspects a bounded prefix instead of copying the whole input. - WorkflowRemediation(plugins=...) accepts plain callables; RemediationPlugin gained __call__ as sugar. - Replace the side-effecting `elif predicate: pass` in _ConfigTextLoader with a positive branch. - Adapt to ruff 0.15.22 (new preview rules from the renovate lock bump): noun-phrase property docstrings, per-file PLC0415 ignore for the lazy classmethod imports, unused TypeVar removal. Deliberate skips: single-pass negation evaluation (would change driver- facing precedence), caching the root duplicate-rule check (rules are mutated post-init by the documented extension pattern), dropping plugin name/description metadata (specified by #181), and the full constructors/root cycle removal (blocked by pydantic runtime type resolution in driver_base). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
get_child(startswith="") matches any first child, so a platform that inherits InterfaceBundleViewMixin without declaring _bundle_membership_prefix would get garbage from the default bundle_id and bundle_member_interfaces instead of failing inert. Both defaults now short-circuit when the prefix is unset; pinned by a regression test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
One large PR completing the remaining v4 work. Each issue was re-evaluated on its merits; where the issue's proposed approach wasn't the best fit, the deviation is explained below and in
CHANGELOG.md.Closes #226, closes #229, closes #218, closes #220, closes #215, closes #217, closes #186, closes #180, closes #181, closes #232, closes #227, closes #230, closes #222, closes #223, closes #224.
Implemented
hier_config.registry:register_driver(),unregister_driver(),get_registered_platforms(). Custom platforms register by string name (case-insensitive, usable anywhere aPlatformis accepted); built-in drivers can be overridden and restored.HConfigDriverBase/HConfigDriverRulesare public API. Re-evaluation: runtimePlatformenum mutation (the issue's sketch) is fragile; a registry keyed byPlatform | strdelivers the same capability safely.view_class(built on Resolve config views from the driver's view_class attribute (#187) #275); custom platforms get views with zero extra wiring.HConfig.from_text()/from_lines()/from_dump()classmethods replaceget_hconfig(),get_hconfig_fast_load(),get_hconfig_from_dump(),get_hconfig_fast_generic_load().get_hconfig_driver()/get_hconfig_view()remain standalone. All call sites, docs, and CLAUDE.md migrated.NegationRulemodel +NegationStrategyenum (REPLACE/DEFAULT/REGEX_SUB) in one orderednegationlist; first match wins.load_driver_rules()still accepts the v2 dict keys for Nautobot compatibility.ParentAllowsDuplicateChildRulewith emptymatch_rulesapplies to the root (children can never match an empty rule, so the mechanism unifies cleanly).compute_difference/compute_remediation/compute_future/compute_with_tagsextracted tohier_config/tree_algorithms.py;HConfigBasekeeps thin delegates._load_from_string_lines()is now a stateful_ConfigTextLoaderwith focused banner/normalize/hierarchy methods; theC901noqa is gone.remediation_transform_callbacksonHConfigDriverRules, applied inWorkflowRemediation.remediation_config.RemediationPluginABC (hier_config.plugins) +WorkflowRemediation(plugins=...), applied after driver callbacks.InvalidConfigError; set-style is already natively supported (JunOS/VyOS/Nokia SRL preprocessors). Full XML/JSON ingestion is additive and deferred past 4.0 per the issue's own "no breaking change" framing.ConfigViewInterfaceBasereduced to a core surface; optional capabilities split intoInterfaceBundleViewMixin,InterfaceVlanViewMixin,InterfaceNACViewMixin,InterfacePhysicalViewMixinwithisinstancecapability checks. Also fixes IOSis_bundlecase-sensitivity.NotImplementedErrorstubs remain in them.Documented decisions (see CHANGELOG "v4 design decisions")
HConfig.remediation()stays public: v4: Rename inconsistent public APIs #216 deliberately renamed it as the tree-level primitive, andWorkflowRemediation(which already validates driver compatibility withIncompatibleDriverError) remains the recommended workflow API.idempotent_for(),negate_with(),config_preprocessor()remain overridable for logic rules cannot express.remediation()never mutates its inputs.Test plan
poetry run ./scripts/build.py lint-and-test— ruff, mypy strict, pyright strict, pylint, yamllint, flynt all pass; 660 tests, 98% coverage (≥95% required).🤖 Generated with Claude Code