Broken ConfigParser removed, SafeConfigParser renamed to ConfigParser.

Life is beatiful once again.
This commit is contained in:
Łukasz Langa 2010-12-16 01:16:22 +00:00
parent bb9686f66f
commit 7f64c8a512
3 changed files with 155 additions and 202 deletions

View File

@ -17,10 +17,10 @@
single: ini file
single: Windows ini file
This module provides the :class:`SafeConfigParser` class which implements
a basic configuration language which provides a structure similar to what's
found in Microsoft Windows INI files. You can use this to write Python
programs which can be customized by end users easily.
This module provides the :class:`ConfigParser` class which implements a basic
configuration language which provides a structure similar to what's found in
Microsoft Windows INI files. You can use this to write Python programs which
can be customized by end users easily.
.. note::
@ -67,7 +67,7 @@ creating the above configuration file programatically.
.. doctest::
>>> import configparser
>>> config = configparser.SafeConfigParser()
>>> config = configparser.ConfigParser()
>>> config['DEFAULT'] = {'ServerAliveInterval': '45',
... 'Compression': 'yes',
... 'CompressionLevel': '9'}
@ -92,7 +92,7 @@ back and explore the data it holds.
.. doctest::
>>> import configparser
>>> config = configparser.SafeConfigParser()
>>> config = configparser.ConfigParser()
>>> config.sections()
[]
>>> config.read('example.ini')
@ -283,13 +283,13 @@ For example:
Interpolation of values
-----------------------
On top of the core functionality, :class:`SafeConfigParser` supports
On top of the core functionality, :class:`ConfigParser` supports
interpolation. This means values can be preprocessed before returning them
from ``get()`` calls.
.. class:: BasicInterpolation()
The default implementation used by :class:`SafeConfigParser`. It enables
The default implementation used by :class:`ConfigParser`. It enables
values to contain format strings which refer to other values in the same
section, or values in the special default section [1]_. Additional default
values can be provided on initialization.
@ -304,7 +304,7 @@ from ``get()`` calls.
my_pictures: %(my_dir)s/Pictures
In the example above, :class:`SafeConfigParser` with *interpolation* set to
In the example above, :class:`ConfigParser` with *interpolation* set to
``BasicInterpolation()`` would resolve ``%(home_dir)s`` to the value of
``home_dir`` (``/Users`` in this case). ``%(my_dir)s`` in effect would
resolve to ``/Users/lumberjack``. All interpolations are done on demand so
@ -444,7 +444,7 @@ the :meth:`__init__` options:
.. doctest::
>>> parser = configparser.SafeConfigParser()
>>> parser = configparser.ConfigParser()
>>> parser.read_dict({'section1': {'key1': 'value1',
... 'key2': 'value2',
... 'key3': 'value3'},
@ -465,7 +465,7 @@ the :meth:`__init__` options:
.. doctest::
>>> from collections import OrderedDict
>>> parser = configparser.SafeConfigParser()
>>> parser = configparser.ConfigParser()
>>> parser.read_dict(
... OrderedDict((
... ('s1',
@ -511,7 +511,7 @@ the :meth:`__init__` options:
... skip-bdb
... skip-innodb # we don't need ACID today
... """
>>> config = configparser.SafeConfigParser(allow_no_value=True)
>>> config = configparser.ConfigParser(allow_no_value=True)
>>> config.read_string(sample_config)
>>> # Settings with values are treated as before:
@ -534,7 +534,7 @@ the :meth:`__init__` options:
This means values (but not keys) can contain the delimiters.
See also the *space_around_delimiters* argument to
:meth:`SafeConfigParser.write`.
:meth:`ConfigParser.write`.
* *comment_prefixes*, default value: ``_COMPATIBLE`` (``'#'`` valid on empty
lines, ``';'`` valid also on non-empty lines)
@ -604,8 +604,7 @@ the :meth:`__init__` options:
advanced variant inspired by ``zc.buildout``. More on the subject in the
`dedicated documentation section <#interpolation-of-values>`_.
.. note:: :class:`RawConfigParser` is using ``None`` by default and
:class:`ConfigParser` is using ``configparser.BrokenInterpolation``.
.. note:: :class:`RawConfigParser` is using ``None`` by default.
More advanced customization may be achieved by overriding default values of
@ -622,7 +621,7 @@ may be overriden by subclasses or by attribute assignment.
.. doctest::
>>> custom = configparser.SafeConfigParser()
>>> custom = configparser.ConfigParser()
>>> custom['section1'] = {'funky': 'nope'}
>>> custom['section1'].getboolean('funky')
Traceback (most recent call last):
@ -652,7 +651,7 @@ may be overriden by subclasses or by attribute assignment.
... [Section2]
... AnotherKey = Value
... """
>>> typical = configparser.SafeConfigParser()
>>> typical = configparser.ConfigParser()
>>> typical.read_string(config)
>>> list(typical['Section1'].keys())
['key']
@ -670,11 +669,11 @@ may be overriden by subclasses or by attribute assignment.
Legacy API Examples
-------------------
Mainly because of backwards compatibility concerns, :mod:`configparser` provides
also a legacy API with explicit ``get``/``set`` methods. While there are valid
use cases for the methods outlined below, mapping protocol access is preferred
for new projects. The legacy API is at times more advanced, low-level and
downright counterintuitive.
Mainly because of backwards compatibility concerns, :mod:`configparser`
provides also a legacy API with explicit ``get``/``set`` methods. While there
are valid use cases for the methods outlined below, mapping protocol access is
preferred for new projects. The legacy API is at times more advanced,
low-level and downright counterintuitive.
An example of writing to a configuration file::
@ -682,12 +681,11 @@ An example of writing to a configuration file::
config = configparser.RawConfigParser()
# Please note that using RawConfigParser's and the raw mode of
# ConfigParser's respective set functions, you can assign non-string values
# to keys internally, but will receive an error when attempting to write to
# a file or when you get it in non-raw mode. Setting values using the
# mapping protocol or SafeConfigParser's set() does not allow such
# assignments to take place.
# Please note that using RawConfigParser's set functions, you can assign
# non-string values to keys internally, but will receive an error when
# attempting to write to a file or when you get it in non-raw mode. Setting
# values using the mapping protocol or ConfigParser's set() does not allow
# such assignments to take place.
config.add_section('Section1')
config.set('Section1', 'int', '15')
config.set('Section1', 'bool', 'true')
@ -718,11 +716,11 @@ An example of reading the configuration file again::
if config.getboolean('Section1', 'bool'):
print(config.get('Section1', 'foo'))
To get interpolation, use :class:`SafeConfigParser`::
To get interpolation, use :class:`ConfigParser`::
import configparser
cfg = configparser.SafeConfigParser()
cfg = configparser.ConfigParser()
cfg.read('example.cfg')
# Set the optional `raw` argument of get() to True if you wish to disable
@ -751,13 +749,13 @@ To get interpolation, use :class:`SafeConfigParser`::
print(cfg.get('Section1', 'monster', fallback=None))
# -> None
Default values are available in all three types of ConfigParsers. They are
used in interpolation if an option used is not defined elsewhere. ::
Default values are available in both types of ConfigParsers. They are used in
interpolation if an option used is not defined elsewhere. ::
import configparser
# New instance with 'bar' and 'baz' defaulting to 'Life' and 'hard' each
config = configparser.SafeConfigParser({'bar': 'Life', 'baz': 'hard'})
config = configparser.ConfigParser({'bar': 'Life', 'baz': 'hard'})
config.read('example.cfg')
print(config.get('Section1', 'foo')) # -> "Python is fun!"
@ -766,12 +764,12 @@ used in interpolation if an option used is not defined elsewhere. ::
print(config.get('Section1', 'foo')) # -> "Life is hard!"
.. _safeconfigparser-objects:
.. _configparser-objects:
SafeConfigParser Objects
------------------------
ConfigParser Objects
--------------------
.. class:: SafeConfigParser(defaults=None, dict_type=collections.OrderedDict, allow_no_value=False, delimiters=('=', ':'), comment_prefixes=_COMPATIBLE, strict=False, empty_lines_in_values=True, default_section=configparser.DEFAULTSECT, interpolation=BasicInterpolation())
.. class:: ConfigParser(defaults=None, dict_type=collections.OrderedDict, allow_no_value=False, delimiters=('=', ':'), comment_prefixes=_COMPATIBLE, strict=False, empty_lines_in_values=True, default_section=configparser.DEFAULTSECT, interpolation=BasicInterpolation())
The main configuration parser. When *defaults* is given, it is initialized
into the dictionary of intrinsic defaults. When *dict_type* is given, it
@ -877,7 +875,7 @@ SafeConfigParser Objects
import configparser, os
config = configparser.SafeConfigParser()
config = configparser.ConfigParser()
config.read_file(open('defaults.cfg'))
config.read(['site.cfg', os.path.expanduser('~/.myapp.cfg')],
encoding='cp1250')
@ -1047,13 +1045,13 @@ RawConfigParser Objects
.. class:: RawConfigParser(defaults=None, dict_type=collections.OrderedDict, allow_no_value=False, delimiters=('=', ':'), comment_prefixes=_COMPATIBLE, strict=False, empty_lines_in_values=True, default_section=configaparser.DEFAULTSECT, interpolation=None)
Legacy variant of the :class:`SafeConfigParser` with interpolation disabled
Legacy variant of the :class:`ConfigParser` with interpolation disabled
by default and unsafe ``add_section`` and ``set`` methods.
.. note::
Consider using :class:`SafeConfigParser` instead which checks types of
Consider using :class:`ConfigParser` instead which checks types of
the values to be stored internally. If you don't want interpolation, you
can use ``SafeConfigParser(interpolation=None)``.
can use ``ConfigParser(interpolation=None)``.
.. method:: add_section(section)
@ -1081,25 +1079,6 @@ RawConfigParser Objects
which does not allow such assignments to take place.
.. _configparser-objects:
ConfigParser Objects
--------------------
.. class:: ConfigParser(defaults=None, dict_type=collections.OrderedDict, allow_no_value=False, delimiters=('=', ':'), comment_prefixes=_COMPATIBLE, strict=False, empty_lines_in_values=True, default_section=configparser.DEFAULTSECT, interpolation=BrokenInterpolation())
.. deprecated:: 3.2
Whenever you can, consider using :class:`SafeConfigParser`. The
:class:`ConfigParser` provides the same functionality but its
implementation is less predictable. It does not validate the
interpolation syntax used within a configuration file. It also does not
enable escaping the interpolation character (when using
:class:`SafeConfigParser`, a key can have ``%`` as part of the value by
specifying ``%%`` in the file). On top of that, this class doesn't ensure
whether values passed to the parser object are strings which may lead to
inconsistent internal state.
Exceptions
----------

View File

@ -5,11 +5,11 @@ and followed by "name: value" entries, with continuations and such in
the style of RFC 822.
Intrinsic defaults can be specified by passing them into the
SafeConfigParser constructor as a dictionary.
ConfigParser constructor as a dictionary.
class:
SafeConfigParser -- responsible for parsing a list of
ConfigParser -- responsible for parsing a list of
configuration files, and managing the parsed database.
methods:
@ -265,9 +265,8 @@ class InterpolationMissingOptionError(InterpolationError):
class InterpolationSyntaxError(InterpolationError):
"""Raised when the source text contains invalid syntax.
Current implementation raises this exception only for SafeConfigParser
instances when the source text into which substitutions are made
does not conform to the required syntax.
Current implementation raises this exception when the source text into
which substitutions are made does not conform to the required syntax.
"""
@ -369,7 +368,7 @@ class Interpolation:
class BasicInterpolation(Interpolation):
"""Interpolation as implemented in the classic SafeConfigParser.
"""Interpolation as implemented in the classic ConfigParser.
The option values can contain format strings which refer to other values in
the same section, or values in the special default section.
@ -512,8 +511,8 @@ class ExtendedInterpolation(Interpolation):
"found: %r" % (rest,))
class BrokenInterpolation(Interpolation):
"""Deprecated interpolation as implemented in the classic ConfigParser.
class LegacyInterpolation(Interpolation):
"""Deprecated interpolation used in old versions of ConfigParser.
Use BasicInterpolation or ExtendedInterpolation instead."""
_KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
@ -598,12 +597,6 @@ class RawConfigParser(MutableMapping):
default_section=DEFAULTSECT,
interpolation=_UNSET):
if self.__class__ is RawConfigParser:
warnings.warn(
"The RawConfigParser class will be removed in future versions."
" Use 'SafeConfigParser(interpolation=None)' instead.",
DeprecationWarning, stacklevel=2
)
self._dict = dict_type
self._sections = self._dict()
self._defaults = self._dict()
@ -1142,8 +1135,8 @@ class RawConfigParser(MutableMapping):
- we allow valueless options but the value is not None
For compatibility reasons this method is not used in classic set()
for RawConfigParsers and ConfigParsers. It is invoked in every
case for mapping protocol access and in SafeConfigParser.set().
for RawConfigParsers. It is invoked in every case for mapping protocol
access and in ConfigParser.set().
"""
if not isinstance(section, str):
raise TypeError("section names must be strings")
@ -1157,21 +1150,6 @@ class RawConfigParser(MutableMapping):
class ConfigParser(RawConfigParser):
"""ConfigParser implementing interpolation."""
_DEFAULT_INTERPOLATION = BrokenInterpolation()
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.__class__ is ConfigParser:
warnings.warn(
"The ConfigParser class will be removed in future versions."
" Use SafeConfigParser instead.",
DeprecationWarning, stacklevel=2
)
class SafeConfigParser(ConfigParser):
"""ConfigParser implementing sane interpolation."""
_DEFAULT_INTERPOLATION = BasicInterpolation()
def set(self, section, option, value=None):
@ -1188,6 +1166,19 @@ class SafeConfigParser(ConfigParser):
super().add_section(section)
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 future versions."
" Use ConfigParser directly instead.",
DeprecationWarning, stacklevel=2
)
class SectionProxy(MutableMapping):
"""A proxy for a single section from a parser."""

View File

@ -5,7 +5,6 @@ import os
import sys
import textwrap
import unittest
import warnings
from test import support
@ -48,9 +47,7 @@ class CfgParserTestCaseClass(unittest.TestCase):
default_section=self.default_section,
interpolation=self.interpolation,
)
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=DeprecationWarning)
instance = self.config_class(**arguments)
instance = self.config_class(**arguments)
return instance
def fromstring(self, string, defaults=None):
@ -708,11 +705,6 @@ class ConfigParserTestCase(BasicTestCase):
config_class = configparser.ConfigParser
def test_interpolation(self):
rawval = {
configparser.ConfigParser: ("something %(with11)s "
"lots of interpolation (11 steps)"),
configparser.SafeConfigParser: "%(with1)s",
}
cf = self.get_interpolation_config()
eq = self.assertEqual
eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
@ -721,21 +713,25 @@ class ConfigParserTestCase(BasicTestCase):
eq(cf.get("Foo", "bar10"),
"something with lots of interpolation (10 steps)")
e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class]))
if self.interpolation == configparser._UNSET:
self.assertEqual(e.args, ("bar11", "Foo", "%(with1)s"))
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):
rawval = {
configparser.ConfigParser: '%(reference)s',
configparser.SafeConfigParser: '',
}
cf = self.get_interpolation_config()
e = self.get_error(cf, configparser.InterpolationMissingOptionError,
"Interpolation Error", "name")
self.assertEqual(e.reference, "reference")
self.assertEqual(e.section, "Interpolation Error")
self.assertEqual(e.option, "name")
self.assertEqual(e.args, ('name', 'Interpolation Error',
rawval[self.config_class], 'reference'))
if self.interpolation == configparser._UNSET:
self.assertEqual(e.args, ('name', 'Interpolation Error',
'', '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>'),
@ -743,35 +739,75 @@ class ConfigParserTestCase(BasicTestCase):
('key', '|value|'),
('name', 'value')])
def test_safe_interpolation(self):
# See http://www.python.org/sf/511737
cf = self.fromstring("[section]\n"
"option1{eq}xxx\n"
"option2{eq}%(option1)s/xxx\n"
"ok{eq}%(option1)s/%%s\n"
"not_ok{eq}%(option2)s/%%s".format(
eq=self.delimiters[0]))
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"
"option1{eq}foo\n".format(eq=self.delimiters[0]))
self.assertEqual(cf.get('sect', "option1"), "foo")
self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
self.assertEqual(cf.get('sect', "option1"), "foo")
# bug #5741: double percents are *not* malformed
cf.set("sect", "option2", "foo%%bar")
self.assertEqual(cf.get("sect", "option2"), "foo%bar")
def test_set_nonstring_types(self):
cf = self.fromstring("[sect]\n"
"option1{eq}foo\n".format(eq=self.delimiters[0]))
# Check that we get a TypeError when setting non-string values
# in an existing section:
self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
self.assertRaises(TypeError, cf.set, "sect", "option1", object())
self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
self.assertRaises(TypeError, cf.set, "sect", "option2", object())
self.assertRaises(TypeError, cf.set, "sect", 123, "invalid opt name!")
self.assertRaises(TypeError, cf.add_section, 123)
def test_add_section_default(self):
cf = self.newconfig()
cf.add_section('non-string')
cf.set('non-string', 'int', 1)
cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%('])
cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1,
'%(list)': '%(list)'})
cf.set('non-string', 'string_with_interpolation', '%(list)s')
self.assertEqual(cf.get('non-string', 'int', raw=True), 1)
self.assertRaises(TypeError, cf.get, 'non-string', 'int')
self.assertEqual(cf.get('non-string', 'list', raw=True),
[0, 1, 1, 2, 3, 5, 8, 13, '%('])
self.assertRaises(TypeError, cf.get, 'non-string', 'list')
self.assertEqual(cf.get('non-string', 'dict', raw=True),
{'pi': 3.14159, '%(': 1, '%(list)': '%(list)'})
self.assertRaises(TypeError, cf.get, 'non-string', 'dict')
self.assertEqual(cf.get('non-string', 'string_with_interpolation',
raw=True), '%(list)s')
self.assertRaises(ValueError, cf.get, 'non-string',
'string_with_interpolation', raw=False)
cf.add_section(123)
cf.set(123, 'this is sick', True)
self.assertEqual(cf.get(123, 'this is sick', raw=True), True)
with self.assertRaises(TypeError):
cf.get(123, 'this is sick')
cf.optionxform = lambda x: x
cf.set('non-string', 1, 1)
self.assertRaises(TypeError, cf.get, 'non-string', 1, 1)
self.assertEqual(cf.get('non-string', 1, raw=True), 1)
self.assertRaises(ValueError, cf.add_section, self.default_section)
class ConfigParserTestCaseLegacyInterpolation(ConfigParserTestCase):
config_class = configparser.ConfigParser
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 ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
delimiters = (':=', '$')
@ -872,56 +908,8 @@ class RawConfigParserTestSambaConf(BasicTestCase):
self.assertEqual(cf.get("global", "hosts allow"), "127.")
self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
class SafeConfigParserTestCase(ConfigParserTestCase):
config_class = configparser.SafeConfigParser
def test_safe_interpolation(self):
# See http://www.python.org/sf/511737
cf = self.fromstring("[section]\n"
"option1{eq}xxx\n"
"option2{eq}%(option1)s/xxx\n"
"ok{eq}%(option1)s/%%s\n"
"not_ok{eq}%(option2)s/%%s".format(
eq=self.delimiters[0]))
self.assertEqual(cf.get("section", "ok"), "xxx/%s")
self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
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")
self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
self.assertEqual(cf.get('sect', "option1"), "foo")
# bug #5741: double percents are *not* malformed
cf.set("sect", "option2", "foo%%bar")
self.assertEqual(cf.get("sect", "option2"), "foo%bar")
def test_set_nonstring_types(self):
cf = self.fromstring("[sect]\n"
"option1{eq}foo\n".format(eq=self.delimiters[0]))
# Check that we get a TypeError when setting non-string values
# in an existing section:
self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
self.assertRaises(TypeError, cf.set, "sect", "option1", object())
self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
self.assertRaises(TypeError, cf.set, "sect", "option2", object())
self.assertRaises(TypeError, cf.set, "sect", 123, "invalid opt name!")
self.assertRaises(TypeError, cf.add_section, 123)
def test_add_section_default(self):
cf = self.newconfig()
self.assertRaises(ValueError, cf.add_section, self.default_section)
class SafeConfigParserTestCaseExtendedInterpolation(BasicTestCase):
config_class = configparser.SafeConfigParser
class ConfigParserTestCaseExtendedInterpolation(BasicTestCase):
config_class = configparser.ConfigParser
interpolation = configparser.ExtendedInterpolation()
default_section = 'common'
@ -984,15 +972,11 @@ class SafeConfigParserTestCaseExtendedInterpolation(BasicTestCase):
class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase):
delimiters = (':=', '$')
comment_prefixes = ('//', '"')
class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase):
class ConfigParserTestCaseNoValue(ConfigParserTestCase):
allow_no_value = True
class SafeConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
config_class = configparser.SafeConfigParser
class ConfigParserTestCaseTrickyFile(CfgParserTestCaseClass):
config_class = configparser.ConfigParser
delimiters = {'='}
comment_prefixes = {'#'}
allow_no_value = True
@ -1047,9 +1031,7 @@ class Issue7005TestCase(unittest.TestCase):
def prepare(self, config_class):
# This is the default, but that's the point.
with warnings.catch_warnings():
warnings.simplefilter("ignore", category=DeprecationWarning)
cp = config_class(allow_no_value=False)
cp = config_class(allow_no_value=False)
cp.add_section("section")
cp.set("section", "option", None)
sio = io.StringIO()
@ -1057,8 +1039,10 @@ class Issue7005TestCase(unittest.TestCase):
return sio.getvalue()
def test_none_as_value_stringified(self):
output = self.prepare(configparser.ConfigParser)
self.assertEqual(output, self.expected_output)
cp = configparser.ConfigParser(allow_no_value=False)
cp.add_section("section")
with self.assertRaises(TypeError):
cp.set("section", "option", None)
def test_none_as_value_stringified_raw(self):
output = self.prepare(configparser.RawConfigParser)
@ -1112,15 +1096,14 @@ def test_main():
support.run_unittest(
ConfigParserTestCase,
ConfigParserTestCaseNonStandardDelimiters,
ConfigParserTestCaseNoValue,
ConfigParserTestCaseExtendedInterpolation,
ConfigParserTestCaseLegacyInterpolation,
ConfigParserTestCaseTrickyFile,
MultilineValuesTestCase,
RawConfigParserTestCase,
RawConfigParserTestCaseNonStandardDelimiters,
RawConfigParserTestSambaConf,
SafeConfigParserTestCase,
SafeConfigParserTestCaseExtendedInterpolation,
SafeConfigParserTestCaseNonStandardDelimiters,
SafeConfigParserTestCaseNoValue,
SafeConfigParserTestCaseTrickyFile,
SortedTestCase,
Issue7005TestCase,
StrictTestCase,
@ -1139,6 +1122,6 @@ def test_coverage(coverdir):
if __name__ == "__main__":
if "-c" in sys.argv:
test_coverage('/tmp/cmd.cover')
test_coverage('/tmp/configparser.cover')
else:
test_main()