Skip to content

Commit df418fe

Browse files
committed
Merge branch '3.15' of https://github.com/python/cpython into 3.15
2 parents 8299d82 + 1c07fb7 commit df418fe

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
@@ -6737,6 +6737,75 @@ def test_rollover_at_midnight(self, weekly=False):
67376737
def test_rollover_at_weekday(self):
67386738
self.test_rollover_at_midnight(weekly=True)
67396739

6740+
def _make_fake_time_handler(self, now, when='S', **kwargs):
6741+
dirname = tempfile.mkdtemp()
6742+
self.addCleanup(os_helper.rmtree, dirname)
6743+
fn = os.path.join(dirname, 'test.log')
6744+
with patch('time.time', lambda: now[0]):
6745+
fh = logging.handlers.TimedRotatingFileHandler(
6746+
fn, when=when, encoding='utf-8', delay=True, **kwargs)
6747+
self.addCleanup(fh.close)
6748+
return fh
6749+
6750+
def test_rollover_after_failed_rollover(self):
6751+
for target in 'os.remove', '_open':
6752+
with self.subTest(target=target):
6753+
now = [1_000_000_000]
6754+
fh = self._make_fake_time_handler(now, backupCount=1)
6755+
fn = fh.baseFilename
6756+
emit = lambda msg: fh.emit(logging.makeLogRecord({'msg': msg}))
6757+
with patch('time.time', lambda: now[0]):
6758+
for msg in 'a', 'b':
6759+
now[0] += 2
6760+
emit(msg)
6761+
now[0] += 2
6762+
if target == '_open':
6763+
failure = patch.object(fh, '_open', side_effect=OSError)
6764+
fh.delay = False
6765+
else:
6766+
failure = patch('os.remove', side_effect=OSError)
6767+
with failure as failed, support.captured_stderr():
6768+
emit('c')
6769+
failed.assert_called_once()
6770+
self.assertGreater(fh.rolloverAt, now[0])
6771+
fh.delay = True
6772+
for msg in 'd', 'e':
6773+
now[0] += 2
6774+
emit(msg)
6775+
fh.close()
6776+
with open(fn, encoding='utf-8') as f:
6777+
self.assertEqual(f.read(), 'e\n')
6778+
backups = [f for f in os.listdir(os.path.dirname(fn))
6779+
if f != 'test.log']
6780+
self.assertEqual(len(backups), 1)
6781+
6782+
def test_rollover_existing_backup(self):
6783+
now = [1_000_000_000]
6784+
fh = self._make_fake_time_handler(now)
6785+
fn = fh.baseFilename
6786+
with patch('time.time', lambda: now[0]):
6787+
fh.emit(logging.makeLogRecord({'msg': 'a'}))
6788+
t = fh.rolloverAt - fh.interval
6789+
dfn = fh.rotation_filename(
6790+
fn + '.' + time.strftime(fh.suffix, time.localtime(t)))
6791+
with open(dfn, 'w', encoding='utf-8') as f:
6792+
f.write('existing\n')
6793+
now[0] += 2
6794+
fh.emit(logging.makeLogRecord({'msg': 'b'}))
6795+
self.assertGreater(fh.rolloverAt, now[0])
6796+
t = fh.rolloverAt - fh.interval
6797+
next_dfn = fh.rotation_filename(
6798+
fn + '.' + time.strftime(fh.suffix, time.localtime(t)))
6799+
now[0] += 2
6800+
fh.emit(logging.makeLogRecord({'msg': 'c'}))
6801+
fh.close()
6802+
with open(dfn, encoding='utf-8') as f:
6803+
self.assertEqual(f.read(), 'existing\n')
6804+
with open(next_dfn, encoding='utf-8') as f:
6805+
self.assertEqual(f.read(), 'a\nb\n')
6806+
with open(fn, encoding='utf-8') as f:
6807+
self.assertEqual(f.read(), 'c\n')
6808+
67406809
def test_invalid(self):
67416810
assertRaises = self.assertRaises
67426811
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)