Broken ConfigParser removed, SafeConfigParser renamed to ConfigParser.
Life is beatiful once again.
This commit is contained in:
parent
bb9686f66f
commit
7f64c8a512
|
@ -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
|
||||
----------
|
||||
|
||||
|
|
|
@ -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."""
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue