Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ad9d48d

Browse files
committed
Merged revisions 62090-62091,62096,62100,62102,62110-62114 via svnmerge from
svn+ssh://[email protected]/python/trunk ........ r62090 | brett.cannon | 2008-04-01 07:37:43 -0500 (Tue, 01 Apr 2008) | 3 lines Generalize test.test_support.test_stdout() with a base context manager so that it is easy to capture stderr if desired. ........ r62091 | brett.cannon | 2008-04-01 07:46:02 -0500 (Tue, 01 Apr 2008) | 3 lines Add ``if __name__ == '__main__'`` to some test files where it didn't take a lot of effort to do so. ........ r62096 | amaury.forgeotdarc | 2008-04-01 17:52:48 -0500 (Tue, 01 Apr 2008) | 4 lines Newly enabled test appears to leak: it registers the same codec on each iteration. Do it only once at load time. ........ r62100 | amaury.forgeotdarc | 2008-04-01 19:55:04 -0500 (Tue, 01 Apr 2008) | 4 lines A DocTestSuite cannot run multiple times: it clears its globals dictionary after the first run. Rebuild the DocTestSuite on each iteration. ........ r62102 | jeffrey.yasskin | 2008-04-01 23:07:44 -0500 (Tue, 01 Apr 2008) | 3 lines Try to make test_signal less flaky. I still see some flakiness in test_itimer_prof. ........ r62110 | vinay.sajip | 2008-04-02 16:09:27 -0500 (Wed, 02 Apr 2008) | 1 line Fix: #2315, #2316, #2317: TimedRotatingFileHandler - changed logic to better handle daylight savings time, deletion of old log files, and fixed a bug in calculating rollover when no logging occurs for a longer interval than the rollover period. ........ r62111 | vinay.sajip | 2008-04-02 16:10:23 -0500 (Wed, 02 Apr 2008) | 1 line Added updates with respect to recent changes to TimedRotatingFileHandler. ........ r62112 | vinay.sajip | 2008-04-02 16:17:25 -0500 (Wed, 02 Apr 2008) | 1 line Added updates with respect to recent changes to TimedRotatingFileHandler. ........ r62113 | amaury.forgeotdarc | 2008-04-02 16:18:46 -0500 (Wed, 02 Apr 2008) | 2 lines Remove debug prints; the buildbot now passes the tests ........ r62114 | benjamin.peterson | 2008-04-02 16:20:35 -0500 (Wed, 02 Apr 2008) | 2 lines Suggested proposed changes to Python be considered on some mailing lists first ........
1 parent 84bea68 commit ad9d48d

11 files changed

Lines changed: 333 additions & 61 deletions

File tree

Doc/library/logging.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1649,10 +1649,11 @@ timed intervals.
16491649

16501650
The system will save old log files by appending extensions to the filename.
16511651
The extensions are date-and-time based, using the strftime format
1652-
``%Y-%m-%d_%H-%M-%S`` or a leading portion thereof, depending on the rollover
1653-
interval. If *backupCount* is nonzero, at most *backupCount* files will be
1654-
kept, and if more would be created when rollover occurs, the oldest one is
1655-
deleted.
1652+
``%Y-%m-%d_%H-%M-%S`` or a leading portion thereof, depending on the
1653+
rollover interval. If *backupCount* is nonzero, at most *backupCount* files
1654+
will be kept, and if more would be created when rollover occurs, the oldest
1655+
one is deleted. The deletion logic uses the interval to determine which
1656+
files to delete, so changing the interval may leave old files lying around.
16561657

16571658

16581659
.. method:: TimedRotatingFileHandler.doRollover()

