»Core Development>Code coverage>Lib/test/test_configparser.py

Python code coverage for Lib/test/test_configparser.py

#countcontent
1n/aimport collections
2n/aimport configparser
3n/aimport io
4n/aimport os
5n/aimport textwrap
6n/aimport unittest
7n/aimport warnings
8n/a
9n/afrom test import support
10n/a
11n/a
12n/aclass SortedDict(collections.UserDict):
13n/a
14n/a def items(self):
15n/a return sorted(self.data.items())
16n/a
17n/a def keys(self):
18n/a return sorted(self.data.keys())
19n/a
20n/a def values(self):
21n/a return [i[1] for i in self.items()]
22n/a
23n/a def iteritems(self):
24n/a return iter(self.items())
25n/a
26n/a def iterkeys(self):
27n/a return iter(self.keys())
28n/a
29n/a def itervalues(self):
30n/a return iter(self.values())
31n/a
32n/a __iter__ = iterkeys
33n/a
34n/a
35n/aclass CfgParserTestCaseClass:
36n/a allow_no_value = False
37n/a delimiters = ('=', ':')
38n/a comment_prefixes = (';', '#')
39n/a inline_comment_prefixes = (';', '#')
40n/a empty_lines_in_values = True
41n/a dict_type = configparser._default_dict
42n/a strict = False
43n/a default_section = configparser.DEFAULTSECT
44n/a interpolation = configparser._UNSET
45n/a
46n/a def newconfig(self, defaults=None):
47n/a arguments = dict(
48n/a defaults=defaults,
49n/a allow_no_value=self.allow_no_value,
50n/a delimiters=self.delimiters,
51n/a comment_prefixes=self.comment_prefixes,
52n/a inline_comment_prefixes=self.inline_comment_prefixes,
53n/a empty_lines_in_values=self.empty_lines_in_values,
54n/a dict_type=self.dict_type,
55n/a strict=self.strict,
56n/a default_section=self.default_section,
57n/a interpolation=self.interpolation,
58n/a )
59n/a instance = self.config_class(**arguments)
60n/a return instance
61n/a
62n/a def fromstring(self, string, defaults=None):
63n/a cf = self.newconfig(defaults)
64n/a cf.read_string(string)
65n/a return cf
66n/a
67n/a
68n/aclass BasicTestCase(CfgParserTestCaseClass):
69n/a
70n/a def basic_test(self, cf):
71n/a E = ['Commented Bar',
72n/a 'Foo Bar',
73n/a 'Internationalized Stuff',
74n/a 'Long Line',
75n/a 'Section\\with$weird%characters[\t',
76n/a 'Spaces',
77n/a 'Spacey Bar',
78n/a 'Spacey Bar From The Beginning',
79n/a 'Types',
80n/a ]
81n/a
82n/a if self.allow_no_value:
83n/a E.append('NoValue')
84n/a E.sort()
85n/a F = [('baz', 'qwe'), ('foo', 'bar3')]
86n/a
87n/a # API access
88n/a L = cf.sections()
89n/a L.sort()
90n/a eq = self.assertEqual
91n/a eq(L, E)
92n/a L = cf.items('Spacey Bar From The Beginning')
93n/a L.sort()
94n/a eq(L, F)
95n/a
96n/a # mapping access
97n/a L = [section for section in cf]
98n/a L.sort()
99n/a E.append(self.default_section)
100n/a E.sort()
101n/a eq(L, E)
102n/a L = cf['Spacey Bar From The Beginning'].items()
103n/a L = sorted(list(L))
104n/a eq(L, F)
105n/a L = cf.items()
106n/a L = sorted(list(L))
107n/a self.assertEqual(len(L), len(E))
108n/a for name, section in L:
109n/a eq(name, section.name)
110n/a eq(cf.defaults(), cf[self.default_section])
111n/a
112n/a # The use of spaces in the section names serves as a
113n/a # regression test for SourceForge bug #583248:
114n/a # http://www.python.org/sf/583248
115n/a
116n/a # API access
117n/a eq(cf.get('Foo Bar', 'foo'), 'bar1')
118n/a eq(cf.get('Spacey Bar', 'foo'), 'bar2')
119n/a eq(cf.get('Spacey Bar From The Beginning', 'foo'), 'bar3')
120n/a eq(cf.get('Spacey Bar From The Beginning', 'baz'), 'qwe')
121n/a eq(cf.get('Commented Bar', 'foo'), 'bar4')
122n/a eq(cf.get('Commented Bar', 'baz'), 'qwe')
123n/a eq(cf.get('Spaces', 'key with spaces'), 'value')
124n/a eq(cf.get('Spaces', 'another with spaces'), 'splat!')
125n/a eq(cf.getint('Types', 'int'), 42)
126n/a eq(cf.get('Types', 'int'), "42")
127n/a self.assertAlmostEqual(cf.getfloat('Types', 'float'), 0.44)
128n/a eq(cf.get('Types', 'float'), "0.44")
129n/a eq(cf.getboolean('Types', 'boolean'), False)
130n/a eq(cf.get('Types', '123'), 'strange but acceptable')
131n/a if self.allow_no_value:
132n/a eq(cf.get('NoValue', 'option-without-value'), None)
133n/a
134n/a # test vars= and fallback=
135n/a eq(cf.get('Foo Bar', 'foo', fallback='baz'), 'bar1')
136n/a eq(cf.get('Foo Bar', 'foo', vars={'foo': 'baz'}), 'baz')
137n/a with self.assertRaises(configparser.NoSectionError):
138n/a cf.get('No Such Foo Bar', 'foo')
139n/a with self.assertRaises(configparser.NoOptionError):
140n/a cf.get('Foo Bar', 'no-such-foo')
141n/a eq(cf.get('No Such Foo Bar', 'foo', fallback='baz'), 'baz')
142n/a eq(cf.get('Foo Bar', 'no-such-foo', fallback='baz'), 'baz')
143n/a eq(cf.get('Spacey Bar', 'foo', fallback=None), 'bar2')
144n/a eq(cf.get('No Such Spacey Bar', 'foo', fallback=None), None)
145n/a eq(cf.getint('Types', 'int', fallback=18), 42)
146n/a eq(cf.getint('Types', 'no-such-int', fallback=18), 18)
147n/a eq(cf.getint('Types', 'no-such-int', fallback="18"), "18") # sic!
148n/a with self.assertRaises(configparser.NoOptionError):
149n/a cf.getint('Types', 'no-such-int')
150n/a self.assertAlmostEqual(cf.getfloat('Types', 'float',
151n/a fallback=0.0), 0.44)
152n/a self.assertAlmostEqual(cf.getfloat('Types', 'no-such-float',
153n/a fallback=0.0), 0.0)
154n/a eq(cf.getfloat('Types', 'no-such-float', fallback="0.0"), "0.0") # sic!
155n/a with self.assertRaises(configparser.NoOptionError):
156n/a cf.getfloat('Types', 'no-such-float')
157n/a eq(cf.getboolean('Types', 'boolean', fallback=True), False)
158n/a eq(cf.getboolean('Types', 'no-such-boolean', fallback="yes"),
159n/a "yes") # sic!
160n/a eq(cf.getboolean('Types', 'no-such-boolean', fallback=True), True)
161n/a with self.assertRaises(configparser.NoOptionError):
162n/a cf.getboolean('Types', 'no-such-boolean')
163n/a eq(cf.getboolean('No Such Types', 'boolean', fallback=True), True)
164n/a if self.allow_no_value:
165n/a eq(cf.get('NoValue', 'option-without-value', fallback=False), None)
166n/a eq(cf.get('NoValue', 'no-such-option-without-value',
167n/a fallback=False), False)
168n/a
169n/a # mapping access
170n/a eq(cf['Foo Bar']['foo'], 'bar1')
171n/a eq(cf['Spacey Bar']['foo'], 'bar2')
172n/a section = cf['Spacey Bar From The Beginning']
173n/a eq(section.name, 'Spacey Bar From The Beginning')
174n/a self.assertIs(section.parser, cf)
175n/a with self.assertRaises(AttributeError):
176n/a section.name = 'Name is read-only'
177n/a with self.assertRaises(AttributeError):
178n/a section.parser = 'Parser is read-only'
179n/a eq(section['foo'], 'bar3')
180n/a eq(section['baz'], 'qwe')
181n/a eq(cf['Commented Bar']['foo'], 'bar4')
182n/a eq(cf['Commented Bar']['baz'], 'qwe')
183n/a eq(cf['Spaces']['key with spaces'], 'value')
184n/a eq(cf['Spaces']['another with spaces'], 'splat!')
185n/a eq(cf['Long Line']['foo'],
186n/a 'this line is much, much longer than my editor\nlikes it.')
187n/a if self.allow_no_value:
188n/a eq(cf['NoValue']['option-without-value'], None)
189n/a # test vars= and fallback=
190n/a eq(cf['Foo Bar'].get('foo', 'baz'), 'bar1')
191n/a eq(cf['Foo Bar'].get('foo', fallback='baz'), 'bar1')
192n/a eq(cf['Foo Bar'].get('foo', vars={'foo': 'baz'}), 'baz')
193n/a with self.assertRaises(KeyError):
194n/a cf['No Such Foo Bar']['foo']
195n/a with self.assertRaises(KeyError):
196n/a cf['Foo Bar']['no-such-foo']
197n/a with self.assertRaises(KeyError):
198n/a cf['No Such Foo Bar'].get('foo', fallback='baz')
199n/a eq(cf['Foo Bar'].get('no-such-foo', 'baz'), 'baz')
200n/a eq(cf['Foo Bar'].get('no-such-foo', fallback='baz'), 'baz')
201n/a eq(cf['Foo Bar'].get('no-such-foo'), None)
202n/a eq(cf['Spacey Bar'].get('foo', None), 'bar2')
203n/a eq(cf['Spacey Bar'].get('foo', fallback=None), 'bar2')
204n/a with self.assertRaises(KeyError):
205n/a cf['No Such Spacey Bar'].get('foo', None)
206n/a eq(cf['Types'].getint('int', 18), 42)
207n/a eq(cf['Types'].getint('int', fallback=18), 42)
208n/a eq(cf['Types'].getint('no-such-int', 18), 18)
209n/a eq(cf['Types'].getint('no-such-int', fallback=18), 18)
210n/a eq(cf['Types'].getint('no-such-int', "18"), "18") # sic!
211n/a eq(cf['Types'].getint('no-such-int', fallback="18"), "18") # sic!
212n/a eq(cf['Types'].getint('no-such-int'), None)
213n/a self.assertAlmostEqual(cf['Types'].getfloat('float', 0.0), 0.44)
214n/a self.assertAlmostEqual(cf['Types'].getfloat('float',
215n/a fallback=0.0), 0.44)
216n/a self.assertAlmostEqual(cf['Types'].getfloat('no-such-float', 0.0), 0.0)
217n/a self.assertAlmostEqual(cf['Types'].getfloat('no-such-float',
218n/a fallback=0.0), 0.0)
219n/a eq(cf['Types'].getfloat('no-such-float', "0.0"), "0.0") # sic!
220n/a eq(cf['Types'].getfloat('no-such-float', fallback="0.0"), "0.0") # sic!
221n/a eq(cf['Types'].getfloat('no-such-float'), None)
222n/a eq(cf['Types'].getboolean('boolean', True), False)
223n/a eq(cf['Types'].getboolean('boolean', fallback=True), False)
224n/a eq(cf['Types'].getboolean('no-such-boolean', "yes"), "yes") # sic!
225n/a eq(cf['Types'].getboolean('no-such-boolean', fallback="yes"),
226n/a "yes") # sic!
227n/a eq(cf['Types'].getboolean('no-such-boolean', True), True)
228n/a eq(cf['Types'].getboolean('no-such-boolean', fallback=True), True)
229n/a eq(cf['Types'].getboolean('no-such-boolean'), None)
230n/a if self.allow_no_value:
231n/a eq(cf['NoValue'].get('option-without-value', False), None)
232n/a eq(cf['NoValue'].get('option-without-value', fallback=False), None)
233n/a eq(cf['NoValue'].get('no-such-option-without-value', False), False)
234n/a eq(cf['NoValue'].get('no-such-option-without-value',
235n/a fallback=False), False)
236n/a
237n/a # Make sure the right things happen for remove_section() and
238n/a # remove_option(); added to include check for SourceForge bug #123324.
239n/a
240n/a cf[self.default_section]['this_value'] = '1'
241n/a cf[self.default_section]['that_value'] = '2'
242n/a
243n/a # API access
244n/a self.assertTrue(cf.remove_section('Spaces'))
245n/a self.assertFalse(cf.has_option('Spaces', 'key with spaces'))
246n/a self.assertFalse(cf.remove_section('Spaces'))
247n/a self.assertFalse(cf.remove_section(self.default_section))
248n/a self.assertTrue(cf.remove_option('Foo Bar', 'foo'),
249n/a "remove_option() failed to report existence of option")
250n/a self.assertFalse(cf.has_option('Foo Bar', 'foo'),
251n/a "remove_option() failed to remove option")
252n/a self.assertFalse(cf.remove_option('Foo Bar', 'foo'),
253n/a "remove_option() failed to report non-existence of option"
254n/a " that was removed")
255n/a self.assertTrue(cf.has_option('Foo Bar', 'this_value'))
256n/a self.assertFalse(cf.remove_option('Foo Bar', 'this_value'))
257n/a self.assertTrue(cf.remove_option(self.default_section, 'this_value'))
258n/a self.assertFalse(cf.has_option('Foo Bar', 'this_value'))
259n/a self.assertFalse(cf.remove_option(self.default_section, 'this_value'))
260n/a
261n/a with self.assertRaises(configparser.NoSectionError) as cm:
262n/a cf.remove_option('No Such Section', 'foo')
263n/a self.assertEqual(cm.exception.args, ('No Such Section',))
264n/a
265n/a eq(cf.get('Long Line', 'foo'),
266n/a 'this line is much, much longer than my editor\nlikes it.')
267n/a
268n/a # mapping access
269n/a del cf['Types']
270n/a self.assertFalse('Types' in cf)
271n/a with self.assertRaises(KeyError):
272n/a del cf['Types']
273n/a with self.assertRaises(ValueError):
274n/a del cf[self.default_section]
275n/a del cf['Spacey Bar']['foo']
276n/a self.assertFalse('foo' in cf['Spacey Bar'])
277n/a with self.assertRaises(KeyError):
278n/a del cf['Spacey Bar']['foo']
279n/a self.assertTrue('that_value' in cf['Spacey Bar'])
280n/a with self.assertRaises(KeyError):
281n/a del cf['Spacey Bar']['that_value']
282n/a del cf[self.default_section]['that_value']
283n/a self.assertFalse('that_value' in cf['Spacey Bar'])
284n/a with self.assertRaises(KeyError):
285n/a del cf[self.default_section]['that_value']
286n/a with self.assertRaises(KeyError):
287n/a del cf['No Such Section']['foo']
288n/a
289n/a # Don't add new asserts below in this method as most of the options
290n/a # and sections are now removed.
291n/a
292n/a def test_basic(self):
293n/a config_string = """\
294n/a[Foo Bar]
295n/afoo{0[0]}bar1
296n/a[Spacey Bar]
297n/afoo {0[0]} bar2
298n/a[Spacey Bar From The Beginning]
299n/a foo {0[0]} bar3
300n/a baz {0[0]} qwe
301n/a[Commented Bar]
302n/afoo{0[1]} bar4 {1[1]} comment
303n/abaz{0[0]}qwe {1[0]}another one
304n/a[Long Line]
305n/afoo{0[1]} this line is much, much longer than my editor
306n/a likes it.
307n/a[Section\\with$weird%characters[\t]
308n/a[Internationalized Stuff]
309n/afoo[bg]{0[1]} Bulgarian
310n/afoo{0[0]}Default
311n/afoo[en]{0[0]}English
312n/afoo[de]{0[0]}Deutsch
313n/a[Spaces]
314n/akey with spaces {0[1]} value
315n/aanother with spaces {0[0]} splat!
316n/a[Types]
317n/aint {0[1]} 42
318n/afloat {0[0]} 0.44
319n/aboolean {0[0]} NO
320n/a123 {0[1]} strange but acceptable
321n/a""".format(self.delimiters, self.comment_prefixes)
322n/a if self.allow_no_value:
323n/a config_string += (
324n/a "[NoValue]\n"
325n/a "option-without-value\n"
326n/a )
327n/a cf = self.fromstring(config_string)
328n/a self.basic_test(cf)
329n/a if self.strict:
330n/a with self.assertRaises(configparser.DuplicateOptionError):
331n/a cf.read_string(textwrap.dedent("""\
332n/a [Duplicate Options Here]
333n/a option {0[0]} with a value
334n/a option {0[1]} with another value
335n/a """.format(self.delimiters)))
336n/a with self.assertRaises(configparser.DuplicateSectionError):
337n/a cf.read_string(textwrap.dedent("""\
338n/a [And Now For Something]
339n/a completely different {0[0]} True
340n/a [And Now For Something]
341n/a the larch {0[1]} 1
342n/a """.format(self.delimiters)))
343n/a else:
344n/a cf.read_string(textwrap.dedent("""\
345n/a [Duplicate Options Here]
346n/a option {0[0]} with a value
347n/a option {0[1]} with another value
348n/a """.format(self.delimiters)))
349n/a
350n/a cf.read_string(textwrap.dedent("""\
351n/a [And Now For Something]
352n/a completely different {0[0]} True
353n/a [And Now For Something]
354n/a the larch {0[1]} 1
355n/a """.format(self.delimiters)))
356n/a
357n/a def test_basic_from_dict(self):
358n/a config = {
359n/a "Foo Bar": {
360n/a "foo": "bar1",
361n/a },
362n/a "Spacey Bar": {
363n/a "foo": "bar2",
364n/a },
365n/a "Spacey Bar From The Beginning": {
366n/a "foo": "bar3",
367n/a "baz": "qwe",
368n/a },
369n/a "Commented Bar": {
370n/a "foo": "bar4",
371n/a "baz": "qwe",
372n/a },
373n/a "Long Line": {
374n/a "foo": "this line is much, much longer than my editor\nlikes "
375n/a "it.",
376n/a },
377n/a "Section\\with$weird%characters[\t": {
378n/a },
379n/a "Internationalized Stuff": {
380n/a "foo[bg]": "Bulgarian",
381n/a "foo": "Default",
382n/a "foo[en]": "English",
383n/a "foo[de]": "Deutsch",
384n/a },
385n/a "Spaces": {
386n/a "key with spaces": "value",
387n/a "another with spaces": "splat!",
388n/a },
389n/a "Types": {
390n/a "int": 42,
391n/a "float": 0.44,
392n/a "boolean": False,
393n/a 123: "strange but acceptable",
394n/a },
395n/a }
396n/a if self.allow_no_value:
397n/a config.update({
398n/a "NoValue": {
399n/a "option-without-value": None,
400n/a }
401n/a })
402n/a cf = self.newconfig()
403n/a cf.read_dict(config)
404n/a self.basic_test(cf)
405n/a if self.strict:
406n/a with self.assertRaises(configparser.DuplicateSectionError):
407n/a cf.read_dict({
408n/a '1': {'key': 'value'},
409n/a 1: {'key2': 'value2'},
410n/a })
411n/a with self.assertRaises(configparser.DuplicateOptionError):
412n/a cf.read_dict({
413n/a "Duplicate Options Here": {
414n/a 'option': 'with a value',
415n/a 'OPTION': 'with another value',
416n/a },
417n/a })
418n/a else:
419n/a cf.read_dict({
420n/a 'section': {'key': 'value'},
421n/a 'SECTION': {'key2': 'value2'},
422n/a })
423n/a cf.read_dict({
424n/a "Duplicate Options Here": {
425n/a 'option': 'with a value',
426n/a 'OPTION': 'with another value',
427n/a },
428n/a })
429n/a
430n/a def test_case_sensitivity(self):
431n/a cf = self.newconfig()
432n/a cf.add_section("A")
433n/a cf.add_section("a")
434n/a cf.add_section("B")
435n/a L = cf.sections()
436n/a L.sort()
437n/a eq = self.assertEqual
438n/a eq(L, ["A", "B", "a"])
439n/a cf.set("a", "B", "value")
440n/a eq(cf.options("a"), ["b"])
441n/a eq(cf.get("a", "b"), "value",
442n/a "could not locate option, expecting case-insensitive option names")
443n/a with self.assertRaises(configparser.NoSectionError):
444n/a # section names are case-sensitive
445n/a cf.set("b", "A", "value")
446n/a self.assertTrue(cf.has_option("a", "b"))
447n/a self.assertFalse(cf.has_option("b", "b"))
448n/a cf.set("A", "A-B", "A-B value")
449n/a for opt in ("a-b", "A-b", "a-B", "A-B"):
450n/a self.assertTrue(
451n/a cf.has_option("A", opt),
452n/a "has_option() returned false for option which should exist")
453n/a eq(cf.options("A"), ["a-b"])
454n/a eq(cf.options("a"), ["b"])
455n/a cf.remove_option("a", "B")
456n/a eq(cf.options("a"), [])
457n/a
458n/a # SF bug #432369:
459n/a cf = self.fromstring(
460n/a "[MySection]\nOption{} first line \n\tsecond line \n".format(
461n/a self.delimiters[0]))
462n/a eq(cf.options("MySection"), ["option"])
463n/a eq(cf.get("MySection", "Option"), "first line\nsecond line")
464n/a
465n/a # SF bug #561822:
466n/a cf = self.fromstring("[section]\n"
467n/a "nekey{}nevalue\n".format(self.delimiters[0]),
468n/a defaults={"key":"value"})
469n/a self.assertTrue(cf.has_option("section", "Key"))
470n/a
471n/a
472n/a def test_case_sensitivity_mapping_access(self):
473n/a cf = self.newconfig()
474n/a cf["A"] = {}
475n/a cf["a"] = {"B": "value"}
476n/a cf["B"] = {}
477n/a L = [section for section in cf]
478n/a L.sort()
479n/a eq = self.assertEqual
480n/a elem_eq = self.assertCountEqual
481n/a eq(L, sorted(["A", "B", self.default_section, "a"]))
482n/a eq(cf["a"].keys(), {"b"})
483n/a eq(cf["a"]["b"], "value",
484n/a "could not locate option, expecting case-insensitive option names")
485n/a with self.assertRaises(KeyError):
486n/a # section names are case-sensitive
487n/a cf["b"]["A"] = "value"
488n/a self.assertTrue("b" in cf["a"])
489n/a cf["A"]["A-B"] = "A-B value"
490n/a for opt in ("a-b", "A-b", "a-B", "A-B"):
491n/a self.assertTrue(
492n/a opt in cf["A"],
493n/a "has_option() returned false for option which should exist")
494n/a eq(cf["A"].keys(), {"a-b"})
495n/a eq(cf["a"].keys(), {"b"})
496n/a del cf["a"]["B"]
497n/a elem_eq(cf["a"].keys(), {})
498n/a
499n/a # SF bug #432369:
500n/a cf = self.fromstring(
501n/a "[MySection]\nOption{} first line \n\tsecond line \n".format(
502n/a self.delimiters[0]))
503n/a eq(cf["MySection"].keys(), {"option"})
504n/a eq(cf["MySection"]["Option"], "first line\nsecond line")
505n/a
506n/a # SF bug #561822:
507n/a cf = self.fromstring("[section]\n"
508n/a "nekey{}nevalue\n".format(self.delimiters[0]),
509n/a defaults={"key":"value"})
510n/a self.assertTrue("Key" in cf["section"])
511n/a
512n/a def test_default_case_sensitivity(self):
513n/a cf = self.newconfig({"foo": "Bar"})
514n/a self.assertEqual(
515n/a cf.get(self.default_section, "Foo"), "Bar",
516n/a "could not locate option, expecting case-insensitive option names")
517n/a cf = self.newconfig({"Foo": "Bar"})
518n/a self.assertEqual(
519n/a cf.get(self.default_section, "Foo"), "Bar",
520n/a "could not locate option, expecting case-insensitive defaults")
521n/a
522n/a def test_parse_errors(self):
523n/a cf = self.newconfig()
524n/a self.parse_error(cf, configparser.ParsingError,
525n/a "[Foo]\n"
526n/a "{}val-without-opt-name\n".format(self.delimiters[0]))
527n/a self.parse_error(cf, configparser.ParsingError,
528n/a "[Foo]\n"
529n/a "{}val-without-opt-name\n".format(self.delimiters[1]))
530n/a e = self.parse_error(cf, configparser.MissingSectionHeaderError,
531n/a "No Section!\n")
532n/a self.assertEqual(e.args, ('<???>', 1, "No Section!\n"))
533n/a if not self.allow_no_value:
534n/a e = self.parse_error(cf, configparser.ParsingError,
535n/a "[Foo]\n wrong-indent\n")
536n/a self.assertEqual(e.args, ('<???>',))
537n/a # read_file on a real file
538n/a tricky = support.findfile("cfgparser.3")
539n/a if self.delimiters[0] == '=':
540n/a error = configparser.ParsingError
541n/a expected = (tricky,)
542n/a else:
543n/a error = configparser.MissingSectionHeaderError
544n/a expected = (tricky, 1,
545n/a ' # INI with as many tricky parts as possible\n')
546n/a with open(tricky, encoding='utf-8') as f:
547n/a e = self.parse_error(cf, error, f)
548n/a self.assertEqual(e.args, expected)
549n/a
550n/a def parse_error(self, cf, exc, src):
551n/a if hasattr(src, 'readline'):
552n/a sio = src
553n/a else:
554n/a sio = io.StringIO(src)
555n/a with self.assertRaises(exc) as cm:
556n/a cf.read_file(sio)
557n/a return cm.exception
558n/a
559n/a def test_query_errors(self):
560n/a cf = self.newconfig()
561n/a self.assertEqual(cf.sections(), [],
562n/a "new ConfigParser should have no defined sections")
563n/a self.assertFalse(cf.has_section("Foo"),
564n/a "new ConfigParser should have no acknowledged "
565n/a "sections")
566n/a with self.assertRaises(configparser.NoSectionError):
567n/a cf.options("Foo")
568n/a with self.assertRaises(configparser.NoSectionError):
569n/a cf.set("foo", "bar", "value")
570n/a e = self.get_error(cf, configparser.NoSectionError, "foo", "bar")
571n/a self.assertEqual(e.args, ("foo",))
572n/a cf.add_section("foo")
573n/a e = self.get_error(cf, configparser.NoOptionError, "foo", "bar")
574n/a self.assertEqual(e.args, ("bar", "foo"))
575n/a
576n/a def get_error(self, cf, exc, section, option):
577n/a try:
578n/a cf.get(section, option)
579n/a except exc as e:
580n/a return e
581n/a else:
582n/a self.fail("expected exception type %s.%s"
583n/a % (exc.__module__, exc.__qualname__))
584n/a
585n/a def test_boolean(self):
586n/a cf = self.fromstring(
587n/a "[BOOLTEST]\n"
588n/a "T1{equals}1\n"
589n/a "T2{equals}TRUE\n"
590n/a "T3{equals}True\n"
591n/a "T4{equals}oN\n"
592n/a "T5{equals}yes\n"
593n/a "F1{equals}0\n"
594n/a "F2{equals}FALSE\n"
595n/a "F3{equals}False\n"
596n/a "F4{equals}oFF\n"
597n/a "F5{equals}nO\n"
598n/a "E1{equals}2\n"
599n/a "E2{equals}foo\n"
600n/a "E3{equals}-1\n"
601n/a "E4{equals}0.1\n"
602n/a "E5{equals}FALSE AND MORE".format(equals=self.delimiters[0])
603n/a )
604n/a for x in range(1, 5):
605n/a self.assertTrue(cf.getboolean('BOOLTEST', 't%d' % x))
606n/a self.assertFalse(cf.getboolean('BOOLTEST', 'f%d' % x))
607n/a self.assertRaises(ValueError,
608n/a cf.getboolean, 'BOOLTEST', 'e%d' % x)
609n/a
610n/a def test_weird_errors(self):
611n/a cf = self.newconfig()
612n/a cf.add_section("Foo")
613n/a with self.assertRaises(configparser.DuplicateSectionError) as cm:
614n/a cf.add_section("Foo")
615n/a e = cm.exception
616n/a self.assertEqual(str(e), "Section 'Foo' already exists")
617n/a self.assertEqual(e.args, ("Foo", None, None))
618n/a
619n/a if self.strict:
620n/a with self.assertRaises(configparser.DuplicateSectionError) as cm:
621n/a cf.read_string(textwrap.dedent("""\
622n/a [Foo]
623n/a will this be added{equals}True
624n/a [Bar]
625n/a what about this{equals}True
626n/a [Foo]
627n/a oops{equals}this won't
628n/a """.format(equals=self.delimiters[0])), source='<foo-bar>')
629n/a e = cm.exception
630n/a self.assertEqual(str(e), "While reading from '<foo-bar>' "
631n/a "[line 5]: section 'Foo' already exists")
632n/a self.assertEqual(e.args, ("Foo", '<foo-bar>', 5))
633n/a
634n/a with self.assertRaises(configparser.DuplicateOptionError) as cm:
635n/a cf.read_dict({'Bar': {'opt': 'val', 'OPT': 'is really `opt`'}})
636n/a e = cm.exception
637n/a self.assertEqual(str(e), "While reading from '<dict>': option "
638n/a "'opt' in section 'Bar' already exists")
639n/a self.assertEqual(e.args, ("Bar", "opt", "<dict>", None))
640n/a
641n/a def test_write(self):
642n/a config_string = (
643n/a "[Long Line]\n"
644n/a "foo{0[0]} this line is much, much longer than my editor\n"
645n/a " likes it.\n"
646n/a "[{default_section}]\n"
647n/a "foo{0[1]} another very\n"
648n/a " long line\n"
649n/a "[Long Line - With Comments!]\n"
650n/a "test {0[1]} we {comment} can\n"
651n/a " also {comment} place\n"
652n/a " comments {comment} in\n"
653n/a " multiline {comment} values"
654n/a "\n".format(self.delimiters, comment=self.comment_prefixes[0],
655n/a default_section=self.default_section)
656n/a )
657n/a if self.allow_no_value:
658n/a config_string += (
659n/a "[Valueless]\n"
660n/a "option-without-value\n"
661n/a )
662n/a
663n/a cf = self.fromstring(config_string)
664n/a for space_around_delimiters in (True, False):
665n/a output = io.StringIO()
666n/a cf.write(output, space_around_delimiters=space_around_delimiters)
667n/a delimiter = self.delimiters[0]
668n/a if space_around_delimiters:
669n/a delimiter = " {} ".format(delimiter)
670n/a expect_string = (
671n/a "[{default_section}]\n"
672n/a "foo{equals}another very\n"
673n/a "\tlong line\n"
674n/a "\n"
675n/a "[Long Line]\n"
676n/a "foo{equals}this line is much, much longer than my editor\n"
677n/a "\tlikes it.\n"
678n/a "\n"
679n/a "[Long Line - With Comments!]\n"
680n/a "test{equals}we\n"
681n/a "\talso\n"
682n/a "\tcomments\n"
683n/a "\tmultiline\n"
684n/a "\n".format(equals=delimiter,
685n/a default_section=self.default_section)
686n/a )
687n/a if self.allow_no_value:
688n/a expect_string += (
689n/a "[Valueless]\n"
690n/a "option-without-value\n"
691n/a "\n"
692n/a )
693n/a self.assertEqual(output.getvalue(), expect_string)
694n/a
695n/a def test_set_string_types(self):
696n/a cf = self.fromstring("[sect]\n"
697n/a "option1{eq}foo\n".format(eq=self.delimiters[0]))
698n/a # Check that we don't get an exception when setting values in
699n/a # an existing section using strings:
700n/a class mystr(str):
701n/a pass
702n/a cf.set("sect", "option1", "splat")
703n/a cf.set("sect", "option1", mystr("splat"))
704n/a cf.set("sect", "option2", "splat")
705n/a cf.set("sect", "option2", mystr("splat"))
706n/a cf.set("sect", "option1", "splat")
707n/a cf.set("sect", "option2", "splat")
708n/a
709n/a def test_read_returns_file_list(self):
710n/a if self.delimiters[0] != '=':
711n/a self.skipTest('incompatible format')
712n/a file1 = support.findfile("cfgparser.1")
713n/a # check when we pass a mix of readable and non-readable files:
714n/a cf = self.newconfig()
715n/a parsed_files = cf.read([file1, "nonexistent-file"])
716n/a self.assertEqual(parsed_files, [file1])
717n/a self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
718n/a # check when we pass only a filename:
719n/a cf = self.newconfig()
720n/a parsed_files = cf.read(file1)
721n/a self.assertEqual(parsed_files, [file1])
722n/a self.assertEqual(cf.get("Foo Bar", "foo"), "newbar")
723n/a # check when we pass only missing files:
724n/a cf = self.newconfig()
725n/a parsed_files = cf.read(["nonexistent-file"])
726n/a self.assertEqual(parsed_files, [])
727n/a # check when we pass no files:
728n/a cf = self.newconfig()
729n/a parsed_files = cf.read([])
730n/a self.assertEqual(parsed_files, [])
731n/a
732n/a # shared by subclasses
733n/a def get_interpolation_config(self):
734n/a return self.fromstring(
735n/a "[Foo]\n"
736n/a "bar{equals}something %(with1)s interpolation (1 step)\n"
737n/a "bar9{equals}something %(with9)s lots of interpolation (9 steps)\n"
738n/a "bar10{equals}something %(with10)s lots of interpolation (10 steps)\n"
739n/a "bar11{equals}something %(with11)s lots of interpolation (11 steps)\n"
740n/a "with11{equals}%(with10)s\n"
741n/a "with10{equals}%(with9)s\n"
742n/a "with9{equals}%(with8)s\n"
743n/a "with8{equals}%(With7)s\n"
744n/a "with7{equals}%(WITH6)s\n"
745n/a "with6{equals}%(with5)s\n"
746n/a "With5{equals}%(with4)s\n"
747n/a "WITH4{equals}%(with3)s\n"
748n/a "with3{equals}%(with2)s\n"
749n/a "with2{equals}%(with1)s\n"
750n/a "with1{equals}with\n"
751n/a "\n"
752n/a "[Mutual Recursion]\n"
753n/a "foo{equals}%(bar)s\n"
754n/a "bar{equals}%(foo)s\n"
755n/a "\n"
756n/a "[Interpolation Error]\n"
757n/a # no definition for 'reference'
758n/a "name{equals}%(reference)s\n".format(equals=self.delimiters[0]))
759n/a
760n/a def check_items_config(self, expected):
761n/a cf = self.fromstring("""
762n/a [section]
763n/a name {0[0]} %(value)s
764n/a key{0[1]} |%(name)s|
765n/a getdefault{0[1]} |%(default)s|
766n/a """.format(self.delimiters), defaults={"default": "<default>"})
767n/a L = list(cf.items("section", vars={'value': 'value'}))
768n/a L.sort()
769n/a self.assertEqual(L, expected)
770n/a with self.assertRaises(configparser.NoSectionError):
771n/a cf.items("no such section")
772n/a
773n/a def test_popitem(self):
774n/a cf = self.fromstring("""
775n/a [section1]
776n/a name1 {0[0]} value1
777n/a [section2]
778n/a name2 {0[0]} value2
779n/a [section3]
780n/a name3 {0[0]} value3
781n/a """.format(self.delimiters), defaults={"default": "<default>"})
782n/a self.assertEqual(cf.popitem()[0], 'section1')
783n/a self.assertEqual(cf.popitem()[0], 'section2')
784n/a self.assertEqual(cf.popitem()[0], 'section3')
785n/a with self.assertRaises(KeyError):
786n/a cf.popitem()
787n/a
788n/a def test_clear(self):
789n/a cf = self.newconfig({"foo": "Bar"})
790n/a self.assertEqual(
791n/a cf.get(self.default_section, "Foo"), "Bar",
792n/a "could not locate option, expecting case-insensitive option names")
793n/a cf['zing'] = {'option1': 'value1', 'option2': 'value2'}
794n/a self.assertEqual(cf.sections(), ['zing'])
795n/a self.assertEqual(set(cf['zing'].keys()), {'option1', 'option2', 'foo'})
796n/a cf.clear()
797n/a self.assertEqual(set(cf.sections()), set())
798n/a self.assertEqual(set(cf[self.default_section].keys()), {'foo'})
799n/a
800n/a def test_setitem(self):
801n/a cf = self.fromstring("""
802n/a [section1]
803n/a name1 {0[0]} value1
804n/a [section2]
805n/a name2 {0[0]} value2
806n/a [section3]
807n/a name3 {0[0]} value3
808n/a """.format(self.delimiters), defaults={"nameD": "valueD"})
809n/a self.assertEqual(set(cf['section1'].keys()), {'name1', 'named'})
810n/a self.assertEqual(set(cf['section2'].keys()), {'name2', 'named'})
811n/a self.assertEqual(set(cf['section3'].keys()), {'name3', 'named'})
812n/a self.assertEqual(cf['section1']['name1'], 'value1')
813n/a self.assertEqual(cf['section2']['name2'], 'value2')
814n/a self.assertEqual(cf['section3']['name3'], 'value3')
815n/a self.assertEqual(cf.sections(), ['section1', 'section2', 'section3'])
816n/a cf['section2'] = {'name22': 'value22'}
817n/a self.assertEqual(set(cf['section2'].keys()), {'name22', 'named'})
818n/a self.assertEqual(cf['section2']['name22'], 'value22')
819n/a self.assertNotIn('name2', cf['section2'])
820n/a self.assertEqual(cf.sections(), ['section1', 'section2', 'section3'])
821n/a cf['section3'] = {}
822n/a self.assertEqual(set(cf['section3'].keys()), {'named'})
823n/a self.assertNotIn('name3', cf['section3'])
824n/a self.assertEqual(cf.sections(), ['section1', 'section2', 'section3'])
825n/a cf[self.default_section] = {}
826n/a self.assertEqual(set(cf[self.default_section].keys()), set())
827n/a self.assertEqual(set(cf['section1'].keys()), {'name1'})
828n/a self.assertEqual(set(cf['section2'].keys()), {'name22'})
829n/a self.assertEqual(set(cf['section3'].keys()), set())
830n/a self.assertEqual(cf.sections(), ['section1', 'section2', 'section3'])
831n/a
832n/a def test_invalid_multiline_value(self):
833n/a if self.allow_no_value:
834n/a self.skipTest('if no_value is allowed, ParsingError is not raised')
835n/a
836n/a invalid = textwrap.dedent("""\
837n/a [DEFAULT]
838n/a test {0} test
839n/a invalid""".format(self.delimiters[0])
840n/a )
841n/a cf = self.newconfig()
842n/a with self.assertRaises(configparser.ParsingError):
843n/a cf.read_string(invalid)
844n/a self.assertEqual(cf.get('DEFAULT', 'test'), 'test')
845n/a self.assertEqual(cf['DEFAULT']['test'], 'test')
846n/a
847n/a
848n/aclass StrictTestCase(BasicTestCase, unittest.TestCase):
849n/a config_class = configparser.RawConfigParser
850n/a strict = True
851n/a
852n/a
853n/aclass ConfigParserTestCase(BasicTestCase, unittest.TestCase):
854n/a config_class = configparser.ConfigParser
855n/a
856n/a def test_interpolation(self):
857n/a cf = self.get_interpolation_config()
858n/a eq = self.assertEqual
859n/a eq(cf.get("Foo", "bar"), "something with interpolation (1 step)")
860n/a eq(cf.get("Foo", "bar9"),
861n/a "something with lots of interpolation (9 steps)")
862n/a eq(cf.get("Foo", "bar10"),
863n/a "something with lots of interpolation (10 steps)")
864n/a e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11")
865n/a if self.interpolation == configparser._UNSET:
866n/a self.assertEqual(e.args, ("bar11", "Foo",
867n/a "something %(with11)s lots of interpolation (11 steps)"))
868n/a elif isinstance(self.interpolation, configparser.LegacyInterpolation):
869n/a self.assertEqual(e.args, ("bar11", "Foo",
870n/a "something %(with11)s lots of interpolation (11 steps)"))
871n/a
872n/a def test_interpolation_missing_value(self):
873n/a cf = self.get_interpolation_config()
874n/a e = self.get_error(cf, configparser.InterpolationMissingOptionError,
875n/a "Interpolation Error", "name")
876n/a self.assertEqual(e.reference, "reference")
877n/a self.assertEqual(e.section, "Interpolation Error")
878n/a self.assertEqual(e.option, "name")
879n/a if self.interpolation == configparser._UNSET:
880n/a self.assertEqual(e.args, ('name', 'Interpolation Error',
881n/a '%(reference)s', 'reference'))
882n/a elif isinstance(self.interpolation, configparser.LegacyInterpolation):
883n/a self.assertEqual(e.args, ('name', 'Interpolation Error',
884n/a '%(reference)s', 'reference'))
885n/a
886n/a def test_items(self):
887n/a self.check_items_config([('default', '<default>'),
888n/a ('getdefault', '|<default>|'),
889n/a ('key', '|value|'),
890n/a ('name', 'value'),
891n/a ('value', 'value')])
892n/a
893n/a def test_safe_interpolation(self):
894n/a # See http://www.python.org/sf/511737
895n/a cf = self.fromstring("[section]\n"
896n/a "option1{eq}xxx\n"
897n/a "option2{eq}%(option1)s/xxx\n"
898n/a "ok{eq}%(option1)s/%%s\n"
899n/a "not_ok{eq}%(option2)s/%%s".format(
900n/a eq=self.delimiters[0]))
901n/a self.assertEqual(cf.get("section", "ok"), "xxx/%s")
902n/a if self.interpolation == configparser._UNSET:
903n/a self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s")
904n/a elif isinstance(self.interpolation, configparser.LegacyInterpolation):
905n/a with self.assertRaises(TypeError):
906n/a cf.get("section", "not_ok")
907n/a
908n/a def test_set_malformatted_interpolation(self):
909n/a cf = self.fromstring("[sect]\n"
910n/a "option1{eq}foo\n".format(eq=self.delimiters[0]))
911n/a
912n/a self.assertEqual(cf.get('sect', "option1"), "foo")
913n/a
914n/a self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo")
915n/a self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%")
916n/a self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo")
917n/a
918n/a self.assertEqual(cf.get('sect', "option1"), "foo")
919n/a
920n/a # bug #5741: double percents are *not* malformed
921n/a cf.set("sect", "option2", "foo%%bar")
922n/a self.assertEqual(cf.get("sect", "option2"), "foo%bar")
923n/a
924n/a def test_set_nonstring_types(self):
925n/a cf = self.fromstring("[sect]\n"
926n/a "option1{eq}foo\n".format(eq=self.delimiters[0]))
927n/a # Check that we get a TypeError when setting non-string values
928n/a # in an existing section:
929n/a self.assertRaises(TypeError, cf.set, "sect", "option1", 1)
930n/a self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0)
931n/a self.assertRaises(TypeError, cf.set, "sect", "option1", object())
932n/a self.assertRaises(TypeError, cf.set, "sect", "option2", 1)
933n/a self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0)
934n/a self.assertRaises(TypeError, cf.set, "sect", "option2", object())
935n/a self.assertRaises(TypeError, cf.set, "sect", 123, "invalid opt name!")
936n/a self.assertRaises(TypeError, cf.add_section, 123)
937n/a
938n/a def test_add_section_default(self):
939n/a cf = self.newconfig()
940n/a self.assertRaises(ValueError, cf.add_section, self.default_section)
941n/a
942n/a
943n/aclass ConfigParserTestCaseNoInterpolation(BasicTestCase, unittest.TestCase):
944n/a config_class = configparser.ConfigParser
945n/a interpolation = None
946n/a ini = textwrap.dedent("""
947n/a [numbers]
948n/a one = 1
949n/a two = %(one)s * 2
950n/a three = ${common:one} * 3
951n/a
952n/a [hexen]
953n/a sixteen = ${numbers:two} * 8
954n/a """).strip()
955n/a
956n/a def assertMatchesIni(self, cf):
957n/a self.assertEqual(cf['numbers']['one'], '1')
958n/a self.assertEqual(cf['numbers']['two'], '%(one)s * 2')
959n/a self.assertEqual(cf['numbers']['three'], '${common:one} * 3')
960n/a self.assertEqual(cf['hexen']['sixteen'], '${numbers:two} * 8')
961n/a
962n/a def test_no_interpolation(self):
963n/a cf = self.fromstring(self.ini)
964n/a self.assertMatchesIni(cf)
965n/a
966n/a def test_empty_case(self):
967n/a cf = self.newconfig()
968n/a self.assertIsNone(cf.read_string(""))
969n/a
970n/a def test_none_as_default_interpolation(self):
971n/a class CustomConfigParser(configparser.ConfigParser):
972n/a _DEFAULT_INTERPOLATION = None
973n/a
974n/a cf = CustomConfigParser()
975n/a cf.read_string(self.ini)
976n/a self.assertMatchesIni(cf)
977n/a
978n/a
979n/aclass ConfigParserTestCaseLegacyInterpolation(ConfigParserTestCase):
980n/a config_class = configparser.ConfigParser
981n/a interpolation = configparser.LegacyInterpolation()
982n/a
983n/a def test_set_malformatted_interpolation(self):
984n/a cf = self.fromstring("[sect]\n"
985n/a "option1{eq}foo\n".format(eq=self.delimiters[0]))
986n/a
987n/a self.assertEqual(cf.get('sect', "option1"), "foo")
988n/a
989n/a cf.set("sect", "option1", "%foo")
990n/a self.assertEqual(cf.get('sect', "option1"), "%foo")
991n/a cf.set("sect", "option1", "foo%")
992n/a self.assertEqual(cf.get('sect', "option1"), "foo%")
993n/a cf.set("sect", "option1", "f%oo")
994n/a self.assertEqual(cf.get('sect', "option1"), "f%oo")
995n/a
996n/a # bug #5741: double percents are *not* malformed
997n/a cf.set("sect", "option2", "foo%%bar")
998n/a self.assertEqual(cf.get("sect", "option2"), "foo%%bar")
999n/a
1000n/a
1001n/aclass ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase):
1002n/a delimiters = (':=', '$')
1003n/a comment_prefixes = ('//', '"')
1004n/a inline_comment_prefixes = ('//', '"')
1005n/a
1006n/a
1007n/aclass ConfigParserTestCaseNonStandardDefaultSection(ConfigParserTestCase):
1008n/a default_section = 'general'
1009n/a
1010n/a
1011n/aclass MultilineValuesTestCase(BasicTestCase, unittest.TestCase):
1012n/a config_class = configparser.ConfigParser
1013n/a wonderful_spam = ("I'm having spam spam spam spam "
1014n/a "spam spam spam beaked beans spam "
1015n/a "spam spam and spam!").replace(' ', '\t\n')
1016n/a
1017n/a def setUp(self):
1018n/a cf = self.newconfig()
1019n/a for i in range(100):
1020n/a s = 'section{}'.format(i)
1021n/a cf.add_section(s)
1022n/a for j in range(10):
1023n/a cf.set(s, 'lovely_spam{}'.format(j), self.wonderful_spam)
1024n/a with open(support.TESTFN, 'w') as f:
1025n/a cf.write(f)
1026n/a
1027n/a def tearDown(self):
1028n/a os.unlink(support.TESTFN)
1029n/a
1030n/a def test_dominating_multiline_values(self):
1031n/a # We're reading from file because this is where the code changed
1032n/a # during performance updates in Python 3.2
1033n/a cf_from_file = self.newconfig()
1034n/a with open(support.TESTFN) as f:
1035n/a cf_from_file.read_file(f)
1036n/a self.assertEqual(cf_from_file.get('section8', 'lovely_spam4'),
1037n/a self.wonderful_spam.replace('\t\n', '\n'))
1038n/a
1039n/a
1040n/aclass RawConfigParserTestCase(BasicTestCase, unittest.TestCase):
1041n/a config_class = configparser.RawConfigParser
1042n/a
1043n/a def test_interpolation(self):
1044n/a cf = self.get_interpolation_config()
1045n/a eq = self.assertEqual
1046n/a eq(cf.get("Foo", "bar"),
1047n/a "something %(with1)s interpolation (1 step)")
1048n/a eq(cf.get("Foo", "bar9"),
1049n/a "something %(with9)s lots of interpolation (9 steps)")
1050n/a eq(cf.get("Foo", "bar10"),
1051n/a "something %(with10)s lots of interpolation (10 steps)")
1052n/a eq(cf.get("Foo", "bar11"),
1053n/a "something %(with11)s lots of interpolation (11 steps)")
1054n/a
1055n/a def test_items(self):
1056n/a self.check_items_config([('default', '<default>'),
1057n/a ('getdefault', '|%(default)s|'),
1058n/a ('key', '|%(name)s|'),
1059n/a ('name', '%(value)s'),
1060n/a ('value', 'value')])
1061n/a
1062n/a def test_set_nonstring_types(self):
1063n/a cf = self.newconfig()
1064n/a cf.add_section('non-string')
1065n/a cf.set('non-string', 'int', 1)
1066n/a cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13])
1067n/a cf.set('non-string', 'dict', {'pi': 3.14159})
1068n/a self.assertEqual(cf.get('non-string', 'int'), 1)
1069n/a self.assertEqual(cf.get('non-string', 'list'),
1070n/a [0, 1, 1, 2, 3, 5, 8, 13])
1071n/a self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159})
1072n/a cf.add_section(123)
1073n/a cf.set(123, 'this is sick', True)
1074n/a self.assertEqual(cf.get(123, 'this is sick'), True)
1075n/a if cf._dict is configparser._default_dict:
1076n/a # would not work for SortedDict; only checking for the most common
1077n/a # default dictionary (OrderedDict)
1078n/a cf.optionxform = lambda x: x
1079n/a cf.set('non-string', 1, 1)
1080n/a self.assertEqual(cf.get('non-string', 1), 1)
1081n/a
1082n/a
1083n/aclass RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase):
1084n/a delimiters = (':=', '$')
1085n/a comment_prefixes = ('//', '"')
1086n/a inline_comment_prefixes = ('//', '"')
1087n/a
1088n/a
1089n/aclass RawConfigParserTestSambaConf(CfgParserTestCaseClass, unittest.TestCase):
1090n/a config_class = configparser.RawConfigParser
1091n/a comment_prefixes = ('#', ';', '----')
1092n/a inline_comment_prefixes = ('//',)
1093n/a empty_lines_in_values = False
1094n/a
1095n/a def test_reading(self):
1096n/a smbconf = support.findfile("cfgparser.2")
1097n/a # check when we pass a mix of readable and non-readable files:
1098n/a cf = self.newconfig()
1099n/a parsed_files = cf.read([smbconf, "nonexistent-file"], encoding='utf-8')
1100n/a self.assertEqual(parsed_files, [smbconf])
1101n/a sections = ['global', 'homes', 'printers',
1102n/a 'print$', 'pdf-generator', 'tmp', 'Agustin']
1103n/a self.assertEqual(cf.sections(), sections)
1104n/a self.assertEqual(cf.get("global", "workgroup"), "MDKGROUP")
1105n/a self.assertEqual(cf.getint("global", "max log size"), 50)
1106n/a self.assertEqual(cf.get("global", "hosts allow"), "127.")
1107n/a self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s")
1108n/a
1109n/aclass ConfigParserTestCaseExtendedInterpolation(BasicTestCase, unittest.TestCase):
1110n/a config_class = configparser.ConfigParser
1111n/a interpolation = configparser.ExtendedInterpolation()
1112n/a default_section = 'common'
1113n/a strict = True
1114n/a
1115n/a def fromstring(self, string, defaults=None, optionxform=None):
1116n/a cf = self.newconfig(defaults)
1117n/a if optionxform:
1118n/a cf.optionxform = optionxform
1119n/a cf.read_string(string)
1120n/a return cf
1121n/a
1122n/a def test_extended_interpolation(self):
1123n/a cf = self.fromstring(textwrap.dedent("""
1124n/a [common]
1125n/a favourite Beatle = Paul
1126n/a favourite color = green
1127n/a
1128n/a [tom]
1129n/a favourite band = ${favourite color} day
1130n/a favourite pope = John ${favourite Beatle} II
1131n/a sequel = ${favourite pope}I
1132n/a
1133n/a [ambv]
1134n/a favourite Beatle = George
1135n/a son of Edward VII = ${favourite Beatle} V
1136n/a son of George V = ${son of Edward VII}I
1137n/a
1138n/a [stanley]
1139n/a favourite Beatle = ${ambv:favourite Beatle}
1140n/a favourite pope = ${tom:favourite pope}
1141n/a favourite color = black
1142n/a favourite state of mind = paranoid
1143n/a favourite movie = soylent ${common:favourite color}
1144n/a favourite song = ${favourite color} sabbath - ${favourite state of mind}
1145n/a """).strip())
1146n/a
1147n/a eq = self.assertEqual
1148n/a eq(cf['common']['favourite Beatle'], 'Paul')
1149n/a eq(cf['common']['favourite color'], 'green')
1150n/a eq(cf['tom']['favourite Beatle'], 'Paul')
1151n/a eq(cf['tom']['favourite color'], 'green')
1152n/a eq(cf['tom']['favourite band'], 'green day')
1153n/a eq(cf['tom']['favourite pope'], 'John Paul II')
1154n/a eq(cf['tom']['sequel'], 'John Paul III')
1155n/a eq(cf['ambv']['favourite Beatle'], 'George')
1156n/a eq(cf['ambv']['favourite color'], 'green')
1157n/a eq(cf['ambv']['son of Edward VII'], 'George V')
1158n/a eq(cf['ambv']['son of George V'], 'George VI')
1159n/a eq(cf['stanley']['favourite Beatle'], 'George')
1160n/a eq(cf['stanley']['favourite color'], 'black')
1161n/a eq(cf['stanley']['favourite state of mind'], 'paranoid')
1162n/a eq(cf['stanley']['favourite movie'], 'soylent green')
1163n/a eq(cf['stanley']['favourite pope'], 'John Paul II')
1164n/a eq(cf['stanley']['favourite song'],
1165n/a 'black sabbath - paranoid')
1166n/a
1167n/a def test_endless_loop(self):
1168n/a cf = self.fromstring(textwrap.dedent("""
1169n/a [one for you]
1170n/a ping = ${one for me:pong}
1171n/a
1172n/a [one for me]
1173n/a pong = ${one for you:ping}
1174n/a
1175n/a [selfish]
1176n/a me = ${me}
1177n/a """).strip())
1178n/a
1179n/a with self.assertRaises(configparser.InterpolationDepthError):
1180n/a cf['one for you']['ping']
1181n/a with self.assertRaises(configparser.InterpolationDepthError):
1182n/a cf['selfish']['me']
1183n/a
1184n/a def test_strange_options(self):
1185n/a cf = self.fromstring("""
1186n/a [dollars]
1187n/a $var = $$value
1188n/a $var2 = ${$var}
1189n/a ${sick} = cannot interpolate me
1190n/a
1191n/a [interpolated]
1192n/a $other = ${dollars:$var}
1193n/a $trying = ${dollars:${sick}}
1194n/a """)
1195n/a
1196n/a self.assertEqual(cf['dollars']['$var'], '$value')
1197n/a self.assertEqual(cf['interpolated']['$other'], '$value')
1198n/a self.assertEqual(cf['dollars']['${sick}'], 'cannot interpolate me')
1199n/a exception_class = configparser.InterpolationMissingOptionError
1200n/a with self.assertRaises(exception_class) as cm:
1201n/a cf['interpolated']['$trying']
1202n/a self.assertEqual(cm.exception.reference, 'dollars:${sick')
1203n/a self.assertEqual(cm.exception.args[2], '${dollars:${sick}}') #rawval
1204n/a
1205n/a def test_case_sensitivity_basic(self):
1206n/a ini = textwrap.dedent("""
1207n/a [common]
1208n/a optionlower = value
1209n/a OptionUpper = Value
1210n/a
1211n/a [Common]
1212n/a optionlower = a better ${common:optionlower}
1213n/a OptionUpper = A Better ${common:OptionUpper}
1214n/a
1215n/a [random]
1216n/a foolower = ${common:optionlower} redefined
1217n/a FooUpper = ${Common:OptionUpper} Redefined
1218n/a """).strip()
1219n/a
1220n/a cf = self.fromstring(ini)
1221n/a eq = self.assertEqual
1222n/a eq(cf['common']['optionlower'], 'value')
1223n/a eq(cf['common']['OptionUpper'], 'Value')
1224n/a eq(cf['Common']['optionlower'], 'a better value')
1225n/a eq(cf['Common']['OptionUpper'], 'A Better Value')
1226n/a eq(cf['random']['foolower'], 'value redefined')
1227n/a eq(cf['random']['FooUpper'], 'A Better Value Redefined')
1228n/a
1229n/a def test_case_sensitivity_conflicts(self):
1230n/a ini = textwrap.dedent("""
1231n/a [common]
1232n/a option = value
1233n/a Option = Value
1234n/a
1235n/a [Common]
1236n/a option = a better ${common:option}
1237n/a Option = A Better ${common:Option}
1238n/a
1239n/a [random]
1240n/a foo = ${common:option} redefined
1241n/a Foo = ${Common:Option} Redefined
1242n/a """).strip()
1243n/a with self.assertRaises(configparser.DuplicateOptionError):
1244n/a cf = self.fromstring(ini)
1245n/a
1246n/a # raw options
1247n/a cf = self.fromstring(ini, optionxform=lambda opt: opt)
1248n/a eq = self.assertEqual
1249n/a eq(cf['common']['option'], 'value')
1250n/a eq(cf['common']['Option'], 'Value')
1251n/a eq(cf['Common']['option'], 'a better value')
1252n/a eq(cf['Common']['Option'], 'A Better Value')
1253n/a eq(cf['random']['foo'], 'value redefined')
1254n/a eq(cf['random']['Foo'], 'A Better Value Redefined')
1255n/a
1256n/a def test_other_errors(self):
1257n/a cf = self.fromstring("""
1258n/a [interpolation fail]
1259n/a case1 = ${where's the brace
1260n/a case2 = ${does_not_exist}
1261n/a case3 = ${wrong_section:wrong_value}
1262n/a case4 = ${i:like:colon:characters}
1263n/a case5 = $100 for Fail No 5!
1264n/a """)
1265n/a
1266n/a with self.assertRaises(configparser.InterpolationSyntaxError):
1267n/a cf['interpolation fail']['case1']
1268n/a with self.assertRaises(configparser.InterpolationMissingOptionError):
1269n/a cf['interpolation fail']['case2']
1270n/a with self.assertRaises(configparser.InterpolationMissingOptionError):
1271n/a cf['interpolation fail']['case3']
1272n/a with self.assertRaises(configparser.InterpolationSyntaxError):
1273n/a cf['interpolation fail']['case4']
1274n/a with self.assertRaises(configparser.InterpolationSyntaxError):
1275n/a cf['interpolation fail']['case5']
1276n/a with self.assertRaises(ValueError):
1277n/a cf['interpolation fail']['case6'] = "BLACK $ABBATH"
1278n/a
1279n/a
1280n/aclass ConfigParserTestCaseNoValue(ConfigParserTestCase):
1281n/a allow_no_value = True
1282n/a
1283n/a
1284n/aclass ConfigParserTestCaseTrickyFile(CfgParserTestCaseClass, unittest.TestCase):
1285n/a config_class = configparser.ConfigParser
1286n/a delimiters = {'='}
1287n/a comment_prefixes = {'#'}
1288n/a allow_no_value = True
1289n/a
1290n/a def test_cfgparser_dot_3(self):
1291n/a tricky = support.findfile("cfgparser.3")
1292n/a cf = self.newconfig()
1293n/a self.assertEqual(len(cf.read(tricky, encoding='utf-8')), 1)
1294n/a self.assertEqual(cf.sections(), ['strange',
1295n/a 'corruption',
1296n/a 'yeah, sections can be '
1297n/a 'indented as well',
1298n/a 'another one!',
1299n/a 'no values here',
1300n/a 'tricky interpolation',
1301n/a 'more interpolation'])
1302n/a self.assertEqual(cf.getint(self.default_section, 'go',
1303n/a vars={'interpolate': '-1'}), -1)
1304n/a with self.assertRaises(ValueError):
1305n/a # no interpolation will happen
1306n/a cf.getint(self.default_section, 'go', raw=True,
1307n/a vars={'interpolate': '-1'})
1308n/a self.assertEqual(len(cf.get('strange', 'other').split('\n')), 4)
1309n/a self.assertEqual(len(cf.get('corruption', 'value').split('\n')), 10)
1310n/a longname = 'yeah, sections can be indented as well'
1311n/a self.assertFalse(cf.getboolean(longname, 'are they subsections'))
1312n/a self.assertEqual(cf.get(longname, 'lets use some Unicode'), '片仮名')
1313n/a self.assertEqual(len(cf.items('another one!')), 5) # 4 in section and
1314n/a # `go` from DEFAULT
1315n/a with self.assertRaises(configparser.InterpolationMissingOptionError):
1316n/a cf.items('no values here')
1317n/a self.assertEqual(cf.get('tricky interpolation', 'lets'), 'do this')
1318n/a self.assertEqual(cf.get('tricky interpolation', 'lets'),
1319n/a cf.get('tricky interpolation', 'go'))
1320n/a self.assertEqual(cf.get('more interpolation', 'lets'), 'go shopping')
1321n/a
1322n/a def test_unicode_failure(self):
1323n/a tricky = support.findfile("cfgparser.3")
1324n/a cf = self.newconfig()
1325n/a with self.assertRaises(UnicodeDecodeError):
1326n/a cf.read(tricky, encoding='ascii')
1327n/a
1328n/a
1329n/aclass Issue7005TestCase(unittest.TestCase):
1330n/a """Test output when None is set() as a value and allow_no_value == False.
1331n/a
1332n/a http://bugs.python.org/issue7005
1333n/a
1334n/a """
1335n/a
1336n/a expected_output = "[section]\noption = None\n\n"
1337n/a
1338n/a def prepare(self, config_class):
1339n/a # This is the default, but that's the point.
1340n/a cp = config_class(allow_no_value=False)
1341n/a cp.add_section("section")
1342n/a cp.set("section", "option", None)
1343n/a sio = io.StringIO()
1344n/a cp.write(sio)
1345n/a return sio.getvalue()
1346n/a
1347n/a def test_none_as_value_stringified(self):
1348n/a cp = configparser.ConfigParser(allow_no_value=False)
1349n/a cp.add_section("section")
1350n/a with self.assertRaises(TypeError):
1351n/a cp.set("section", "option", None)
1352n/a
1353n/a def test_none_as_value_stringified_raw(self):
1354n/a output = self.prepare(configparser.RawConfigParser)
1355n/a self.assertEqual(output, self.expected_output)
1356n/a
1357n/a
1358n/aclass SortedTestCase(RawConfigParserTestCase):
1359n/a dict_type = SortedDict
1360n/a
1361n/a def test_sorted(self):
1362n/a cf = self.fromstring("[b]\n"
1363n/a "o4=1\n"
1364n/a "o3=2\n"
1365n/a "o2=3\n"
1366n/a "o1=4\n"
1367n/a "[a]\n"
1368n/a "k=v\n")
1369n/a output = io.StringIO()
1370n/a cf.write(output)
1371n/a self.assertEqual(output.getvalue(),
1372n/a "[a]\n"
1373n/a "k = v\n\n"
1374n/a "[b]\n"
1375n/a "o1 = 4\n"
1376n/a "o2 = 3\n"
1377n/a "o3 = 2\n"
1378n/a "o4 = 1\n\n")
1379n/a
1380n/a
1381n/aclass CompatibleTestCase(CfgParserTestCaseClass, unittest.TestCase):
1382n/a config_class = configparser.RawConfigParser
1383n/a comment_prefixes = '#;'
1384n/a inline_comment_prefixes = ';'
1385n/a
1386n/a def test_comment_handling(self):
1387n/a config_string = textwrap.dedent("""\
1388n/a [Commented Bar]
1389n/a baz=qwe ; a comment
1390n/a foo: bar # not a comment!
1391n/a # but this is a comment
1392n/a ; another comment
1393n/a quirk: this;is not a comment
1394n/a ; a space must precede an inline comment
1395n/a """)
1396n/a cf = self.fromstring(config_string)
1397n/a self.assertEqual(cf.get('Commented Bar', 'foo'),
1398n/a 'bar # not a comment!')
1399n/a self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe')
1400n/a self.assertEqual(cf.get('Commented Bar', 'quirk'),
1401n/a 'this;is not a comment')
1402n/a
1403n/aclass CopyTestCase(BasicTestCase, unittest.TestCase):
1404n/a config_class = configparser.ConfigParser
1405n/a
1406n/a def fromstring(self, string, defaults=None):
1407n/a cf = self.newconfig(defaults)
1408n/a cf.read_string(string)
1409n/a cf_copy = self.newconfig()
1410n/a cf_copy.read_dict(cf)
1411n/a # we have to clean up option duplicates that appeared because of
1412n/a # the magic DEFAULTSECT behaviour.
1413n/a for section in cf_copy.values():
1414n/a if section.name == self.default_section:
1415n/a continue
1416n/a for default, value in cf[self.default_section].items():
1417n/a if section[default] == value:
1418n/a del section[default]
1419n/a return cf_copy
1420n/a
1421n/a
1422n/aclass FakeFile:
1423n/a def __init__(self):
1424n/a file_path = support.findfile("cfgparser.1")
1425n/a with open(file_path) as f:
1426n/a self.lines = f.readlines()
1427n/a self.lines.reverse()
1428n/a
1429n/a def readline(self):
1430n/a if len(self.lines):
1431n/a return self.lines.pop()
1432n/a return ''
1433n/a
1434n/a
1435n/adef readline_generator(f):
1436n/a """As advised in Doc/library/configparser.rst."""
1437n/a line = f.readline()
1438n/a while line:
1439n/a yield line
1440n/a line = f.readline()
1441n/a
1442n/a
1443n/aclass ReadFileTestCase(unittest.TestCase):
1444n/a def test_file(self):
1445n/a file_paths = [support.findfile("cfgparser.1")]
1446n/a try:
1447n/a file_paths.append(file_paths[0].encode('utf8'))
1448n/a except UnicodeEncodeError:
1449n/a pass # unfortunately we can't test bytes on this path
1450n/a for file_path in file_paths:
1451n/a parser = configparser.ConfigParser()
1452n/a with open(file_path) as f:
1453n/a parser.read_file(f)
1454n/a self.assertIn("Foo Bar", parser)
1455n/a self.assertIn("foo", parser["Foo Bar"])
1456n/a self.assertEqual(parser["Foo Bar"]["foo"], "newbar")
1457n/a
1458n/a def test_iterable(self):
1459n/a lines = textwrap.dedent("""
1460n/a [Foo Bar]
1461n/a foo=newbar""").strip().split('\n')
1462n/a parser = configparser.ConfigParser()
1463n/a parser.read_file(lines)
1464n/a self.assertIn("Foo Bar", parser)
1465n/a self.assertIn("foo", parser["Foo Bar"])
1466n/a self.assertEqual(parser["Foo Bar"]["foo"], "newbar")
1467n/a
1468n/a def test_readline_generator(self):
1469n/a """Issue #11670."""
1470n/a parser = configparser.ConfigParser()
1471n/a with self.assertRaises(TypeError):
1472n/a parser.read_file(FakeFile())
1473n/a parser.read_file(readline_generator(FakeFile()))
1474n/a self.assertIn("Foo Bar", parser)
1475n/a self.assertIn("foo", parser["Foo Bar"])
1476n/a self.assertEqual(parser["Foo Bar"]["foo"], "newbar")
1477n/a
1478n/a def test_source_as_bytes(self):
1479n/a """Issue #18260."""
1480n/a lines = textwrap.dedent("""
1481n/a [badbad]
1482n/a [badbad]""").strip().split('\n')
1483n/a parser = configparser.ConfigParser()
1484n/a with self.assertRaises(configparser.DuplicateSectionError) as dse:
1485n/a parser.read_file(lines, source=b"badbad")
1486n/a self.assertEqual(
1487n/a str(dse.exception),
1488n/a "While reading from b'badbad' [line 2]: section 'badbad' "
1489n/a "already exists"
1490n/a )
1491n/a lines = textwrap.dedent("""
1492n/a [badbad]
1493n/a bad = bad
1494n/a bad = bad""").strip().split('\n')
1495n/a parser = configparser.ConfigParser()
1496n/a with self.assertRaises(configparser.DuplicateOptionError) as dse:
1497n/a parser.read_file(lines, source=b"badbad")
1498n/a self.assertEqual(
1499n/a str(dse.exception),
1500n/a "While reading from b'badbad' [line 3]: option 'bad' in section "
1501n/a "'badbad' already exists"
1502n/a )
1503n/a lines = textwrap.dedent("""
1504n/a [badbad]
1505n/a = bad""").strip().split('\n')
1506n/a parser = configparser.ConfigParser()
1507n/a with self.assertRaises(configparser.ParsingError) as dse:
1508n/a parser.read_file(lines, source=b"badbad")
1509n/a self.assertEqual(
1510n/a str(dse.exception),
1511n/a "Source contains parsing errors: b'badbad'\n\t[line 2]: '= bad'"
1512n/a )
1513n/a lines = textwrap.dedent("""
1514n/a [badbad
1515n/a bad = bad""").strip().split('\n')
1516n/a parser = configparser.ConfigParser()
1517n/a with self.assertRaises(configparser.MissingSectionHeaderError) as dse:
1518n/a parser.read_file(lines, source=b"badbad")
1519n/a self.assertEqual(
1520n/a str(dse.exception),
1521n/a "File contains no section headers.\nfile: b'badbad', line: 1\n"
1522n/a "'[badbad'"
1523n/a )
1524n/a
1525n/a
1526n/aclass CoverageOneHundredTestCase(unittest.TestCase):
1527n/a """Covers edge cases in the codebase."""
1528n/a
1529n/a def test_duplicate_option_error(self):
1530n/a error = configparser.DuplicateOptionError('section', 'option')
1531n/a self.assertEqual(error.section, 'section')
1532n/a self.assertEqual(error.option, 'option')
1533n/a self.assertEqual(error.source, None)
1534n/a self.assertEqual(error.lineno, None)
1535n/a self.assertEqual(error.args, ('section', 'option', None, None))
1536n/a self.assertEqual(str(error), "Option 'option' in section 'section' "
1537n/a "already exists")
1538n/a
1539n/a def test_interpolation_depth_error(self):
1540n/a error = configparser.InterpolationDepthError('option', 'section',
1541n/a 'rawval')
1542n/a self.assertEqual(error.args, ('option', 'section', 'rawval'))
1543n/a self.assertEqual(error.option, 'option')
1544n/a self.assertEqual(error.section, 'section')
1545n/a
1546n/a def test_parsing_error(self):
1547n/a with self.assertRaises(ValueError) as cm:
1548n/a configparser.ParsingError()
1549n/a self.assertEqual(str(cm.exception), "Required argument `source' not "
1550n/a "given.")
1551n/a with self.assertRaises(ValueError) as cm:
1552n/a configparser.ParsingError(source='source', filename='filename')
1553n/a self.assertEqual(str(cm.exception), "Cannot specify both `filename' "
1554n/a "and `source'. Use `source'.")
1555n/a error = configparser.ParsingError(filename='source')
1556n/a self.assertEqual(error.source, 'source')
1557n/a with warnings.catch_warnings(record=True) as w:
1558n/a warnings.simplefilter("always", DeprecationWarning)
1559n/a self.assertEqual(error.filename, 'source')
1560n/a error.filename = 'filename'
1561n/a self.assertEqual(error.source, 'filename')
1562n/a for warning in w:
1563n/a self.assertTrue(warning.category is DeprecationWarning)
1564n/a
1565n/a def test_interpolation_validation(self):
1566n/a parser = configparser.ConfigParser()
1567n/a parser.read_string("""
1568n/a [section]
1569n/a invalid_percent = %
1570n/a invalid_reference = %(()
1571n/a invalid_variable = %(does_not_exist)s
1572n/a """)
1573n/a with self.assertRaises(configparser.InterpolationSyntaxError) as cm:
1574n/a parser['section']['invalid_percent']
1575n/a self.assertEqual(str(cm.exception), "'%' must be followed by '%' or "
1576n/a "'(', found: '%'")
1577n/a with self.assertRaises(configparser.InterpolationSyntaxError) as cm:
1578n/a parser['section']['invalid_reference']
1579n/a self.assertEqual(str(cm.exception), "bad interpolation variable "
1580n/a "reference '%(()'")
1581n/a
1582n/a def test_readfp_deprecation(self):
1583n/a sio = io.StringIO("""
1584n/a [section]
1585n/a option = value
1586n/a """)
1587n/a parser = configparser.ConfigParser()
1588n/a with warnings.catch_warnings(record=True) as w:
1589n/a warnings.simplefilter("always", DeprecationWarning)
1590n/a parser.readfp(sio, filename='StringIO')
1591n/a for warning in w:
1592n/a self.assertTrue(warning.category is DeprecationWarning)
1593n/a self.assertEqual(len(parser), 2)
1594n/a self.assertEqual(parser['section']['option'], 'value')
1595n/a
1596n/a def test_safeconfigparser_deprecation(self):
1597n/a with warnings.catch_warnings(record=True) as w:
1598n/a warnings.simplefilter("always", DeprecationWarning)
1599n/a parser = configparser.SafeConfigParser()
1600n/a for warning in w:
1601n/a self.assertTrue(warning.category is DeprecationWarning)
1602n/a
1603n/a def test_sectionproxy_repr(self):
1604n/a parser = configparser.ConfigParser()
1605n/a parser.read_string("""
1606n/a [section]
1607n/a key = value
1608n/a """)
1609n/a self.assertEqual(repr(parser['section']), '<Section: section>')
1610n/a
1611n/a def test_inconsistent_converters_state(self):
1612n/a parser = configparser.ConfigParser()
1613n/a import decimal
1614n/a parser.converters['decimal'] = decimal.Decimal
1615n/a parser.read_string("""
1616n/a [s1]
1617n/a one = 1
1618n/a [s2]
1619n/a two = 2
1620n/a """)
1621n/a self.assertIn('decimal', parser.converters)
1622n/a self.assertEqual(parser.getdecimal('s1', 'one'), 1)
1623n/a self.assertEqual(parser.getdecimal('s2', 'two'), 2)
1624n/a self.assertEqual(parser['s1'].getdecimal('one'), 1)
1625n/a self.assertEqual(parser['s2'].getdecimal('two'), 2)
1626n/a del parser.getdecimal
1627n/a with self.assertRaises(AttributeError):
1628n/a parser.getdecimal('s1', 'one')
1629n/a self.assertIn('decimal', parser.converters)
1630n/a del parser.converters['decimal']
1631n/a self.assertNotIn('decimal', parser.converters)
1632n/a with self.assertRaises(AttributeError):
1633n/a parser.getdecimal('s1', 'one')
1634n/a with self.assertRaises(AttributeError):
1635n/a parser['s1'].getdecimal('one')
1636n/a with self.assertRaises(AttributeError):
1637n/a parser['s2'].getdecimal('two')
1638n/a
1639n/a
1640n/aclass ExceptionPicklingTestCase(unittest.TestCase):
1641n/a """Tests for issue #13760: ConfigParser exceptions are not picklable."""
1642n/a
1643n/a def test_error(self):
1644n/a import pickle
1645n/a e1 = configparser.Error('value')
1646n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1647n/a pickled = pickle.dumps(e1, proto)
1648n/a e2 = pickle.loads(pickled)
1649n/a self.assertEqual(e1.message, e2.message)
1650n/a self.assertEqual(repr(e1), repr(e2))
1651n/a
1652n/a def test_nosectionerror(self):
1653n/a import pickle
1654n/a e1 = configparser.NoSectionError('section')
1655n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1656n/a pickled = pickle.dumps(e1, proto)
1657n/a e2 = pickle.loads(pickled)
1658n/a self.assertEqual(e1.message, e2.message)
1659n/a self.assertEqual(e1.args, e2.args)
1660n/a self.assertEqual(e1.section, e2.section)
1661n/a self.assertEqual(repr(e1), repr(e2))
1662n/a
1663n/a def test_nooptionerror(self):
1664n/a import pickle
1665n/a e1 = configparser.NoOptionError('option', 'section')
1666n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1667n/a pickled = pickle.dumps(e1, proto)
1668n/a e2 = pickle.loads(pickled)
1669n/a self.assertEqual(e1.message, e2.message)
1670n/a self.assertEqual(e1.args, e2.args)
1671n/a self.assertEqual(e1.section, e2.section)
1672n/a self.assertEqual(e1.option, e2.option)
1673n/a self.assertEqual(repr(e1), repr(e2))
1674n/a
1675n/a def test_duplicatesectionerror(self):
1676n/a import pickle
1677n/a e1 = configparser.DuplicateSectionError('section', 'source', 123)
1678n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1679n/a pickled = pickle.dumps(e1, proto)
1680n/a e2 = pickle.loads(pickled)
1681n/a self.assertEqual(e1.message, e2.message)
1682n/a self.assertEqual(e1.args, e2.args)
1683n/a self.assertEqual(e1.section, e2.section)
1684n/a self.assertEqual(e1.source, e2.source)
1685n/a self.assertEqual(e1.lineno, e2.lineno)
1686n/a self.assertEqual(repr(e1), repr(e2))
1687n/a
1688n/a def test_duplicateoptionerror(self):
1689n/a import pickle
1690n/a e1 = configparser.DuplicateOptionError('section', 'option', 'source',
1691n/a 123)
1692n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1693n/a pickled = pickle.dumps(e1, proto)
1694n/a e2 = pickle.loads(pickled)
1695n/a self.assertEqual(e1.message, e2.message)
1696n/a self.assertEqual(e1.args, e2.args)
1697n/a self.assertEqual(e1.section, e2.section)
1698n/a self.assertEqual(e1.option, e2.option)
1699n/a self.assertEqual(e1.source, e2.source)
1700n/a self.assertEqual(e1.lineno, e2.lineno)
1701n/a self.assertEqual(repr(e1), repr(e2))
1702n/a
1703n/a def test_interpolationerror(self):
1704n/a import pickle
1705n/a e1 = configparser.InterpolationError('option', 'section', 'msg')
1706n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1707n/a pickled = pickle.dumps(e1, proto)
1708n/a e2 = pickle.loads(pickled)
1709n/a self.assertEqual(e1.message, e2.message)
1710n/a self.assertEqual(e1.args, e2.args)
1711n/a self.assertEqual(e1.section, e2.section)
1712n/a self.assertEqual(e1.option, e2.option)
1713n/a self.assertEqual(repr(e1), repr(e2))
1714n/a
1715n/a def test_interpolationmissingoptionerror(self):
1716n/a import pickle
1717n/a e1 = configparser.InterpolationMissingOptionError('option', 'section',
1718n/a 'rawval', 'reference')
1719n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1720n/a pickled = pickle.dumps(e1, proto)
1721n/a e2 = pickle.loads(pickled)
1722n/a self.assertEqual(e1.message, e2.message)
1723n/a self.assertEqual(e1.args, e2.args)
1724n/a self.assertEqual(e1.section, e2.section)
1725n/a self.assertEqual(e1.option, e2.option)
1726n/a self.assertEqual(e1.reference, e2.reference)
1727n/a self.assertEqual(repr(e1), repr(e2))
1728n/a
1729n/a def test_interpolationsyntaxerror(self):
1730n/a import pickle
1731n/a e1 = configparser.InterpolationSyntaxError('option', 'section', 'msg')
1732n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1733n/a pickled = pickle.dumps(e1, proto)
1734n/a e2 = pickle.loads(pickled)
1735n/a self.assertEqual(e1.message, e2.message)
1736n/a self.assertEqual(e1.args, e2.args)
1737n/a self.assertEqual(e1.section, e2.section)
1738n/a self.assertEqual(e1.option, e2.option)
1739n/a self.assertEqual(repr(e1), repr(e2))
1740n/a
1741n/a def test_interpolationdeptherror(self):
1742n/a import pickle
1743n/a e1 = configparser.InterpolationDepthError('option', 'section',
1744n/a 'rawval')
1745n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1746n/a pickled = pickle.dumps(e1, proto)
1747n/a e2 = pickle.loads(pickled)
1748n/a self.assertEqual(e1.message, e2.message)
1749n/a self.assertEqual(e1.args, e2.args)
1750n/a self.assertEqual(e1.section, e2.section)
1751n/a self.assertEqual(e1.option, e2.option)
1752n/a self.assertEqual(repr(e1), repr(e2))
1753n/a
1754n/a def test_parsingerror(self):
1755n/a import pickle
1756n/a e1 = configparser.ParsingError('source')
1757n/a e1.append(1, 'line1')
1758n/a e1.append(2, 'line2')
1759n/a e1.append(3, 'line3')
1760n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1761n/a pickled = pickle.dumps(e1, proto)
1762n/a e2 = pickle.loads(pickled)
1763n/a self.assertEqual(e1.message, e2.message)
1764n/a self.assertEqual(e1.args, e2.args)
1765n/a self.assertEqual(e1.source, e2.source)
1766n/a self.assertEqual(e1.errors, e2.errors)
1767n/a self.assertEqual(repr(e1), repr(e2))
1768n/a e1 = configparser.ParsingError(filename='filename')
1769n/a e1.append(1, 'line1')
1770n/a e1.append(2, 'line2')
1771n/a e1.append(3, 'line3')
1772n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1773n/a pickled = pickle.dumps(e1, proto)
1774n/a e2 = pickle.loads(pickled)
1775n/a self.assertEqual(e1.message, e2.message)
1776n/a self.assertEqual(e1.args, e2.args)
1777n/a self.assertEqual(e1.source, e2.source)
1778n/a self.assertEqual(e1.errors, e2.errors)
1779n/a self.assertEqual(repr(e1), repr(e2))
1780n/a
1781n/a def test_missingsectionheadererror(self):
1782n/a import pickle
1783n/a e1 = configparser.MissingSectionHeaderError('filename', 123, 'line')
1784n/a for proto in range(pickle.HIGHEST_PROTOCOL + 1):
1785n/a pickled = pickle.dumps(e1, proto)
1786n/a e2 = pickle.loads(pickled)
1787n/a self.assertEqual(e1.message, e2.message)
1788n/a self.assertEqual(e1.args, e2.args)
1789n/a self.assertEqual(e1.line, e2.line)
1790n/a self.assertEqual(e1.source, e2.source)
1791n/a self.assertEqual(e1.lineno, e2.lineno)
1792n/a self.assertEqual(repr(e1), repr(e2))
1793n/a
1794n/a
1795n/aclass InlineCommentStrippingTestCase(unittest.TestCase):
1796n/a """Tests for issue #14590: ConfigParser doesn't strip inline comment when
1797n/a delimiter occurs earlier without preceding space.."""
1798n/a
1799n/a def test_stripping(self):
1800n/a cfg = configparser.ConfigParser(inline_comment_prefixes=(';', '#',
1801n/a '//'))
1802n/a cfg.read_string("""
1803n/a [section]
1804n/a k1 = v1;still v1
1805n/a k2 = v2 ;a comment
1806n/a k3 = v3 ; also a comment
1807n/a k4 = v4;still v4 ;a comment
1808n/a k5 = v5;still v5 ; also a comment
1809n/a k6 = v6;still v6; and still v6 ;a comment
1810n/a k7 = v7;still v7; and still v7 ; also a comment
1811n/a
1812n/a [multiprefix]
1813n/a k1 = v1;still v1 #a comment ; yeah, pretty much
1814n/a k2 = v2 // this already is a comment ; continued
1815n/a k3 = v3;#//still v3# and still v3 ; a comment
1816n/a """)
1817n/a s = cfg['section']
1818n/a self.assertEqual(s['k1'], 'v1;still v1')
1819n/a self.assertEqual(s['k2'], 'v2')
1820n/a self.assertEqual(s['k3'], 'v3')
1821n/a self.assertEqual(s['k4'], 'v4;still v4')
1822n/a self.assertEqual(s['k5'], 'v5;still v5')
1823n/a self.assertEqual(s['k6'], 'v6;still v6; and still v6')
1824n/a self.assertEqual(s['k7'], 'v7;still v7; and still v7')
1825n/a s = cfg['multiprefix']
1826n/a self.assertEqual(s['k1'], 'v1;still v1')
1827n/a self.assertEqual(s['k2'], 'v2')
1828n/a self.assertEqual(s['k3'], 'v3;#//still v3# and still v3')
1829n/a
1830n/a
1831n/aclass ExceptionContextTestCase(unittest.TestCase):
1832n/a """ Test that implementation details doesn't leak
1833n/a through raising exceptions. """
1834n/a
1835n/a def test_get_basic_interpolation(self):
1836n/a parser = configparser.ConfigParser()
1837n/a parser.read_string("""
1838n/a [Paths]
1839n/a home_dir: /Users
1840n/a my_dir: %(home_dir1)s/lumberjack
1841n/a my_pictures: %(my_dir)s/Pictures
1842n/a """)
1843n/a cm = self.assertRaises(configparser.InterpolationMissingOptionError)
1844n/a with cm:
1845n/a parser.get('Paths', 'my_dir')
1846n/a self.assertIs(cm.exception.__suppress_context__, True)
1847n/a
1848n/a def test_get_extended_interpolation(self):
1849n/a parser = configparser.ConfigParser(
1850n/a interpolation=configparser.ExtendedInterpolation())
1851n/a parser.read_string("""
1852n/a [Paths]
1853n/a home_dir: /Users
1854n/a my_dir: ${home_dir1}/lumberjack
1855n/a my_pictures: ${my_dir}/Pictures
1856n/a """)
1857n/a cm = self.assertRaises(configparser.InterpolationMissingOptionError)
1858n/a with cm:
1859n/a parser.get('Paths', 'my_dir')
1860n/a self.assertIs(cm.exception.__suppress_context__, True)
1861n/a
1862n/a def test_missing_options(self):
1863n/a parser = configparser.ConfigParser()
1864n/a parser.read_string("""
1865n/a [Paths]
1866n/a home_dir: /Users
1867n/a """)
1868n/a with self.assertRaises(configparser.NoSectionError) as cm:
1869n/a parser.options('test')
1870n/a self.assertIs(cm.exception.__suppress_context__, True)
1871n/a
1872n/a def test_missing_section(self):
1873n/a config = configparser.ConfigParser()
1874n/a with self.assertRaises(configparser.NoSectionError) as cm:
1875n/a config.set('Section1', 'an_int', '15')
1876n/a self.assertIs(cm.exception.__suppress_context__, True)
1877n/a
1878n/a def test_remove_option(self):
1879n/a config = configparser.ConfigParser()
1880n/a with self.assertRaises(configparser.NoSectionError) as cm:
1881n/a config.remove_option('Section1', 'an_int')
1882n/a self.assertIs(cm.exception.__suppress_context__, True)
1883n/a
1884n/a
1885n/aclass ConvertersTestCase(BasicTestCase, unittest.TestCase):
1886n/a """Introduced in 3.5, issue #18159."""
1887n/a
1888n/a config_class = configparser.ConfigParser
1889n/a
1890n/a def newconfig(self, defaults=None):
1891n/a instance = super().newconfig(defaults=defaults)
1892n/a instance.converters['list'] = lambda v: [e.strip() for e in v.split()
1893n/a if e.strip()]
1894n/a return instance
1895n/a
1896n/a def test_converters(self):
1897n/a cfg = self.newconfig()
1898n/a self.assertIn('boolean', cfg.converters)
1899n/a self.assertIn('list', cfg.converters)
1900n/a self.assertIsNone(cfg.converters['int'])
1901n/a self.assertIsNone(cfg.converters['float'])
1902n/a self.assertIsNone(cfg.converters['boolean'])
1903n/a self.assertIsNotNone(cfg.converters['list'])
1904n/a self.assertEqual(len(cfg.converters), 4)
1905n/a with self.assertRaises(ValueError):
1906n/a cfg.converters[''] = lambda v: v
1907n/a with self.assertRaises(ValueError):
1908n/a cfg.converters[None] = lambda v: v
1909n/a cfg.read_string("""
1910n/a [s]
1911n/a str = string
1912n/a int = 1
1913n/a float = 0.5
1914n/a list = a b c d e f g
1915n/a bool = yes
1916n/a """)
1917n/a s = cfg['s']
1918n/a self.assertEqual(s['str'], 'string')
1919n/a self.assertEqual(s['int'], '1')
1920n/a self.assertEqual(s['float'], '0.5')
1921n/a self.assertEqual(s['list'], 'a b c d e f g')
1922n/a self.assertEqual(s['bool'], 'yes')
1923n/a self.assertEqual(cfg.get('s', 'str'), 'string')
1924n/a self.assertEqual(cfg.get('s', 'int'), '1')
1925n/a self.assertEqual(cfg.get('s', 'float'), '0.5')
1926n/a self.assertEqual(cfg.get('s', 'list'), 'a b c d e f g')
1927n/a self.assertEqual(cfg.get('s', 'bool'), 'yes')
1928n/a self.assertEqual(cfg.get('s', 'str'), 'string')
1929n/a self.assertEqual(cfg.getint('s', 'int'), 1)
1930n/a self.assertEqual(cfg.getfloat('s', 'float'), 0.5)
1931n/a self.assertEqual(cfg.getlist('s', 'list'), ['a', 'b', 'c', 'd',
1932n/a 'e', 'f', 'g'])
1933n/a self.assertEqual(cfg.getboolean('s', 'bool'), True)
1934n/a self.assertEqual(s.get('str'), 'string')
1935n/a self.assertEqual(s.getint('int'), 1)
1936n/a self.assertEqual(s.getfloat('float'), 0.5)
1937n/a self.assertEqual(s.getlist('list'), ['a', 'b', 'c', 'd',
1938n/a 'e', 'f', 'g'])
1939n/a self.assertEqual(s.getboolean('bool'), True)
1940n/a with self.assertRaises(AttributeError):
1941n/a cfg.getdecimal('s', 'float')
1942n/a with self.assertRaises(AttributeError):
1943n/a s.getdecimal('float')
1944n/a import decimal
1945n/a cfg.converters['decimal'] = decimal.Decimal
1946n/a self.assertIn('decimal', cfg.converters)
1947n/a self.assertIsNotNone(cfg.converters['decimal'])
1948n/a self.assertEqual(len(cfg.converters), 5)
1949n/a dec0_5 = decimal.Decimal('0.5')
1950n/a self.assertEqual(cfg.getdecimal('s', 'float'), dec0_5)
1951n/a self.assertEqual(s.getdecimal('float'), dec0_5)
1952n/a del cfg.converters['decimal']
1953n/a self.assertNotIn('decimal', cfg.converters)
1954n/a self.assertEqual(len(cfg.converters), 4)
1955n/a with self.assertRaises(AttributeError):
1956n/a cfg.getdecimal('s', 'float')
1957n/a with self.assertRaises(AttributeError):
1958n/a s.getdecimal('float')
1959n/a with self.assertRaises(KeyError):
1960n/a del cfg.converters['decimal']
1961n/a with self.assertRaises(KeyError):
1962n/a del cfg.converters['']
1963n/a with self.assertRaises(KeyError):
1964n/a del cfg.converters[None]
1965n/a
1966n/a
1967n/aclass BlatantOverrideConvertersTestCase(unittest.TestCase):
1968n/a """What if somebody overrode a getboolean()? We want to make sure that in
1969n/a this case the automatic converters do not kick in."""
1970n/a
1971n/a config = """
1972n/a [one]
1973n/a one = false
1974n/a two = false
1975n/a three = long story short
1976n/a
1977n/a [two]
1978n/a one = false
1979n/a two = false
1980n/a three = four
1981n/a """
1982n/a
1983n/a def test_converters_at_init(self):
1984n/a cfg = configparser.ConfigParser(converters={'len': len})
1985n/a cfg.read_string(self.config)
1986n/a self._test_len(cfg)
1987n/a self.assertIsNotNone(cfg.converters['len'])
1988n/a
1989n/a def test_inheritance(self):
1990n/a class StrangeConfigParser(configparser.ConfigParser):
1991n/a gettysburg = 'a historic borough in south central Pennsylvania'
1992n/a
1993n/a def getboolean(self, section, option, *, raw=False, vars=None,
1994n/a fallback=configparser._UNSET):
1995n/a if section == option:
1996n/a return True
1997n/a return super().getboolean(section, option, raw=raw, vars=vars,
1998n/a fallback=fallback)
1999n/a def getlen(self, section, option, *, raw=False, vars=None,
2000n/a fallback=configparser._UNSET):
2001n/a return self._get_conv(section, option, len, raw=raw, vars=vars,
2002n/a fallback=fallback)
2003n/a
2004n/a cfg = StrangeConfigParser()
2005n/a cfg.read_string(self.config)
2006n/a self._test_len(cfg)
2007n/a self.assertIsNone(cfg.converters['len'])
2008n/a self.assertTrue(cfg.getboolean('one', 'one'))
2009n/a self.assertTrue(cfg.getboolean('two', 'two'))
2010n/a self.assertFalse(cfg.getboolean('one', 'two'))
2011n/a self.assertFalse(cfg.getboolean('two', 'one'))
2012n/a cfg.converters['boolean'] = cfg._convert_to_boolean
2013n/a self.assertFalse(cfg.getboolean('one', 'one'))
2014n/a self.assertFalse(cfg.getboolean('two', 'two'))
2015n/a self.assertFalse(cfg.getboolean('one', 'two'))
2016n/a self.assertFalse(cfg.getboolean('two', 'one'))
2017n/a
2018n/a def _test_len(self, cfg):
2019n/a self.assertEqual(len(cfg.converters), 4)
2020n/a self.assertIn('boolean', cfg.converters)
2021n/a self.assertIn('len', cfg.converters)
2022n/a self.assertNotIn('tysburg', cfg.converters)
2023n/a self.assertIsNone(cfg.converters['int'])
2024n/a self.assertIsNone(cfg.converters['float'])
2025n/a self.assertIsNone(cfg.converters['boolean'])
2026n/a self.assertEqual(cfg.getlen('one', 'one'), 5)
2027n/a self.assertEqual(cfg.getlen('one', 'two'), 5)
2028n/a self.assertEqual(cfg.getlen('one', 'three'), 16)
2029n/a self.assertEqual(cfg.getlen('two', 'one'), 5)
2030n/a self.assertEqual(cfg.getlen('two', 'two'), 5)
2031n/a self.assertEqual(cfg.getlen('two', 'three'), 4)
2032n/a self.assertEqual(cfg.getlen('two', 'four', fallback=0), 0)
2033n/a with self.assertRaises(configparser.NoOptionError):
2034n/a cfg.getlen('two', 'four')
2035n/a self.assertEqual(cfg['one'].getlen('one'), 5)
2036n/a self.assertEqual(cfg['one'].getlen('two'), 5)
2037n/a self.assertEqual(cfg['one'].getlen('three'), 16)
2038n/a self.assertEqual(cfg['two'].getlen('one'), 5)
2039n/a self.assertEqual(cfg['two'].getlen('two'), 5)
2040n/a self.assertEqual(cfg['two'].getlen('three'), 4)
2041n/a self.assertEqual(cfg['two'].getlen('four', 0), 0)
2042n/a self.assertEqual(cfg['two'].getlen('four'), None)
2043n/a
2044n/a def test_instance_assignment(self):
2045n/a cfg = configparser.ConfigParser()
2046n/a cfg.getboolean = lambda section, option: True
2047n/a cfg.getlen = lambda section, option: len(cfg[section][option])
2048n/a cfg.read_string(self.config)
2049n/a self.assertEqual(len(cfg.converters), 3)
2050n/a self.assertIn('boolean', cfg.converters)
2051n/a self.assertNotIn('len', cfg.converters)
2052n/a self.assertIsNone(cfg.converters['int'])
2053n/a self.assertIsNone(cfg.converters['float'])
2054n/a self.assertIsNone(cfg.converters['boolean'])
2055n/a self.assertTrue(cfg.getboolean('one', 'one'))
2056n/a self.assertTrue(cfg.getboolean('two', 'two'))
2057n/a self.assertTrue(cfg.getboolean('one', 'two'))
2058n/a self.assertTrue(cfg.getboolean('two', 'one'))
2059n/a cfg.converters['boolean'] = cfg._convert_to_boolean
2060n/a self.assertFalse(cfg.getboolean('one', 'one'))
2061n/a self.assertFalse(cfg.getboolean('two', 'two'))
2062n/a self.assertFalse(cfg.getboolean('one', 'two'))
2063n/a self.assertFalse(cfg.getboolean('two', 'one'))
2064n/a self.assertEqual(cfg.getlen('one', 'one'), 5)
2065n/a self.assertEqual(cfg.getlen('one', 'two'), 5)
2066n/a self.assertEqual(cfg.getlen('one', 'three'), 16)
2067n/a self.assertEqual(cfg.getlen('two', 'one'), 5)
2068n/a self.assertEqual(cfg.getlen('two', 'two'), 5)
2069n/a self.assertEqual(cfg.getlen('two', 'three'), 4)
2070n/a # If a getter impl is assigned straight to the instance, it won't
2071n/a # be available on the section proxies.
2072n/a with self.assertRaises(AttributeError):
2073n/a self.assertEqual(cfg['one'].getlen('one'), 5)
2074n/a with self.assertRaises(AttributeError):
2075n/a self.assertEqual(cfg['two'].getlen('one'), 5)
2076n/a
2077n/a
2078n/aclass MiscTestCase(unittest.TestCase):
2079n/a def test__all__(self):
2080n/a blacklist = {"Error"}
2081n/a support.check__all__(self, configparser, blacklist=blacklist)
2082n/a
2083n/a
2084n/aif __name__ == '__main__':
2085n/a unittest.main()