Skip to content

Commit e8659b4

Browse files
authored
bpo-45173: Keep configparser deprecations until Python 3.12 (GH-30952)
* Revert "bpo-45173 Remove configparser deprecations" This reverts commit df2284b. * bpo-45173: Note these configparser deprecations will be removed in 3.12
1 parent 38e0b9e commit e8659b4

File tree

5 files changed

+105
-11
lines changed

5 files changed

+105
-11
lines changed

Doc/library/configparser.rst

+22-3
Original file line numberDiff line numberDiff line change
@@ -1201,6 +1201,28 @@ ConfigParser Objects
12011201
names is stripped before :meth:`optionxform` is called.
12021202

12031203

1204+
.. method:: readfp(fp, filename=None)
1205+
1206+
.. deprecated:: 3.2
1207+
Use :meth:`read_file` instead.
1208+
1209+
.. versionchanged:: 3.2
1210+
:meth:`readfp` now iterates on *fp* instead of calling ``fp.readline()``.
1211+
1212+
For existing code calling :meth:`readfp` with arguments which don't
1213+
support iteration, the following generator may be used as a wrapper
1214+
around the file-like object::
1215+
1216+
def readline_generator(fp):
1217+
line = fp.readline()
1218+
while line:
1219+
yield line
1220+
line = fp.readline()
1221+
1222+
Instead of ``parser.readfp(fp)`` use
1223+
``parser.read_file(readline_generator(fp))``.
1224+
1225+
12041226
.. data:: MAX_INTERPOLATION_DEPTH
12051227

12061228
The maximum depth for recursive interpolation for :meth:`get` when the *raw*
@@ -1338,9 +1360,6 @@ Exceptions
13381360
The ``filename`` attribute and :meth:`__init__` argument were renamed to
13391361
``source`` for consistency.
13401362

1341-
.. versionchanged:: 3.11
1342-
The deprecated ``filename`` attribute was removed.
1343-
13441363

13451364
.. rubric:: Footnotes
13461365

Doc/whatsnew/3.11.rst

+10-7
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,16 @@ Deprecated
458458
as deprecated, its docstring is now corrected).
459459
(Contributed by Hugo van Kemenade in :issue:`45837`.)
460460

461+
* The following have been deprecated in :mod:`configparser` since Python 3.2.
462+
Their deprecation warnings have now been updated to note they will removed in
463+
Python 3.12:
464+
465+
* the :class:`configparser.SafeConfigParser` class
466+
* the :attr:`configparser.ParsingError.filename` property
467+
* the :meth:`configparser.ParsingError.readfp` method
468+
469+
(Contributed by Hugo van Kemenade in :issue:`45173`.)
470+
461471
Removed
462472
=======
463473

@@ -502,13 +512,6 @@ Removed
502512
the ``l*gettext()`` functions.
503513
(Contributed by Dong-hee Na and Serhiy Storchaka in :issue:`44235`.)
504514

505-
* Removed from the :mod:`configparser` module:
506-
the :class:`SafeConfigParser` class,
507-
the :attr:`filename` property of the :class:`ParsingError` class,
508-
the :meth:`readfp` method of the :class:`ConfigParser` class,
509-
deprecated since Python 3.2.
510-
(Contributed by Hugo van Kemenade in :issue:`45173`.)
511-
512515
* The :func:`@asyncio.coroutine <asyncio.coroutine>` :term:`decorator` enabling
513516
legacy generator-based coroutines to be compatible with async/await code.
514517
The function has been deprecated since Python 3.8 and the removal was

Lib/configparser.py

+44-1
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,13 @@
146146
import os
147147
import re
148148
import sys
149+
import warnings
149150

150151
__all__ = ["NoSectionError", "DuplicateOptionError", "DuplicateSectionError",
151152
"NoOptionError", "InterpolationError", "InterpolationDepthError",
152153
"InterpolationMissingOptionError", "InterpolationSyntaxError",
153154
"ParsingError", "MissingSectionHeaderError",
154-
"ConfigParser", "RawConfigParser",
155+
"ConfigParser", "SafeConfigParser", "RawConfigParser",
155156
"Interpolation", "BasicInterpolation", "ExtendedInterpolation",
156157
"LegacyInterpolation", "SectionProxy", "ConverterMapping",
157158
"DEFAULTSECT", "MAX_INTERPOLATION_DEPTH"]
@@ -311,6 +312,26 @@ def __init__(self, source=None, filename=None):
311312
self.errors = []
312313
self.args = (source, )
313314