Lib/logging/handlers.py

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
based on PEP 282 and comments thereto in comp.lang.python, and influenced by
2020
Apache's log4j system.
2121
22-
Copyright (C) 2001-2007 Vinay Sajip. All Rights Reserved.
22+
Copyright (C) 2001-2008 Vinay Sajip. All Rights Reserved.
2323
2424
To use, simply 'import logging' and log away!
2525
"""
2626

27-
import logging, socket, os, pickle, struct, time, glob
27+
import logging, socket, os, pickle, struct, time, re
2828
from stat import ST_DEV, ST_INO
2929

3030
try:
@@ -173,15 +173,19 @@ def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None,
173173
if self.when == 'S':
174174
self.interval = 1 # one second
175175
self.suffix = "%Y-%m-%d_%H-%M-%S"
176+
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}$"
176177
elif self.when == 'M':
177178
self.interval = 60 # one minute
178179
self.suffix = "%Y-%m-%d_%H-%M"
180+
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}$"
179181
elif self.when == 'H':
180182
self.interval = 60 * 60 # one hour
181183
self.suffix = "%Y-%m-%d_%H"
184+
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}$"
182185
elif self.when == 'D' or self.when == 'MIDNIGHT':
183186
self.interval = 60 * 60 * 24 # one day
184187
self.suffix = "%Y-%m-%d"
188+
self.extMatch = r"^\d{4}-\d{2}-\d{2}$"
185189
elif self.when.startswith('W'):
186190
self.interval = 60 * 60 * 24 * 7 # one week
187191
if len(self.when) != 2:
@@ -190,9 +194,11 @@ def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None,
190194
raise ValueError("Invalid day specified for weekly rollover: %s" % self.when)
191195
self.dayOfWeek = int(self.when[1])
192196
self.suffix = "%Y-%m-%d"
197+
self.extMatch = r"^\d{4}-\d{2}-\d{2}$"
193198
else:
194199
raise ValueError("Invalid rollover interval specified: %s" % self.when)
195200

201+
self.extMatch = re.compile(self.extMatch)
196202
self.interval = self.interval * interval # multiply by units requested
197203
self.rolloverAt = currentTime + self.interval
198204

@@ -235,23 +241,54 @@ def __init__(self, filename, when='h', interval=1, backupCount=0, encoding=None,
235241
daysToWait = self.dayOfWeek - day
236242
else:
237243
daysToWait = 6 - day + self.dayOfWeek + 1
238-
self.rolloverAt = self.rolloverAt + (daysToWait * (60 * 60 * 24))
244+
newRolloverAt = self.rolloverAt + (daysToWait * (60 * 60 * 24))
245+
dstNow = t[-1]
246+
dstAtRollover = time.localtime(newRolloverAt)[-1]
247+
if dstNow != dstAtRollover:
248+
if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour
249+
newRolloverAt = newRolloverAt - 3600
250+
else: # DST bows out before next rollover, so we need to add an hour
251+
newRolloverAt = newRolloverAt + 3600
252+
self.rolloverAt = newRolloverAt
239253

240254
#print "Will rollover at %d, %d seconds from now" % (self.rolloverAt, self.rolloverAt - currentTime)
241255

242256
def shouldRollover(self, record):
243257
"""
244-
Determine if rollover should occur
258+
Determine if rollover should occur.
245259
246260
record is not used, as we are just comparing times, but it is needed so
247-
the method siguratures are the same
261+
the method signatures are the same
248262
"""
249263
t = int(time.time())
250264
if t >= self.rolloverAt:
251265
return 1
252266
#print "No need to rollover: %d, %d" % (t, self.rolloverAt)
253267
return 0
254268

269+
def getFilesToDelete(self):
270+
"""
271+
Determine the files to delete when rolling over.
272+
273+
More specific than the earlier method, which just used glob.glob().
274+
"""
275+
dirName, baseName = os.path.split(self.baseFilename)
276+
fileNames = os.listdir(dirName)
277+
result = []
278+
prefix = baseName + "."
279+
plen = len(prefix)
280+
for fileName in fileNames:
281+
if fileName[:plen] == prefix:
282+
suffix = fileName[plen:]
283+
if self.extMatch.match(suffix):
284+
result.append(fileName)
285+
result.sort()
286+
if len(result) < self.backupCount:
287+
result = []
288+
else:
289+
result = result[:len(result) - self.backupCount]
290+
return result
291+
255292
def doRollover(self):
256293
"""
257294
do a rollover; in this case, a date/time stamp is appended to the filename
@@ -270,14 +307,29 @@ def doRollover(self):
270307
os.rename(self.baseFilename, dfn)
271308
if self.backupCount > 0:
272309
# find the oldest log file and delete it
273-
s = glob.glob(self.baseFilename + ".20*")
274-
if len(s) > self.backupCount:
275-
s.sort()
276-
os.remove(s[0])
310+
#s = glob.glob(self.baseFilename + ".20*")
311+
#if len(s) > self.backupCount:
312+
# s.sort()
313+
# os.remove(s[0])
314+
for s in self.getFilesToDelete():
315+
os.remove(s)
277316
#print "%s -> %s" % (self.baseFilename, dfn)
278317
self.mode = 'w'
279318
self.stream = self._open()
280-
self.rolloverAt = self.rolloverAt + self.interval
319+
newRolloverAt = self.rolloverAt + self.interval
320+
currentTime = int(time.time())
321+
while newRolloverAt <= currentTime:
322+
newRolloverAt = newRolloverAt + self.interval
323+
#If DST changes and midnight or weekly rollover, adjust for this.
324+
if self.when == 'MIDNIGHT' or self.when.startswith('W'):
325+
dstNow = time.localtime(currentTime)[-1]
326+
dstAtRollover = time.localtime(newRolloverAt)[-1]
327+
if dstNow != dstAtRollover:
328+
if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour
329+
newRolloverAt = newRolloverAt - 3600
330+
else: # DST bows out before next rollover, so we need to add an hour
331+
newRolloverAt = newRolloverAt + 3600
332+
self.rolloverAt = newRolloverAt
281333

