[Python-checkins] gh-89336: Remove configparser APIs that were deprecated for 3.12 (#92503)

gpshead webhook-mailer at python.org
Tue Jun 21 17:31:31 EDT 2022


https://github.com/python/cpython/commit/296e4efebbd1865153ed3be24887a2af3898a0c4
commit: 296e4efebbd1865153ed3be24887a2af3898a0c4
branch: main
author: Gregory P. Smith <greg at krypto.org>
committer: gpshead <greg at krypto.org>
date: 2022-06-21T14:31:25-07:00
summary:

gh-89336: Remove configparser APIs that were deprecated for 3.12 (#92503)

https://github.com/python/cpython/issue/89336: Remove configparser 3.12 deprecations.

Co-authored-by: Hugo van Kemenade <hugovk at users.noreply.github.com>

files:
A Misc/NEWS.d/next/Library/2022-05-08-18-51-14.gh-issue-89336.TL6ip7.rst
M Doc/library/configparser.rst
M Doc/whatsnew/3.12.rst
M Lib/configparser.py
M Lib/test/test_configparser.py

diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst
index 72aa20d73d8bd..bf49f2bfbe1b4 100644
--- a/Doc/library/configparser.rst
+++ b/Doc/library/configparser.rst
@@ -1206,28 +1206,6 @@ ConfigParser Objects
       names is stripped before :meth:`optionxform` is called.
 
 
-   .. method:: readfp(fp, filename=None)
-
-      .. deprecated:: 3.2
-         Use :meth:`read_file` instead.
-
-      .. versionchanged:: 3.2
-         :meth:`readfp` now iterates on *fp* instead of calling ``fp.readline()``.
-
-      For existing code calling :meth:`readfp` with arguments which don't
-      support iteration, the following generator may be used as a wrapper
-      around the file-like object::
-
-         def readline_generator(fp):
-             line = fp.readline()
-             while line:
-                 yield line
-                 line = fp.readline()
-
-      Instead of ``parser.readfp(fp)`` use
-      ``parser.read_file(readline_generator(fp))``.
-
-
 .. data:: MAX_INTERPOLATION_DEPTH
 
    The maximum depth for recursive interpolation for :meth:`get` when the *raw*
@@ -1361,10 +1339,9 @@ Exceptions
 
    Exception raised when errors occur attempting to parse a file.
 
-   .. versionchanged:: 3.2
-      The ``filename`` attribute and :meth:`__init__` argument were renamed to
-      ``source`` for consistency.
-
+.. versionchanged:: 3.12
+   The ``filename`` attribute and :meth:`__init__` constructor argument were
+   removed.  They have been available using the name ``source`` since 3.2.
 
 .. rubric:: Footnotes
 
diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index b7d7eecfedb86..2439479b458d3 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -178,6 +178,16 @@ although there is currently no date scheduled for their removal.
 Removed
 =======
 
+* Several names deprecated in the :mod:`configparser` way back in 3.2 have
+  been removed per :gh:`89336`:
+
+  * :class:`configparser.ParsingError` no longer has a ``filename`` attribute
+    or argument. Use the ``source`` attribute and argument instead.
+  * :mod:`configparser` no longer has a ``SafeConfigParser`` class. Use the
+    shorter :class:`~configparser.ConfigParser` name instead.
+  * :class:`configparser.ConfigParser` no longer has a ``readfp`` method.
+    Use :meth:`~configparser.ConfigParser.read_file` instead.
+
 * The following undocumented :mod:`sqlite3` features, deprecated in Python
   3.10, are now removed:
 
diff --git a/Lib/configparser.py b/Lib/configparser.py
index de9ee537ac188..f98e6fb01f97c 100644
--- a/Lib/configparser.py
+++ b/Lib/configparser.py
@@ -148,14 +148,14 @@
 import sys
 import warnings
 
-__all__ = ["NoSectionError", "DuplicateOptionError", "DuplicateSectionError",
+__all__ = ("NoSectionError", "DuplicateOptionError", "DuplicateSectionError",
            "NoOptionError", "InterpolationError", "InterpolationDepthError",
            "InterpolationMissingOptionError", "InterpolationSyntaxError",
            "ParsingError", "MissingSectionHeaderError",
-           "ConfigParser", "SafeConfigParser", "RawConfigParser",
+           "ConfigParser", "RawConfigParser",
            "Interpolation", "BasicInterpolation",  "ExtendedInterpolation",
            "LegacyInterpolation", "SectionProxy", "ConverterMapping",
-           "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
+           "DEFAULTSECT", "MAX_INTERPOLATION_DEPTH")
 
 _default_dict = dict
 DEFAULTSECT = "DEFAULT"
@@ -297,41 +297,12 @@ def __init__(self, option, section, rawval):
 class ParsingError(Error):
     """Raised when a configuration file does not follow legal syntax."""
 
-    def __init__(self, source=None, filename=None):
-        # Exactly one of `source'/`filename' arguments has to be given.
-        # `filename' kept for compatibility.
-        if filename and source:
-            raise ValueError("Cannot specify both `filename' and `source'. "
-                             "Use `source'.")
-        elif not filename and not source:
-            raise ValueError("Required argument `source' not given.")
-        elif filename:
-            source = filename
-        Error.__init__(self, 'Source contains parsing errors: %r' % source)
+    def __init__(self, source):
+        super().__init__(f'Source contains parsing errors: {source!r}')
         self.source = source
         self.errors = []
         self.args = (source, )
 
-    @property
-    def filename(self):
-        """Deprecated, use `source'."""
-        warnings.warn(
-            "The 'filename' attribute will be removed in Python 3.12. "
-            "Use 'source' instead.",
-            DeprecationWarning, stacklevel=2
-        )
-        return self.source
-
-    @filename.setter
-    def filename(self, value):
-        """Deprecated, user `source'."""
-        warnings.warn(
-            "The 'filename' attribute will be removed in Python 3.12. "
-            "Use 'source' instead.",
-            DeprecationWarning, stacklevel=2
-        )
-        self.source = value
-
     def append(self, lineno, line):
         self.errors.append((lineno, line))
         self.message += '\n\t[line %2d]: %s' % (lineno, line)
@@ -768,15 +739,6 @@ def read_dict(self, dictionary, source='<dict>'):
                 elements_added.add((section, key))
                 self.set(section, key, value)
 
-    def readfp(self, fp, filename=None):
-        """Deprecated, use read_file instead."""
-        warnings.warn(
-            "This method will be removed in Python 3.12. "
-            "Use 'parser.read_file()' instead.",
-            DeprecationWarning, stacklevel=2
-        )
-        self.read_file(fp, source=filename)
-
     def get(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
         """Get an option value for a given section.
 
@@ -1239,19 +1201,6 @@ def _read_defaults(self, defaults):
             self._interpolation = hold_interpolation
 
 
-class SafeConfigParser(ConfigParser):
-    """ConfigParser alias for backwards compatibility purposes."""
-
-    def __init__(self, *args, **kwargs):
-        super().__init__(*args, **kwargs)
-        warnings.warn(
-            "The SafeConfigParser class has been renamed to ConfigParser "
-            "in Python 3.2. This alias will be removed in Python 3.12."
-            " Use ConfigParser directly instead.",
-            DeprecationWarning, stacklevel=2
-        )
-
-
 class SectionProxy(MutableMapping):
     """A proxy for a single section from a parser."""
 
diff --git a/Lib/test/test_configparser.py b/Lib/test/test_configparser.py
index 59c4b275cb46d..5e2715a96b994 100644
--- a/Lib/test/test_configparser.py
+++ b/Lib/test/test_configparser.py
@@ -1612,23 +1612,12 @@ def test_interpolation_depth_error(self):
         self.assertEqual(error.section, 'section')
 
     def test_parsing_error(self):
-        with self.assertRaises(ValueError) as cm:
+        with self.assertRaises(TypeError) as cm:
             configparser.ParsingError()
-        self.assertEqual(str(cm.exception), "Required argument `source' not "
-                                            "given.")
-        with self.assertRaises(ValueError) as cm:
-            configparser.ParsingError(source='source', filename='filename')
-        self.assertEqual(str(cm.exception), "Cannot specify both `filename' "
-                                            "and `source'. Use `source'.")
-        error = configparser.ParsingError(filename='source')
+        error = configparser.ParsingError(source='source')
+        self.assertEqual(error.source, 'source')
+        error = configparser.ParsingError('source')
         self.assertEqual(error.source, 'source')
-        with warnings.catch_warnings(record=True) as w:
-            warnings.simplefilter("always", DeprecationWarning)
-            self.assertEqual(error.filename, 'source')
-            error.filename = 'filename'
-            self.assertEqual(error.source, 'filename')
-        for warning in w:
-            self.assertTrue(warning.category is DeprecationWarning)
 
     def test_interpolation_validation(self):
         parser = configparser.ConfigParser()
@@ -1647,27 +1636,6 @@ def test_interpolation_validation(self):
         self.assertEqual(str(cm.exception), "bad interpolation variable "
                                             "reference '%(()'")
 
-    def test_readfp_deprecation(self):
-        sio = io.StringIO("""
-        [section]
-        option = value
-        """)
-        parser = configparser.ConfigParser()
-        with warnings.catch_warnings(record=True) as w:
-            warnings.simplefilter("always", DeprecationWarning)
-            parser.readfp(sio, filename='StringIO')
-        for warning in w:
-            self.assertTrue(warning.category is DeprecationWarning)
-        self.assertEqual(len(parser), 2)
-        self.assertEqual(parser['section']['option'], 'value')
-
-    def test_safeconfigparser_deprecation(self):
-        with warnings.catch_warnings(record=True) as w:
-            warnings.simplefilter("always", DeprecationWarning)
-            parser = configparser.SafeConfigParser()
-        for warning in w:
-            self.assertTrue(warning.category is DeprecationWarning)
-
     def test_legacyinterpolation_deprecation(self):
         with warnings.catch_warnings(record=True) as w:
             warnings.simplefilter("always", DeprecationWarning)
@@ -1841,7 +1809,7 @@ def test_parsingerror(self):
             self.assertEqual(e1.source, e2.source)
             self.assertEqual(e1.errors, e2.errors)
             self.assertEqual(repr(e1), repr(e2))
-        e1 = configparser.ParsingError(filename='filename')
+        e1 = configparser.ParsingError('filename')
         e1.append(1, 'line1')
         e1.append(2, 'line2')
         e1.append(3, 'line3')
diff --git a/Misc/NEWS.d/next/Library/2022-05-08-18-51-14.gh-issue-89336.TL6ip7.rst b/Misc/NEWS.d/next/Library/2022-05-08-18-51-14.gh-issue-89336.TL6ip7.rst
new file mode 100644
index 0000000000000..b4c58c0e48b25
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-05-08-18-51-14.gh-issue-89336.TL6ip7.rst
@@ -0,0 +1,4 @@
+Removed :mod:`configparser` module APIs:
+the ``SafeConfigParser`` class alias, the ``ParsingError.filename``
+property and parameter, and the ``ConfigParser.readfp`` method, all
+of which were deprecated since Python 3.2.



More information about the Python-checkins mailing list