diff -r 8a65e6aff672 Doc/library/configparser.rst --- a/Doc/library/configparser.rst Tue Apr 05 18:12:15 2011 +0200 +++ b/Doc/library/configparser.rst Tue Apr 05 22:43:11 2011 +0200 @@ -974,17 +974,25 @@ .. method:: read_file(f, source=None) - Read and parse configuration data from the file or file-like object in - *f* (only the :meth:`readline` method is used). The file-like object - must operate in text mode. Specifically, it must return strings from - :meth:`readline`. + Read and parse configuration data from any iterable object in *f*, as long + as it is returning one line at a time, as a Unicode string. This applies to + files. Optional argument *source* specifies the name of the file being read. If not given and *f* has a :attr:`name` attribute, that is used for *source*; the default is ``''``. .. versionadded:: 3.2 - Replaces :meth:`readfp`. + Replaces :meth:`readfp`. Prior to Python 3.2, :meth:`readfp` drew lines + from the file-like object using the :meth:`readline` method instead of + directly iterating over it. This type of legacy file-like objects can + be migrated by wrapping them with the following generator:: + + def readline_generator(f): + line = f.readline() + while line != '': + yield line + line = f.readline() .. method:: read_string(string, source='') diff -r 8a65e6aff672 Lib/configparser.py --- a/Lib/configparser.py Tue Apr 05 18:12:15 2011 +0200 +++ b/Lib/configparser.py Tue Apr 05 22:43:11 2011 +0200 @@ -694,10 +694,10 @@ def read_file(self, f, source=None): """Like read() but the argument must be a file-like object. - The `f' argument must have a `readline' method. Optional second - argument is the `source' specifying the name of the file being read. If - not given, it is taken from f.name. If `f' has no `name' attribute, - `' is used. + The `f' argument must be iterable, returning one line at a time. + Optional second argument is the `source' specifying the name of the + file being read. If not given, it is taken from f.name. If `f' has no + `name' attribute, `' is used. """ if source is None: try: diff -r 8a65e6aff672 Lib/test/test_cfgparser.py --- a/Lib/test/test_cfgparser.py Tue Apr 05 18:12:15 2011 +0200 +++ b/Lib/test/test_cfgparser.py Tue Apr 05 22:43:11 2011 +0200 @@ -1235,6 +1235,59 @@ del section[default] return cf_copy + +class FakeFile: + def __init__(self): + file_path = support.findfile("cfgparser.1") + with open(file_path) as f: + self.lines = f.readlines() + self.lines.reverse() + + def readline(self): + if len(self.lines): + return self.lines.pop() + return '' + + +def readline_generator(f): + """As advised in Doc/library/configparser.rst.""" + line = f.readline() + while line != '': + yield line + line = f.readline() + + +class ReadFileTestCase(unittest.TestCase): + def test_file(self): + file_path = support.findfile("cfgparser.1") + parser = configparser.ConfigParser() + with open(file_path) as f: + parser.read_file(f) + self.assertTrue("Foo Bar" in parser) + self.assertTrue("foo" in parser["Foo Bar"]) + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") + + def test_iterable(self): + lines = textwrap.dedent(""" + [Foo Bar] + foo=newbar""").strip().split('\n') + parser = configparser.ConfigParser() + parser.read_file(lines) + self.assertTrue("Foo Bar" in parser) + self.assertTrue("foo" in parser["Foo Bar"]) + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") + + def test_readline_generator(self): + """Issue #11670.""" + parser = configparser.ConfigParser() + with self.assertRaises(TypeError): + parser.read_file(FakeFile()) + parser.read_file(readline_generator(FakeFile())) + self.assertTrue("Foo Bar" in parser) + self.assertTrue("foo" in parser["Foo Bar"]) + self.assertEqual(parser["Foo Bar"]["foo"], "newbar") + + class CoverageOneHundredTestCase(unittest.TestCase): """Covers edge cases in the codebase.""" @@ -1338,5 +1391,6 @@ CompatibleTestCase, CopyTestCase, ConfigParserTestCaseNonStandardDefaultSection, + ReadFileTestCase, CoverageOneHundredTestCase, )

AltStyle によって変換されたページ (->オリジナル) /