315+
@property
316+
def filename(self):
317+
"""Deprecated, use `source'."""
318+
warnings.warn(
319+
"The 'filename' attribute will be removed in Python 3.12. "
320+
"Use 'source' instead.",
321+
DeprecationWarning, stacklevel=2
322+
)
323+
return self.source
324+
325+
@filename.setter
326+
def filename(self, value):
327+
"""Deprecated, user `source'."""
328+
warnings.warn(
329+
"The 'filename' attribute will be removed in Python 3.12. "
330+
"Use 'source' instead.",
331+
DeprecationWarning, stacklevel=2
332+
)
333+
self.source = value
334+
314335
def append(self, lineno, line):
315336
self.errors.append((lineno, line))
316337
self.message += '\n\t[line %2d]: %s' % (lineno, line)
@@ -733,6 +754,15 @@ def read_dict(self, dictionary, source='<dict>'):
733754
elements_added.add((section, key))
734755
self.set(section, key, value)
735756

757+
def readfp(self, fp, filename=None):
758+
"""Deprecated, use read_file instead."""
759+
warnings.warn(
760+
"This method will be removed in Python 3.12. "
761+
"Use 'parser.read_file()' instead.",
762+
DeprecationWarning, stacklevel=2
763+
)
764+
self.read_file(fp, source=filename)
765+
736766
def get(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
737767
"""Get an option value for a given section.
738768
@@ -1195,6 +1225,19 @@ def _read_defaults(self, defaults):
11951225
self._interpolation = hold_interpolation
11961226

11971227

1228+
class SafeConfigParser(ConfigParser):
1229+
"""ConfigParser alias for backwards compatibility purposes."""
1230+
1231+
def __init__(self, *args, **kwargs):
1232+
super().__init__(*args, **kwargs)
1233+
warnings.warn(
1234+
"The SafeConfigParser class has been renamed to ConfigParser "
1235+
"in Python 3.2. This alias will be removed in Python 3.12."
1236+
" Use ConfigParser directly instead.",
1237+
DeprecationWarning, stacklevel=2
1238+
)
1239+
1240+
11981241
class SectionProxy(MutableMapping):
11991242
"""A proxy for a single section from a parser."""
12001243

Lib/test/test_configparser.py

+28
Original file line numberDiff line numberDiff line change
@@ -1612,6 +1612,13 @@ def test_parsing_error(self):
16121612
"and `source'. Use `source'.")
16131613
error = configparser.ParsingError(filename='source')
16141614
self.assertEqual(error.source, 'source')
1615+
with warnings.catch_warnings(record=True) as w:
1616+
warnings.simplefilter("always", DeprecationWarning)
1617+
self.assertEqual(error.filename, 'source')
1618+
error.filename = 'filename'
1619+
self.assertEqual(error.source, 'filename')
1620+
for warning in w:
1621+
self.assertTrue(warning.category is DeprecationWarning)
16151622

16161623
def test_interpolation_validation(self):
16171624
parser = configparser.ConfigParser()
@@ -1630,6 +1637,27 @@ def test_interpolation_validation(self):
16301637
self.assertEqual(str(cm.exception), "bad interpolation variable "
16311638
"reference '%(()'")
16321639

1640+
def test_readfp_deprecation(self):
1641+
sio = io.StringIO("""
1642+
[section]
1643+
option = value
1644+
""")
1645+
parser = configparser.ConfigParser()
1646+
with warnings.catch_warnings(record=True) as w:
1647+
warnings.simplefilter("always", DeprecationWarning)
1648+
parser.readfp(sio, filename='StringIO')
1649+
for warning in w:
1650+
self.assertTrue(warning.category is DeprecationWarning)
1651+
self.assertEqual(len(parser), 2)
1652+
self.assertEqual(parser['section']['option'], 'value')
1653+
1654+
def test_safeconfigparser_deprecation(self):
1655+
with warnings.catch_warnings(record=True) as w:
1656+
warnings.simplefilter("always", DeprecationWarning)
1657+
parser = configparser.SafeConfigParser()
1658+
for warning in w:
1659+
self.assertTrue(warning.category is DeprecationWarning)
1660+
16331661
def test_sectionproxy_repr(self):
16341662
parser = configparser.ConfigParser()
16351663
parser.read_string("""
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Note the configparser deprecations will be removed in Python 3.12.

0 commit comments

Comments
 (0)