Repository navigation
Modernize string formatting in configparser and its test module #159684
Description
Feature or enhancement
Proposal:
Lib/configparser.py and Lib/test/test_configparser.py still carry a fair
amount of pre-f-string formatting (% formatting and str.format() calls) plus
a handful of constructs that have since acquired simpler spellings. Linting the
two modules with Ruff's current default rule set reports 72 violations:
35 UP032 f-string
17 UP031 printf-string-formatting
3 UP030 format-literals
3 RUF012 mutable-class-default
2 SIM102 collapsible-if
2 C414 unnecessary-double-cast-or-process
1 C408 unnecessary-collection-call
1 C405 unnecessary-literal-set
1 C901 complex-structure
1 F841 unused-variable
1 I001 unsorted-imports
1 ISC004 implicit-string-concatenation-in-collection-literal
1 RUF019 unnecessary-key-check
1 RUF022 unsorted-dunder-all
1 RUF059 unused-unpacked-variable
1 SIM117 multiple-with-statements
None of these are bugs, and CPython's own Ruff configuration only selects F401
and F811 for Lib/, so nothing here is failing today. The proposal is simply
to modernize the two modules: convert the %/.format() call sites to
f-strings, and apply the small set of simplifications above.
Two of the reports need more than a mechanical fix:
-
C901onExtendedInterpolation._interpolate_someis a complexity metric,
not a defect. Splitting that parser loop up would be a much larger and
riskier change, so I propose an explicit# noqa: C901 # gh-159686. The
issue reference rides along in the directive rather than in a comment above
it, so the suppression carries its own trail without adding prose to the
method; configparser: ExtendedInterpolation._interpolate_some exceeds common complexity limits #159686 records why the complexity is inherent to the
interpolation grammar and what a refactoring might look like. -
RUF012wants the mutable class attributes annotatedClassVar, and the
obvious spelling of that would importtypingat runtime, which this module
deliberately avoids (cf. thegh-117703note above the imports). Adding
from __future__ import annotationsand importingClassVaronly under
TYPE_CHECKINGkeepstypingout of the import graph, astomlliband
importlib.metadataalready do.-X importtimeconfirmstypingis still
not imported. A side benefit is thatIterable['ParsingError']can lose its
quotes (UP037).This does make
TYPE_CHECKINGa module-level name, so it needs adding to
not_exportedin thecheck__all__test.
Motivation
Two reasons:
-
These are the usual readability wins. The error paths in particular read
better as f-strings, e.g.- Error.__init__(self, 'No section: %r' % (section,)) + Error.__init__(self, f'No section: {section!r}')
-
configparseris backported to PyPI as
backports.configparser, whose
module is merged from CPython periodically. That project lints with the
default rule set and currently has to carry a per-file exemption for the
CPython-derived files (jaraco/configparser#73). Landing the changes here
lets the backport drop the exemption and keeps the two copies converging
rather than diverging.
I have this working locally as four reviewable commits (the f-string
conversion, the simplifications, the handful of % sites Ruff will not
autofix, and the import/__all__/ClassVar changes above), and I am happy to
put up the PR. With all of it applied, both CPython's own Ruff configuration
and the default rule set report no findings for either file, and
test_configparser, test_logging, test_collections, test___all__ and
test_pydoc all pass.
Has this already been discussed elsewhere?
No response given
Activity
pythongh-159684: Add a NEWS entry