Skip to content

Commit

Permalink
pythongh-104886: Remove deprecated configparser.LegacyInterpolation (p…
Browse files Browse the repository at this point in the history
…ython#104887)

Co-authored-by: Victor Stinner <vstinner@python.org>
  • Loading branch information
hugovk and vstinner committed May 26, 2023
1 parent 0242e9a commit 3f9c60f
Show file tree
Hide file tree
Showing 5 changed files with 12 additions and 91 deletions.
7 changes: 7 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ Removed
* Remove support for using :class:`pathlib.Path` objects as context managers.
This functionality was deprecated and made a no-op in Python 3.9.

* Remove the undocumented :class:`!configparser.LegacyInterpolation` class,
deprecated in the docstring since Python 3.2,
and with a deprecation warning since Python 3.11.
(Contributed by Hugo van Kemenade in :gh:`104886`.)

* Remove the :meth:`!turtle.RawTurtle.settiltangle` method,
deprecated in docs since Python 3.1
and with a deprecation warning since Python 3.11.
Expand All @@ -135,6 +140,8 @@ Removed
* :meth:`unittest.TestLoader.loadTestsFromTestCase`
* :meth:`unittest.TestLoader.getTestCaseNames`

(Contributed by Hugo van Kemenade in :gh:`104835`.)

* :pep:`594`: Remove the :mod:`!cgi`` and :mod:`!cgitb` modules,
deprecated in Python 3.11.

Expand Down
49 changes: 1 addition & 48 deletions Lib/configparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@
"ParsingError", "MissingSectionHeaderError",
"ConfigParser", "RawConfigParser",
"Interpolation", "BasicInterpolation", "ExtendedInterpolation",
"LegacyInterpolation", "SectionProxy", "ConverterMapping",
"SectionProxy", "ConverterMapping",
"DEFAULTSECT", "MAX_INTERPOLATION_DEPTH")

_default_dict = dict
Expand Down Expand Up @@ -491,53 +491,6 @@ def _interpolate_some(self, parser, option, accum, rest, section, map,
"found: %r" % (rest,))


class LegacyInterpolation(Interpolation):
"""Deprecated interpolation used in old versions of ConfigParser.
Use BasicInterpolation or ExtendedInterpolation instead."""

_KEYCRE = re.compile(r"%\(([^)]*)\)s|.")

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
warnings.warn(
"LegacyInterpolation has been deprecated since Python 3.2 "
"and will be removed from the configparser module in Python 3.13. "
"Use BasicInterpolation or ExtendedInterpolation instead.",
DeprecationWarning, stacklevel=2
)

def before_get(self, parser, section, option, value, vars):
rawval = value
depth = MAX_INTERPOLATION_DEPTH
while depth: # Loop through this until it's done
depth -= 1
if value and "%(" in value:
replace = functools.partial(self._interpolation_replace,
parser=parser)
value = self._KEYCRE.sub(replace, value)
try:
value = value % vars
except KeyError as e:
raise InterpolationMissingOptionError(
option, section, rawval, e.args[0]) from None
else:
break
if value and "%(" in value:
raise InterpolationDepthError(option, section, rawval)
return value

def before_set(self, parser, section, option, value):
return value

@staticmethod
def _interpolation_replace(match, parser):
s = match.group(1)
if s is None:
return match.group()
else:
return "%%(%s)s" % parser.optionxform(s)


class RawConfigParser(MutableMapping):
"""ConfigParser that does not do interpolation."""

Expand Down
42 changes: 0 additions & 42 deletions Lib/test/test_configparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -907,9 +907,6 @@ def test_interpolation(self):
if self.interpolation == configparser._UNSET:
self.assertEqual(e.args, ("bar11", "Foo",
"something %(with11)s lots of interpolation (11 steps)"))
elif isinstance(self.interpolation, configparser.LegacyInterpolation):
self.assertEqual(e.args, ("bar11", "Foo",
"something %(with11)s lots of interpolation (11 steps)"))

def test_interpolation_missing_value(self):
cf = self.get_interpolation_config()
Expand All @@ -921,9 +918,6 @@ def test_interpolation_missing_value(self):
if self.interpolation == configparser._UNSET:
self.assertEqual(e.args, ('name', 'Interpolation Error',
'%(reference)s', 'reference'))
elif isinstance(self.interpolation, configparser.LegacyInterpolation):
self.assertEqual(e.args, ('name', 'Interpolation Error',
'%(reference)s', 'reference'))

def test_items(self):
self.check_items_config([('default', '<default>'),
Expand All @@ -942,9 +936,6 @@ def test_safe_interpolation(self):
self.assertEqual(cf.get("section", "ok"), "xxx/%s")
if self.interpolation == configparser._UNSET:
self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
elif isinstance(self.interpolation, configparser.LegacyInterpolation):
with self.assertRaises(TypeError):
cf.get("section", "not_ok")

def test_set_malformatted_interpolation(self):
cf = self.fromstring("[sect]\n"
Expand Down Expand Up @@ -1025,31 +1016,6 @@ class CustomConfigParser(configparser.ConfigParser):
cf.read_string(self.ini)
self.assertMatchesIni(cf)


class ConfigParserTestCaseLegacyInterpolation(ConfigParserTestCase):
config_class = configparser.ConfigParser
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
interpolation = configparser.LegacyInterpolation()

def test_set_malformatted_interpolation(self):
cf = self.fromstring("[sect]\n"
"option1{eq}foo\n".format(eq=self.delimiters[0]))

self.assertEqual(cf.get('sect', "option1"), "foo")

cf.set("sect", "option1", "%foo")
self.assertEqual(cf.get('sect', "option1"), "%foo")
cf.set("sect", "option1", "foo%")
self.assertEqual(cf.get('sect', "option1"), "foo%")
cf.set("sect", "option1", "f%oo")
self.assertEqual(cf.get('sect', "option1"), "f%oo")

# bug #5741: double percents are *not* malformed
cf.set("sect", "option2", "foo%%bar")
self.assertEqual(cf.get("sect", "option2"), "foo%%bar")


class ConfigParserTestCaseInvalidInterpolationType(unittest.TestCase):
def test_error_on_wrong_type_for_interpolation(self):
for value in [configparser.ExtendedInterpolation, 42, "a string"]:
Expand Down Expand Up @@ -1636,14 +1602,6 @@ def test_interpolation_validation(self):
self.assertEqual(str(cm.exception), "bad interpolation variable "
"reference '%(()'")

def test_legacyinterpolation_deprecation(self):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter("always", DeprecationWarning)
configparser.LegacyInterpolation()
self.assertGreaterEqual(len(w), 1)
for warning in w:
self.assertIs(warning.category, DeprecationWarning)

def test_sectionproxy_repr(self):
parser = configparser.ConfigParser()
parser.read_string("""
Expand Down
2 changes: 1 addition & 1 deletion Misc/NEWS.d/3.11.0a7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -989,7 +989,7 @@ references in :ref:`PEP 585 generic aliases <types-genericalias>`.
.. nonce: xnhT4a
.. section: Library
Add :exc:`DeprecationWarning` to :class:`LegacyInterpolation`, deprecated in
Add :exc:`DeprecationWarning` to :class:`!LegacyInterpolation`, deprecated in
the docstring since Python 3.2. Will be removed in Python 3.13. Use
:class:`BasicInterpolation` or :class:`ExtendedInterpolation` instead.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Remove the undocumented :class:`!configparser.LegacyInterpolation` class,
deprecated in the docstring since Python 3.2, and with a deprecation warning
since Python 3.11. Patch by Hugo van Kemenade.

0 comments on commit 3f9c60f

Please sign in to comment.