Fix: Sub() now preserves pflag bindings for nested keys (#2089) #2090
+466
−2
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.
Problem
When binding a pflag to a nested key (e.g.,
"test.test_field") and then callingSub("test"), the pflag binding was lost in the sub-Viper instance. This caused:sub-Viperdoesn't include thepflag-boundkeyUnmarshal()on thesub-Viperdoesn't populate fields bound to pflagsRelated
Fixes #2089
Reproduction
Consider the following code:
Output before Fix
Issues:
AllKeys()only shows[test_field2], missingtest_field.TestFieldunmarshals tofalseinstead oftrue.sub-viperdoesn't.Root Cause
The
Sub()method only copied the stored config values, but didn't copy the pflag bindings that tell it where to get values from flags.Viper stores bindings separately:
v.pflags- pflag bindingsv.env- environment variable bindingsv.aliases- key aliasesv.defaults- default valuesv.override- override valuesWhen creating a sub-Viper, these binding maps were not copied for keys matching the subtree prefix, so the sub-Viper lost all context about bound flags.
Solution
Modified the
Sub()method to:pflagbindings that have the requested key as a prefixenvbindings that match the subtreealiasesthat reference keys in the subtreedefaultsand overrides from the subtreeChanges
Modified Files
viper.go: Updated Sub() method to copy all binding types
Key Implementation Details
strings.CutPrefix()to efficiently check and remove prefixes.searchMap()to extract nested defaults and overrides.Testing
Added comprehensive test coverage in
viper_test.go:Core Fix Tests
TestSubWithNestedPFlagBindings- Basic nested pflag binding (issue BindFlags does not work well with nested keys #2089)TestSubWithMultipleNestedPFlagBindings- Multiple pflags in subtreeTestSubWithDeepNestedPFlagBindings- Multi-level Sub() calls.Binding Types
TestSubWithEnvBindings- Environment variable bindingsTestSubWithAliases- Alias preservationTestSubWithDefaults- Default valuesIntegration & Edge Cases
TestSubWithMixedSources- Combining pflags, env, defaults, Set()TestSubWithoutPFlagBindings- Backwards compatibilityTestSubReturnsNilForNonExistentKey- Nil for missing keysTestSubWithCaseSensitivity- Case-insensitive handlingTestSubSharesConfigWithParent- Config sharing behaviorTestSubWithBoolPFlags- Boolean flag typesTestSubWithSlicePFlags- Array/slice flag typesTestSubWithUnsetPFlag- Flags using defaultsTestSubPriorityOrder- Value precedence (Set > PFlag > Default)TestSubPreservesKeyDelimiter- Custom delimiter supportTestSubWithIntAndFloatPFlags- Numeric typesTestMultipleSubCallsIndependence- Multiple Sub() isolationOutput after Fix
Breaking Changes
None. This is a pure bug fix that adds missing functionality. All existing code continues to work as before.
Sub()without pflags works identically (tested)pflag/env/alias/defaultscopying