282334
class WatchedFileHandler(logging.FileHandler):
283335
"""

Lib/test/test_code.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,7 @@ def test_main(verbose=None):
122122
from test.test_support import run_doctest
123123
from test import test_code
124124
run_doctest(test_code, verbose)
125+
126+
127+
if __name__ == '__main__':
128+
test_main()

Lib/test/test_collections.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,13 +317,12 @@ def test_MutableSequence(self):
317317
self.failIf(issubclass(str, MutableSequence))
318318

319319
import doctest, collections
320-
NamedTupleDocs = doctest.DocTestSuite(module=collections)
321320

322321
def test_main(verbose=None):
323-
import collections as CollectionsModule
322+
NamedTupleDocs = doctest.DocTestSuite(module=collections)
324323
test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs]
325324
test_support.run_unittest(*test_classes)
326-
test_support.run_doctest(CollectionsModule, verbose)
325+
test_support.run_doctest(collections, verbose)
327326

328327

329328
if __name__ == "__main__":

Lib/test/test_io.py

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,22 @@ def process_word(self):
574574
self.buffer = bytearray()
575575
return output
576576

577+
codecEnabled = False
578+
579+
@classmethod
580+
def lookupTestDecoder(cls, name):
581+
if cls.codecEnabled and name == 'test_decoder':
582+
return codecs.CodecInfo(
583+
name='test_decoder', encode=None, decode=None,
584+
incrementalencoder=None,
585+
streamreader=None, streamwriter=None,
586+
incrementaldecoder=cls)
587+
588+
# Register the previous decoder for testing.
589+
# Disabled by default, tests will enable it.
590+
codecs.register(StatefulIncrementalDecoder.lookupTestDecoder)
591+
592+
577593
class StatefulIncrementalDecoderTest(unittest.TestCase):
578594
"""
579595
Make sure the StatefulIncrementalDecoder actually works.
@@ -899,14 +915,6 @@ def testSeekingToo(self):
899915
def testSeekAndTell(self):
900916
"""Test seek/tell using the StatefulIncrementalDecoder."""
901917

902-
def lookupTestDecoder(name):
903-
if self.codecEnabled and name == 'test_decoder':
904-
return codecs.CodecInfo(
905-
name='test_decoder', encode=None, decode=None,
906-
incrementalencoder=None,
907-
streamreader=None, streamwriter=None,
908-
incrementaldecoder=StatefulIncrementalDecoder)
909-
910918
def testSeekAndTellWithData(data, min_pos=0):
911919
"""Tell/seek to various points within a data stream and ensure
912920
that the decoded data returned by read() is consistent."""
@@ -927,9 +935,8 @@ def testSeekAndTellWithData(data, min_pos=0):
927935
self.assertEquals(f.read(), decoded[i:])
928936
f.close()
929937

930-
# Register a special incremental decoder for testing.
931-
codecs.register(lookupTestDecoder)
932-
self.codecEnabled = 1
938+
# Enable the test decoder.
939+
StatefulIncrementalDecoder.codecEnabled = 1
933940

934941
# Run the tests.
935942
try:
@@ -948,7 +955,7 @@ def testSeekAndTellWithData(data, min_pos=0):
948955

949956
# Ensure our test decoder won't interfere with subsequent tests.
950957
finally:
951-
self.codecEnabled = 0
958+
StatefulIncrementalDecoder.codecEnabled = 0
952959

953960
def testEncodedWrites(self):
954961
data = "1234567890"

Lib/test/test_lib2to3.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,7 @@ def suite():
1313

1414
def test_main():
1515
run_unittest(suite())
16+
17+
18+
if __name__ == '__main__':
19+
test_main()

Lib/test/test_signal.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@ def exit_subprocess():
2828
os._exit(0)
2929

3030

31+
def ignoring_eintr(__func, *args, **kwargs):
32+
try:
33+
return __func(*args, **kwargs)
34+
except IOError as e:
35+
if e.errno != signal.EINTR:
36+
raise
37+
return None
38+
39+
3140
class InterProcessSignalTests(unittest.TestCase):
3241
MAX_DURATION = 20 # Entire test should last at most 20 sec.
3342

