From 3f9c60f51ef820937e7e0f95f45e63fa0ae21e6c Mon Sep 17 00:00:00 2001 From: Hugo van Kemenade Date: Fri, 26 May 2023 09:06:32 +0300 Subject: [PATCH] gh-104886: Remove deprecated configparser.LegacyInterpolation (#104887) Co-authored-by: Victor Stinner --- Doc/whatsnew/3.13.rst | 7 +++ Lib/configparser.py | 49 +------------------ Lib/test/test_configparser.py | 42 ---------------- Misc/NEWS.d/3.11.0a7.rst | 2 +- ...-05-24-21-30-40.gh-issue-104886.8TuV-_.rst | 3 ++ 5 files changed, 12 insertions(+), 91 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2023-05-24-21-30-40.gh-issue-104886.8TuV-_.rst diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index 29ad0febb8b432..0e78a080c4304b 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -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. @@ -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. diff --git a/Lib/configparser.py b/Lib/configparser.py index dee5a0db7e7ddc..9640f71adc7718 100644 --- a/Lib/configparser.py +++ b/Lib/configparser.py @@ -155,7 +155,7 @@ "ParsingError", "MissingSectionHeaderError", "ConfigParser", "RawConfigParser", "Interpolation", "BasicInterpolation", "ExtendedInterpolation", - "LegacyInterpolation", "SectionProxy", "ConverterMapping", + "SectionProxy", "ConverterMapping", "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH") _default_dict = dict @@ -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.""" diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py index da17c00063c56d..eef439412528d3 100644 --- a/Lib/test/test_configparser.py +++ b/Lib/test/test_configparser.py @@ -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() @@ -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', ''), @@ -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" @@ -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"]: @@ -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(""" diff --git a/Misc/NEWS.d/3.11.0a7.rst b/Misc/NEWS.d/3.11.0a7.rst index 8e7ccd4d6771ee..5e9aadf6395659 100644 --- a/Misc/NEWS.d/3.11.0a7.rst +++ b/Misc/NEWS.d/3.11.0a7.rst @@ -989,7 +989,7 @@ references in :ref:`PEP 585 generic aliases `. .. 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. diff --git a/Misc/NEWS.d/next/Library/2023-05-24-21-30-40.gh-issue-104886.8TuV-_.rst b/Misc/NEWS.d/next/Library/2023-05-24-21-30-40.gh-issue-104886.8TuV-_.rst new file mode 100644 index 00000000000000..2f6796bed7b17c --- /dev/null +++ b/Misc/NEWS.d/next/Library/2023-05-24-21-30-40.gh-issue-104886.8TuV-_.rst @@ -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.