Skip to content

bpo-45173: Keep configparser deprecations until Python 3.12 #30952

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions Doc/library/configparser.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1201,6 +1201,28 @@ 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*
Expand Down Expand Up @@ -1338,9 +1360,6 @@ Exceptions
The ``filename`` attribute and :meth:`__init__` argument were renamed to
``source`` for consistency.

.. versionchanged:: 3.11
The deprecated ``filename`` attribute was removed.


.. rubric:: Footnotes

Expand Down
17 changes: 10 additions & 7 deletions Doc/whatsnew/3.11.rst
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,16 @@ Deprecated
as deprecated, its docstring is now corrected).
(Contributed by Hugo van Kemenade in :issue:`45837`.)

* The following have been deprecated in :mod:`configparser` since Python 3.2.
Their deprecation warnings have now been updated to note they will removed in
Python 3.12:

* the :class:`configparser.SafeConfigParser` class
* the :attr:`configparser.ParsingError.filename` property
* the :meth:`configparser.ParsingError.readfp` method

(Contributed by Hugo van Kemenade in :issue:`45173`.)

Removed
=======

Expand Down Expand Up @@ -501,13 +511,6 @@ Removed
the ``l*gettext()`` functions.
(Contributed by Dong-hee Na and Serhiy Storchaka in :issue:`44235`.)

* Removed from the :mod:`configparser` module:
the :class:`SafeConfigParser` class,
the :attr:`filename` property of the :class:`ParsingError` class,
the :meth:`readfp` method of the :class:`ConfigParser` class,
deprecated since Python 3.2.
(Contributed by Hugo van Kemenade in :issue:`45173`.)

* The :func:`@asyncio.coroutine <asyncio.coroutine>` :term:`decorator` enabling
legacy generator-based coroutines to be compatible with async/await code.
The function has been deprecated since Python 3.8 and the removal was
Expand Down
45 changes: 44 additions & 1 deletion Lib/configparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,12 +146,13 @@
import os
import re
import sys
import warnings

__all__ = ["NoSectionError", "DuplicateOptionError", "DuplicateSectionError",
"NoOptionError", "InterpolationError", "InterpolationDepthError",
"InterpolationMissingOptionError", "InterpolationSyntaxError",
"ParsingError", "MissingSectionHeaderError",
"ConfigParser", "RawConfigParser",
"ConfigParser", "SafeConfigParser", "RawConfigParser",
"Interpolation", "BasicInterpolation", "ExtendedInterpolation",
"LegacyInterpolation", "SectionProxy", "ConverterMapping",
"DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
Expand Down Expand Up @@ -311,6 +312,26 @@ def __init__(self, source=None, filename=None):
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)
Expand Down Expand Up @@ -733,6 +754,15 @@ 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.

Expand Down Expand Up @@ -1195,6 +1225,19 @@ 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."""

Expand Down
28 changes: 28 additions & 0 deletions Lib/test/test_configparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1612,6 +1612,13 @@ def test_parsing_error(self):
"and `source'. Use `source'.")
error = configparser.ParsingError(filename='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()
Expand All @@ -1630,6 +1637,27 @@ 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_sectionproxy_repr(self):
parser = configparser.ConfigParser()
parser.read_string("""
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Note the configparser deprecations will be removed in Python 3.12.