@@ -77,8 +86,11 @@ def run_test(self):
7786
if test_support.verbose:
7887
print("test runner's pid is", pid)
7988

80-
child = subprocess.Popen(['kill', '-HUP', str(pid)])
81-
self.wait(child)
89+
child = ignoring_eintr(subprocess.Popen, ['kill', '-HUP', str(pid)])
90+
if child:
91+
self.wait(child)
92+
if not self.a_called:
93+
time.sleep(1) # Give the signal time to be delivered.
8294
self.assertTrue(self.a_called)
8395
self.assertFalse(self.b_called)
8496
self.a_called = False
@@ -87,30 +99,36 @@ def run_test(self):
8799
child = subprocess.Popen(['kill', '-USR1', str(pid)])
88100
# This wait should be interrupted by the signal's exception.
89101
self.wait(child)
102+
time.sleep(1) # Give the signal time to be delivered.
90103
self.fail('HandlerBCalled exception not thrown')
91104
except HandlerBCalled:
92105
self.assertTrue(self.b_called)
93106
self.assertFalse(self.a_called)
94107
if test_support.verbose:
95108
print("HandlerBCalled exception caught")
96109

97-
child = subprocess.Popen(['kill', '-USR2', str(pid)])
98-
self.wait(child) # Nothing should happen.
110+
child = ignoring_eintr(subprocess.Popen, ['kill', '-USR2', str(pid)])
111+
if child:
112+
self.wait(child) # Nothing should happen.
99113

100114
try:
101115
signal.alarm(1)
102116
# The race condition in pause doesn't matter in this case,
103117
# since alarm is going to raise a KeyboardException, which
104118
# will skip the call.
105119
signal.pause()
120+
# But if another signal arrives before the alarm, pause
121+
# may return early.
122+
time.sleep(1)
106123
except KeyboardInterrupt:
107124
if test_support.verbose:
108125
print("KeyboardInterrupt (the alarm() went off)")
109126
except:
110-
self.fail('Some other exception woke us from pause: %s' %
127+
self.fail("Some other exception woke us from pause: %s" %
111128
traceback.format_exc())
112129
else:
113-
self.fail('pause returned of its own accord')
130+
self.fail("pause returned of its own accord, and the signal"
131+
" didn't arrive after another second.")
114132

115133
def test_main(self):
116134
# This function spawns a child process to insulate the main

Lib/test/test_socket.py

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,22 @@
1515
from weakref import proxy
1616
import signal
1717

18-
# Temporary hack to see why test_socket hangs on one buildbot
19-
if os.environ.get('COMPUTERNAME') == "GRAPE":
20-
def verbose_write(arg):
21-
print(arg, file=sys.__stdout__)
22-
else:
23-
def verbose_write(arg):
24-
pass
25-
2618
PORT = 50007
2719
HOST = 'localhost'
2820
MSG = b'Michael Gilfix was here\n'
2921

3022
class SocketTCPTest(unittest.TestCase):
3123

3224
def setUp(self):
33-
verbose_write(self)
3425
self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
3526
self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
36-
verbose_write(str(self) + " socket created")
3727
global PORT
3828
PORT = test_support.bind_port(self.serv, HOST, PORT)
39-
verbose_write(str(self) + " start listening")
4029
self.serv.listen(1)
41-
verbose_write(str(self) + " started")
4230

4331
def tearDown(self):
44-
verbose_write(str(self) + " close")
4532
self.serv.close()
4633
self.serv = None
47-
verbose_write(str(self) + " done")
4834

4935
class SocketUDPTest(unittest.TestCase):
5036

Lib/test/test_support.py

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -381,19 +381,23 @@ def transient_internet():
381381

382382

383383
@contextlib.contextmanager
384-
def captured_stdout():
385-
"""Run the with statement body using a StringIO object as sys.stdout.
386-
Example use::
384+
def captured_output(stream_name):
385+
"""Run the 'with' statement body using a StringIO object in place of a
386+
specific attribute on the sys module.
387+
Example use (with 'stream_name=stdout')::
387388
388389
with captured_stdout() as s:
389390
print "hello"
390391
assert s.getvalue() == "hello"
391392
"""
392393
import io
393-
orig_stdout = sys.stdout
394-
sys.stdout = io.StringIO()
395-
yield sys.stdout
396-
sys.stdout = orig_stdout
394+
orig_stdout = getattr(sys, stream_name)
395+
setattr(sys, stream_name, io.StringIO())
396+
yield getattr(sys, stream_name)
397+
setattr(sys, stream_name, orig_stdout)
398+
399+
def captured_stdout():
400+
return captured_output("stdout")
397401

398402

399403
#=======================================================================

0 commit comments

Comments
 (0)