https://github.com/python/cpython/commit/dbac03b411549c0f40fbb66127ae6f445027fcc8 commit: dbac03b411549c0f40fbb66127ae6f445027fcc8 branch: main author: Vincent Michel <[email protected]> committer: serhiy-storchaka <[email protected]> date: 2026-08-12T09:01:42Z summary:
gh-75245: Support line buffering in socket.makefile() (GH-12370) buffering=1 now enables line buffering in text mode, as in open() and as it worked in Python 2. In binary mode it emits a RuntimeWarning and uses the default buffer size, also as in open(). Co-authored-by: Serhiy Storchaka <[email protected]> files: A Misc/NEWS.d/next/Library/2021-09-09-10-15-54.gh-issue-75245.tLeTkn.rst M Lib/socket.py M Lib/test/test_socket.py diff --git a/Lib/socket.py b/Lib/socket.py index 2a4f875f76b069..21a852155abb3b 100644 --- a/Lib/socket.py +++ b/Lib/socket.py @@ -327,8 +327,18 @@ def makefile(self, mode="r", buffering=None, *, rawmode += "w" raw = SocketIO(self, rawmode) self._io_refs += 1 + line_buffering = False if buffering is None: buffering = -1 + if buffering == 1: + if binary: + import warnings + warnings.warn("line buffering (buffering=1) isn't supported " + "in binary mode, the default buffer size will " + "be used", RuntimeWarning, 2) + else: + line_buffering = True + buffering = -1 if buffering < 0: buffering = io.DEFAULT_BUFFER_SIZE if buffering == 0: @@ -345,7 +355,8 @@ def makefile(self, mode="r", buffering=None, *, if binary: return buffer encoding = io.text_encoding(encoding) - text = io.TextIOWrapper(buffer, encoding, errors, newline) + text = io.TextIOWrapper( + buffer, encoding, errors, newline, line_buffering) text.mode = mode return text diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py index 7bb50f7b8aa47e..e4b3d848923f8c 100644 --- a/Lib/test/test_socket.py +++ b/Lib/test/test_socket.py @@ -1969,6 +1969,25 @@ def test_makefile_mode(self): with sock.makefile(mode, encoding=encoding) as fp: self.assertEqual(fp.mode, mode) + def test_makefile_line_buffering(self): + with socket.socket() as sock: + for mode in 'r', 'w': + with self.subTest(mode=mode): + with sock.makefile(mode, buffering=1, + encoding="utf-8") as fp: + self.assertTrue(fp.line_buffering) + + def test_makefile_line_buffering_binary(self): + # Line buffering is not supported in binary mode, as in open(). + with socket.socket() as sock: + for mode in 'rb', 'wb': + with self.subTest(mode=mode): + with self.assertWarnsRegex( + RuntimeWarning, + "line buffering .* isn't supported in binary " + "mode"): + sock.makefile(mode, buffering=1).close() + def test_makefile_invalid_mode(self): for mode in 'rt', 'x', '+', 'a': with self.subTest(mode=mode): @@ -5761,10 +5780,20 @@ def testReadline(self): # Performing file readline test line = self.read_file.readline() self.assertEqual(line, self.read_msg) + # Readline mode + if self.bufsize == 1 and self.read_mode == "r": + self.assertTrue(self.read_file.line_buffering) def _testReadline(self): self.write_file.write(self.write_msg) - self.write_file.flush() + # Readline mode: no need to flush + if self.bufsize == 1 and self.write_mode == "w": + self.assertTrue(self.write_file.line_buffering) + else: + self.write_file.flush() + # Prevent garbage collection from flushing + # until the server has finished + self.assertTrue(self.serv_finished.wait(5.0)) def testCloseAfterMakefile(self): # The file returned by makefile should keep the socket open. @@ -5922,11 +5951,6 @@ def _testWriteNonBlocking(self): self.serv_skipped = "failed to saturate the socket buffer" -class LineBufferedFileObjectClassTestCase(FileObjectClassTestCase): - - bufsize = 1 # Default-buffered for reading; line-buffered for writing - - class SmallBufferedFileObjectClassTestCase(FileObjectClassTestCase): bufsize = 2 # Exercise the buffering code @@ -5962,6 +5986,16 @@ class UnicodeReadWriteFileObjectClassTestCase(FileObjectClassTestCase): newline = '' +class UnicodeLineBufferedFileObjectClassTestCase(FileObjectClassTestCase): + + bufsize = 1 # Default-buffered for reading; line-buffered for writing + read_mode = 'r' + read_msg = MSG.decode('utf-8') + write_mode = 'w' + write_msg = MSG.decode('utf-8') + newline = '' + + class NetworkConnectionTest(object): """Prove network connection.""" diff --git a/Misc/NEWS.d/next/Library/2021-09-09-10-15-54.gh-issue-75245.tLeTkn.rst b/Misc/NEWS.d/next/Library/2021-09-09-10-15-54.gh-issue-75245.tLeTkn.rst new file mode 100644 index 00000000000000..e690f4e2c14e3d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2021-09-09-10-15-54.gh-issue-75245.tLeTkn.rst @@ -0,0 +1,5 @@ +:meth:`socket.socket.makefile` now supports line buffering (``buffering=1``) +in text mode, as :func:`open` does and as it worked in Python 2. Previously +it silently used block buffering. In binary mode it now emits +a :exc:`RuntimeWarning` and uses the default buffer size, also as :func:`open` +does. _______________________________________________ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3//lists/python-checkins.python.org Member address: [email protected]
