From d8bf6653c5564768c2aa22aa5bfa7b6036e30f84 Mon Sep 17 00:00:00 2001 From: Seth Sims Date: Mon, 19 Oct 2020 08:16:22 -0400 Subject: [PATCH 1/2] bpo-41270: Making NamedTemporaryFile act as its own iterator to mimic normal file objects. NamedTemporaryFile returns a proxy object _TemporaryFileWrapper. However it does not proxy the __next__ method so the object cannot be used by for loops or by the next() builtin without calling iter() on it first. This changes that by explicity poxying the __next__ method. --- Lib/tempfile.py | 3 +++ Lib/test/test_tempfile.py | 13 +++++++++++++ Misc/ACKS | 1 + .../2020-07-10-14-33-52.bpo-41270.pjUqyd.rst | 1 + 4 files changed, 18 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2020-07-10-14-33-52.bpo-41270.pjUqyd.rst diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 770f72c25295cb..4d991623d80d59 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -499,6 +499,9 @@ def close(self): """ self._closer.close() + def __next__(self): + return next(self.file) + # iter() doesn't use __getattr__ to find the __iter__ method def __iter__(self): # Don't return iter(self.file), but yield from it to avoid closing diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 8ace883d74bb24..a3f44551195b33 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -886,6 +886,19 @@ def make_file(): self.assertEqual(l, lines[i]) self.assertEqual(i, len(lines) - 1) + def test_next(self): + lines = [b'spam\n', b'eggs\n', b'beans\n'] + with tempfile.NamedTemporaryFile(mode='w+b') as fd: + fd.write(b''.join(lines)) + fd.seek(0) + + for i, l in enumerate(lines): + self.assertEqual(l, next(fd)) + self.assertEqual(i, len(lines) - 1) + + with self.assertRaises(StopIteration): + next(fd) + def test_creates_named(self): # NamedTemporaryFile creates files with names f = tempfile.NamedTemporaryFile() diff --git a/Misc/ACKS b/Misc/ACKS index 7f4a9bcbc0f8cd..dd00da8eeedf88 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -1599,6 +1599,7 @@ Kirill Simonov Nathan Paul Simons Guilherme Simões Adam Simpkins +Seth Sims Karthikeyan Singaravelan Mandeep Singh Ravi Sinha diff --git a/Misc/NEWS.d/next/Library/2020-07-10-14-33-52.bpo-41270.pjUqyd.rst b/Misc/NEWS.d/next/Library/2020-07-10-14-33-52.bpo-41270.pjUqyd.rst new file mode 100644 index 00000000000000..897099bb4fbb64 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-07-10-14-33-52.bpo-41270.pjUqyd.rst @@ -0,0 +1 @@ +Added :func:`tempfile._TemporaryFileWrapper.__next__` so that the object returned by :func:`tempfile.NamedTemporaryFile` can be used to iterate over the contents of the file. From ece481137a834cfd053355753f50b7ff2291ab0a Mon Sep 17 00:00:00 2001 From: Seth Sims Date: Mon, 2 Nov 2020 09:19:47 -0500 Subject: [PATCH 2/2] Addressing comments to simplify test case. --- Lib/test/test_tempfile.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index a3f44551195b33..11d71c7b841876 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -892,10 +892,7 @@ def test_next(self): fd.write(b''.join(lines)) fd.seek(0) - for i, l in enumerate(lines): - self.assertEqual(l, next(fd)) - self.assertEqual(i, len(lines) - 1) - + self.assertEqual(list(fd), lines) with self.assertRaises(StopIteration): next(fd)