Skip to content

gh-70999: Preserve caller vars in ExtendedInterpolation nested interpolation - #155880

Open
nikolauspschuetz wants to merge 3 commits into
python:mainfrom
nikolauspschuetz:gh-70999-extendedinterpolation-vars
Open

gh-70999: Preserve caller vars in ExtendedInterpolation nested interpolation#155880
nikolauspschuetz wants to merge 3 commits into
python:mainfrom
nikolauspschuetz:gh-70999-extendedinterpolation-vars

Conversation

@nikolauspschuetz

@nikolauspschuetz nikolauspschuetz commented Aug 16, 2026

Copy link
Copy Markdown

ExtendedInterpolation honoured caller-supplied vars only at the first interpolation level. When a value referenced another option in the same section (e.g. a=${b}, b=${c}), the recursive call rebuilt its lookup map from the section and dropped the one carrying vars, so cfg.get('s', 'a', vars={'c': 'x'}) returned the configured c instead of x.

Reuse the caller's map for same-section references — mirroring BasicInterpolation, which already threads the same map through recursion — and only rebuild it when crossing into another section, so vars don't leak across sections. Adds a regression test.

Fixes #70999

…interpolation

ExtendedInterpolation honoured caller-supplied ``vars`` only at the first
level of interpolation. When a value referenced another option in the same
section, the recursive call rebuilt the lookup map from
``parser.items(section, raw=True)``, discarding the map that carried ``vars``.

Mirror BasicInterpolation, which threads the same ``(section, map)`` through
recursion, by reusing ``map`` when the reference stays in the current section
and only rebuilding it when crossing into another section (so ``vars`` do not
leak across sections).
@nikolauspschuetz
nikolauspschuetz force-pushed the gh-70999-extendedinterpolation-vars branch from acd5275 to 0ea8e9d Compare August 16, 2026 03:35
Comment on lines +1350 to +1359
eq = self.assertEqual
# Directly referencing the overridden option already worked.
eq(cf.get('section', 'b', vars={'c': 'OVERRIDE'}), 'OVERRIDE')
# Reaching it through another same-section option must too.
eq(cf.get('section', 'a', vars={'c': 'OVERRIDE'}), 'OVERRIDE')
# Without an override the configured value is still used.
eq(cf.get('section', 'a'), 'default')
# ``vars`` are scoped to the requested section and must not leak
# into a different section reached via ``${section:option}``.
eq(cf.get('cross', 'via', vars={'c': 'OVERRIDE'}), 'default')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that asserts speak for themselves and the comments here are a bit verbose. The above gh-70999 reference is enough.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trimmed those — the asserts stand on their own now, with just the gh-70999 reference kept. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ExtendedInterpolation drops user-defined 'vars' during _interpolate_some() recursion

2 participants