ExtendedInterpolation._interpolate_some in Lib/configparser.py has a
cyclomatic complexity of 13, above the McCabe default limit of 10 that most
linters ship with. Its sibling BasicInterpolation._interpolate_some sits
exactly at 10, so both are at or past the line.
The method is a hand-rolled scanner: a while rest: loop that locates the next
$, then branches on the following character, and for ${...} splits the
reference on : and dispatches on whether the result has one component (an
option in the current section), two (a section and an option) or more (an
error), with a try/except mapping three different lookup failures onto
InterpolationMissingOptionError, before recursing. Every branch of that
dispatch is also a place an interpolation bug could hide, and the structure is
duplicated in near-identical form in BasicInterpolation.
One plausible direction, without changing any behavior: extract the reference
resolution (from path = m.group(1).split(':') through the try/except)
into a small helper that returns the resolved value or raises. That removes
most of the branching from the loop, and the two _interpolate_some
implementations would then differ mainly in their sigil and their key regex.
I'm not proposing a particular refactoring here; the method is correct and
well-tested, and reshaping it has real risk. I'd rather this be a tracked,
visible concern than an invisible one.
Motivation
gh-159684 brings Lib/configparser.py up to Ruff's default rule set, and
everything else it reports can be fixed mechanically. C901 is the exception:
it is a measurement, not a defect, and there is no small edit that satisfies
it. That PR therefore adds an explicit # noqa: C901 with a comment pointing
here, so the suppression is documented rather than silent, and so anyone who
wonders why it is there finds the reasoning and can pick up the refactoring if
they think it is worth doing.
Activity