Restore the v3 public names as a permanent v4 API - #300
Merged
Conversation
v4 renamed or removed a set of names that v3 users call every day, with no alias anywhere in the package. A v3 consumer upgrading hit an ImportError or AttributeError on the first line. nautobot-golden-config is the reference case: three missing names (get_hconfig, hconfig_v2_os_v3_platform_mapper, load_hconfig_v2_options) blocked it entirely. Restore every renamed or removed name as a thin delegation to its v4 counterpart. No DeprecationWarning, no planned removal -- the old spellings are a supported part of the v4 API. Delegating rather than copying means the two spellings cannot drift apart. HConfigDriverRules regains negate_with, negation_default_when, and negation_sub as declared fields so type checkers accept them; an after-model validator folds their contents into the unified negation list in the order DEFAULT, REPLACE, REGEX_SUB, matching load_driver_rules() and reproducing the v3 resolution priority. They are constructor inputs only. Prove parity with the real thing: tests/integration/v3_scenarios.py mirrors golden config's _get_hierconfig_remediation and imports under both majors. test_v3_baseline.py compares 28 scenarios against a committed v3.7.0 recording on every push; test_v3_differential.py (marker v3_differential, deselected by default) diffs against a live v3 install. All 28 scenarios match v3 byte for byte. Out of scope, and documented as such: depth() became a property, several call sites raise typed exceptions instead of ValueError, and the EOS/NX-OS/XR views return data where v3 raised NotImplementedError. Claude-Session: https://claude.ai/code/session_01HbMucj2WqnL685BRUcFhZT
Code review found that v3's own custom-driver documentation teaches driver.rules.negate_with.append(...) in three places (docs/user/custom-drivers.md lines 193, 276, 410 at tag v3.7.0). Folding those fields into the unified negation list once at validation meant that idiom still ran, silently did nothing, and produced a different -- potentially destructive -- remediation. The premise behind the constructor-only decision was wrong. Replace the after-model validator with HConfigDriverRules.all_negation_rules(), which resolves `negation` plus the three v3 fields on every lookup. driver.negate_with() and HConfigChild.negate() read through it. Appending to either spelling now takes effect, and because nothing is mutated, re-validating a rules model no longer duplicates every v3 rule -- HConfigDriverRules( **base.model_dump(), negate_with=[...]) was silently doubling them. The no-v3- rules path returns `negation` itself, so the common case allocates nothing. Add options:negation_appended to the shared scenario module, exercising the append idiom end to end. It matches v3.7.0 byte for byte, as do the other 28. Also from the review: - Restore HConfigChild.use_default_for_negation(), the one v3 public name still missing. The compatibility page claimed every v3 name worked; now it does. - Correct CHANGELOG.md, which listed names under Removed that this branch retains, and add the missing issue references. - Fix the hconfig_v2_os_v3_platform_mapper doctest: Platform is a str-mixin enum, so the repr is quoted. Claude-Session: https://claude.ai/code/session_01HbMucj2WqnL685BRUcFhZT
|
Claude finished @jtdub's task in 3m 42s —— View job Review complete ✅
Gates: BlockersNone. Should fix
Nits
Notes (not findings, for context)
Verdict against AGENTS.md "Before Opening a PR"
Pass. No blockers found; the two "should fix" items are doc-wording accuracy issues, not code or hard-rule violations. |
PR review found that "Behavior changes to review" in the migration guide claimed every item under it was something the v3 compatibility surface could not absorb. Three of the six -- future() negation resolution, structured input rejection, and custom driver wiring -- were never candidates for name-alias coverage. Grouping them with the genuine gaps overstated what the surface was meant to cover. Split the section. "Gaps the v3 compatibility surface cannot cover" holds the four changes that reach code keeping the v3 spellings: the depth property, the typed exceptions, the completed views, and XML/JSON rejection -- which belongs there because the restored get_hconfig() raises where v3 did not. "Other v4 changes worth reviewing" holds the rest. Both pages now state four consistently; the compatibility page said four while the PR description said three. Also drop a copy-paste leftover in test_load_hconfig_v2_options_from_file: it took the tags_file_path fixture and asserted the file exists, neither of which relates to what it exercises. Its remaining assertion now reads through all_negation_rules() rather than the raw negation list. Claude-Session: https://claude.ai/code/session_01HbMucj2WqnL685BRUcFhZT
|
Claude finished @jtdub's task in 1m 30s —— View job Review complete ✅
Gates: Both "Should fix" items from the previous review pass are resolved in
BlockersNone. Should fixNone. NitsNone. Verdict against AGENTS.md "Before Opening a PR"
Pass. No blockers, no should-fix items, no nits remaining. |
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
Makes v4 a non-breaking upgrade for v3 users. Every v3 public name that v4 renamed or removed is restored as a thin delegation to its v4 counterpart — no
DeprecationWarning, no planned removal. The old spellings become a supported, documented, tested part of the v4 API.nautobot-golden-configdrove the scope. Its whole hier_config surface is six items; three were missing and blocked it entirely (get_hconfig,hconfig_v2_os_v3_platform_mapper,load_hconfig_v2_options). Its code now runs unedited once it widens thehier-config = "^3.4.1"pin.What is restored
get_hconfig,get_hconfig_fast_load,get_hconfig_from_dump,get_hconfig_fast_generic_load;get_hconfig_driverre-exported fromhier_config.constructorsconfig_to_get_to,dump_simple,cisco_style_text,tags_add,tags_remove,use_default_for_negationload_hconfig_v2_options,load_hconfig_v2_tags,load_hconfig_v2_options_from_file,HCONFIG_PLATFORM_V2_TO_V3_MAPPING, both platform mappersNegationDefaultWithRule,NegationDefaultWhenRule,NegationSubRuleDelegating rather than copying means the two spellings cannot drift apart.
Negation rules stay live
HConfigDriverRuleskeepsnegate_with,negation_default_when, andnegation_subas declared fields, so mypy and pyright accept them.all_negation_rules()resolves them together with the unifiednegationlist on every lookup, rather than folding once at validation.That matters: v3's own
docs/user/custom-drivers.mdteachesdriver.rules.negate_with.append(...)in three places. Folding at validation left that idiom running silently with no effect, producing a different — potentially destructive — remediation. Resolving at lookup time also means re-validating a rules model never duplicates rules, soHConfigDriverRules(**base.model_dump(), negate_with=[...])is safe. The no-v3-rules path returnsnegationitself, so the common case allocates nothing.Proving parity, not asserting it
tests/integration/v3_scenarios.pymirrorsnautobot_golden_config.models._get_hierconfig_remediationstep for step and imports under both major versions. It covers 29 scenarios: the plain golden config path over three fixture pairs, every driver name the v2 mapper knows plus the unknown and whitespace-padded forms, a full v2 options dict firing all three negation strategies, the same rules applied by append, tag filtering, and the restored names golden config does not call.Two tests consume it:
test_v3_baseline.pycompares againsttests/fixtures/v3_baseline.json, a committed recording made on 3.7.0. Runs in the normal suite — no network, no second environment.test_v3_differential.pydiffs against a live v3 install. Deselected by default via the newv3_differentialmarker; run it withpoetry run pytest -m v3_differential.All 29 scenarios match v3.7.0 byte for byte. Regenerate the recording with
./scripts/generate_v3_baseline.py.Still breaking, and documented as such
Three v4 changes cannot be absorbed by a name alias.
docs/user/v3-compatibility.mdand the migration guide both state them:depth()became thedepthproperty — the one required call-site edit.DriverNotFoundError/InvalidConfigError/IncompatibleDriverErrorreplaceValueError.NotImplementedError.So
4.0.0remains correct under semver.Also in here
docs/user/v3-compatibility.md, added to the nav.CHANGELOG.md's### Removedsection listed names this branch retains. Corrected.Known gap, deliberately left out
HCONFIG_PLATFORM_V2_TO_V3_MAPPINGhas no entries forHP_PROCURVE,HP_COMWARE5, orFORTINET_FORTIOS, so those devices fall through toPlatform.GENERICand get a wrong remediation with no error. The table is restored verbatim from v3, so adding entries would change behavior and break the v3 parity contract these tests enforce. It also needs netutils' exact driver-name strings, which I did not want to guess. Worth a follow-up issue.Self-Review Checklist
poetry run ./scripts/build.py lint-and-testpasses locally (lint + 95% test coverage). 846 tests, 97% coverage.CHANGELOG.mdhas an entry under## [Unreleased]referencing this issue/PR ((#NNN)).mkdocs build --strictpasses if docs were touched).AI-Assisted Contributions
Written with Claude Code. Reviewed with
/code-reviewand/security-reviewbefore opening.The code review found one HIGH issue — the negation append idiom described above — which is fixed in
2086635, along with a non-idempotent validator, the missinguse_default_for_negation, an overstated changelog, and a wrong doctest.The security review found no vulnerabilities. It cleared
formats.pyXML parsing (no XXE), all YAML loading (safe_loadthroughout), the driver registry (no import-by-string), and bothsubprocess.runcalls (list argv, no interpolated data).https://claude.ai/code/session_01HbMucj2WqnL685BRUcFhZT