Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Doc/library/textwrap.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,10 @@ functions should be good enough; otherwise, you should use an instance of
print(repr(s)) # prints ' hello\n world\n '
print(repr(dedent(s))) # prints 'hello\n world\n'

.. versionchanged:: 3.14
The :func:`!dedent` function now correctly normalizes blank lines containing
only whitespace characters. Previously, the implementation only normalized
blank lines containing tabs and spaces.

.. function:: indent(text, prefix, predicate=None)

Expand Down
2 changes: 1 addition & 1 deletion Doc/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# won't suddenly cause build failures. Updating the version is fine as long
# as no warnings are raised by doing so.
# Keep this version in sync with ``Doc/conf.py``.
sphinx~=9.0.0
sphinx<9.0.0

blurb

Expand Down
9 changes: 9 additions & 0 deletions Doc/whatsnew/3.14.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2265,6 +2265,15 @@ pdb
(Contributed by Tian Gao in :gh:`124533`.)


textwrap
--------

* Optimize the :func:`~textwrap.dedent` function, improving performance by
an average of 2.4x, with larger improvements for bigger inputs,
and fix a bug with incomplete normalization of blank lines with whitespace
characters other than space and tab.


uuid
----

Expand Down
6 changes: 5 additions & 1 deletion Lib/logging/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,11 @@ def shouldRollover(self, record):
if self.stream is None: # delay was set...
self.stream = self._open()
if self.maxBytes > 0: # are we rolling over?
pos = self.stream.tell()
try:
pos = self.stream.tell()
except io.UnsupportedOperation:
# gh-143237: Never rollover a named pipe.
return False
if not pos:
# gh-116263: Never rollover an empty file
return False
Expand Down
27 changes: 27 additions & 0 deletions Lib/test/test_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import codecs
import configparser
import contextlib
import copy
import datetime
import pathlib
Expand Down Expand Up @@ -6369,6 +6370,32 @@ def test_should_not_rollover_non_file(self):
self.assertFalse(rh.shouldRollover(self.next_rec()))
rh.close()

@unittest.skipUnless(hasattr(os, "mkfifo"), 'requires os.mkfifo()')
def test_should_not_rollover_named_pipe(self):
# gh-143237 - test with non-seekable special file (named pipe)
filename = os_helper.TESTFN
self.addCleanup(os_helper.unlink, filename)
try:
os.mkfifo(filename)
except PermissionError as e:
self.skipTest('os.mkfifo(): %s' % e)

data = 'not read'
def other_side():
nonlocal data
with open(filename, 'rb') as f:
data = f.read()

thread = threading.Thread(target=other_side)
with threading_helper.start_threads([thread]):
rh = logging.handlers.RotatingFileHandler(
filename, encoding="utf-8", maxBytes=1)
with contextlib.closing(rh):
m = self.next_rec()
self.assertFalse(rh.shouldRollover(m))
rh.emit(m)
self.assertEqual(data.decode(), m.msg + os.linesep)

def test_should_rollover(self):
with open(self.fn, 'wb') as f:
f.write(b'\n')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix support of named pipes in the rotating :mod:`logging` handlers.
Loading