Skip to content

Commit a9b2fde

Browse files
committed
Merge branch '3.14' of https://github.com/python/cpython into 3.14
2 parents fc91f0a + e152a82 commit a9b2fde

3 files changed

Lines changed: 73 additions & 1 deletion

File tree

‎Lib/logging/handlers.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,7 @@ def doRollover(self):
446446
timeTuple = time.localtime(t + addend)
447447
dfn = self.rotation_filename(self.baseFilename + "." +
448448
time.strftime(self.suffix, timeTuple))
449+
self.rolloverAt = self.computeRollover(currentTime)
449450
if os.path.exists(dfn):
450451
# Already rolled over.
451452
return
@@ -459,7 +460,6 @@ def doRollover(self):
459460
os.remove(s)
460461
if not self.delay:
461462
self.stream = self._open()
462-
self.rolloverAt = self.computeRollover(currentTime)
463463

464464
class WatchedFileHandler(logging.FileHandler):
465465
"""

‎Lib/test/test_logging.py‎

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6683,6 +6683,75 @@ def test_rollover_at_midnight(self, weekly=False):
66836683
def test_rollover_at_weekday(self):
66846684
self.test_rollover_at_midnight(weekly=True)
66856685

6686+
def _make_fake_time_handler(self, now, when='S', **kwargs):
6687+
dirname = tempfile.mkdtemp()
6688+
self.addCleanup(os_helper.rmtree, dirname)
6689+
fn = os.path.join(dirname, 'test.log')
6690+
with patch('time.time', lambda: now[0]):
6691+
fh = logging.handlers.TimedRotatingFileHandler(
6692+
fn, when=when, encoding='utf-8', delay=True, **kwargs)
6693+
self.addCleanup(fh.close)
6694+
return fh
6695+
6696+
def test_rollover_after_failed_rollover(self):
6697+
for target in 'os.remove', '_open':
6698+
with self.subTest(target=target):
6699+
now = [1_000_000_000]
6700+
fh = self._make_fake_time_handler(now, backupCount=1)
6701+
fn = fh.baseFilename
6702+
emit = lambda msg: fh.emit(logging.makeLogRecord({'msg': msg}))
6703+
with patch('time.time', lambda: now[0]):
6704+
for msg in 'a', 'b':
6705+
now[0] += 2
6706+
emit(msg)
6707+
now[0] += 2
6708+
if target == '_open':
6709+
failure = patch.object(fh, '_open', side_effect=OSError)
6710+
fh.delay = False
6711+
else:
6712+
failure = patch('os.remove', side_effect=OSError)
6713+
with failure as failed, support.captured_stderr():
6714+
emit('c')
6715+
failed.assert_called_once()
6716+
self.assertGreater(fh.rolloverAt, now[0])
6717+
fh.delay = True
6718+
for msg in 'd', 'e':
6719+
now[0] += 2
6720+
emit(msg)
6721+
fh.close()
6722+
with open(fn, encoding='utf-8') as f:
6723+
self.assertEqual(f.read(), 'e\n')
6724+
backups = [f for f in os.listdir(os.path.dirname(fn))
6725+
if f != 'test.log']
6726+
self.assertEqual(len(backups), 1)
6727+
6728+
def test_rollover_existing_backup(self):
6729+
now = [1_000_000_000]
6730+
fh = self._make_fake_time_handler(now)
6731+
fn = fh.baseFilename
6732+
with patch('time.time', lambda: now[0]):
6733+
fh.emit(logging.makeLogRecord({'msg': 'a'}))
6734+
t = fh.rolloverAt - fh.interval
6735+
dfn = fh.rotation_filename(
6736+
fn + '.' + time.strftime(fh.suffix, time.localtime(t)))
6737+
with open(dfn, 'w', encoding='utf-8') as f:
6738+
f.write('existing\n')
6739+
now[0] += 2
6740+
fh.emit(logging.makeLogRecord({'msg': 'b'}))
6741+
self.assertGreater(fh.rolloverAt, now[0])
6742+
t = fh.rolloverAt - fh.interval
6743+
next_dfn = fh.rotation_filename(
6744+
fn + '.' + time.strftime(fh.suffix, time.localtime(t)))
6745+
now[0] += 2
6746+
fh.emit(logging.makeLogRecord({'msg': 'c'}))
6747+
fh.close()
6748+
with open(dfn, encoding='utf-8') as f:
6749+
self.assertEqual(f.read(), 'existing\n')
6750+
with open(next_dfn, encoding='utf-8') as f:
6751+
self.assertEqual(f.read(), 'a\nb\n')
6752+
with open(fn, encoding='utf-8') as f:
6753+
self.assertEqual(f.read(), 'c\n')
6754+
66866755
def test_invalid(self):
66876756
assertRaises = self.assertRaises
66886757
assertRaises(ValueError, logging.handlers.TimedRotatingFileHandler,
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Fix :class:`logging.handlers.TimedRotatingFileHandler` permanently stopping
2+
rollover after a rollover failed or its backup file already existed, for
3+
example at a DST change.

0 commit comments

Comments
 (0)