mirror of https://github.com/python/cpython
Merged revisions 62090-62091,62096,62100,62102,62110-62114 via svnmerge from
svn+ssh://pythondev@svn.python.org/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 ........
This commit is contained in:
parent
84bea688c2
commit
ad9d48d865
|
@ -1649,10 +1649,11 @@ timed intervals.
|
||||||
|
|
||||||
The system will save old log files by appending extensions to the filename.
|
The system will save old log files by appending extensions to the filename.
|
||||||
The extensions are date-and-time based, using the strftime format
|
The extensions are date-and-time based, using the strftime format
|
||||||
``%Y-%m-%d_%H-%M-%S`` or a leading portion thereof, depending on the rollover
|
``%Y-%m-%d_%H-%M-%S`` or a leading portion thereof, depending on the
|
||||||
interval. If *backupCount* is nonzero, at most *backupCount* files will be
|
rollover interval. If *backupCount* is nonzero, at most *backupCount* files
|
||||||
kept, and if more would be created when rollover occurs, the oldest one is
|
will be kept, and if more would be created when rollover occurs, the oldest
|
||||||
deleted.
|
one is deleted. The deletion logic uses the interval to determine which
|
||||||
|
files to delete, so changing the interval may leave old files lying around.
|
||||||
|
|
||||||
|
|
||||||
.. method:: TimedRotatingFileHandler.doRollover()
|
.. method:: TimedRotatingFileHandler.doRollover()
|
||||||
|
|
|
@ -19,12 +19,12 @@ Additional handlers for the logging package for Python. The core package is
|
||||||
based on PEP 282 and comments thereto in comp.lang.python, and influenced by
|
based on PEP 282 and comments thereto in comp.lang.python, and influenced by
|
||||||
Apache's log4j system.
|
Apache's log4j system.
|
||||||
|
|
||||||
Copyright (C) 2001-2007 Vinay Sajip. All Rights Reserved.
|
Copyright (C) 2001-2008 Vinay Sajip. All Rights Reserved.
|
||||||
|
|
||||||
To use, simply 'import logging' and log away!
|
To use, simply 'import logging' and log away!
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import logging, socket, os, pickle, struct, time, glob
|
import logging, socket, os, pickle, struct, time, re
|
||||||
from stat import ST_DEV, ST_INO
|
from stat import ST_DEV, ST_INO
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -173,15 +173,19 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
|
||||||
if self.when == 'S':
|
if self.when == 'S':
|
||||||
self.interval = 1 # one second
|
self.interval = 1 # one second
|
||||||
self.suffix = "%Y-%m-%d_%H-%M-%S"
|
self.suffix = "%Y-%m-%d_%H-%M-%S"
|
||||||
|
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}$"
|
||||||
elif self.when == 'M':
|
elif self.when == 'M':
|
||||||
self.interval = 60 # one minute
|
self.interval = 60 # one minute
|
||||||
self.suffix = "%Y-%m-%d_%H-%M"
|
self.suffix = "%Y-%m-%d_%H-%M"
|
||||||
|
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}$"
|
||||||
elif self.when == 'H':
|
elif self.when == 'H':
|
||||||
self.interval = 60 * 60 # one hour
|
self.interval = 60 * 60 # one hour
|
||||||
self.suffix = "%Y-%m-%d_%H"
|
self.suffix = "%Y-%m-%d_%H"
|
||||||
|
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}$"
|
||||||
elif self.when == 'D' or self.when == 'MIDNIGHT':
|
elif self.when == 'D' or self.when == 'MIDNIGHT':
|
||||||
self.interval = 60 * 60 * 24 # one day
|
self.interval = 60 * 60 * 24 # one day
|
||||||
self.suffix = "%Y-%m-%d"
|
self.suffix = "%Y-%m-%d"
|
||||||
|
self.extMatch = r"^\d{4}-\d{2}-\d{2}$"
|
||||||
elif self.when.startswith('W'):
|
elif self.when.startswith('W'):
|
||||||
self.interval = 60 * 60 * 24 * 7 # one week
|
self.interval = 60 * 60 * 24 * 7 # one week
|
||||||
if len(self.when) != 2:
|
if len(self.when) != 2:
|
||||||
|
@ -190,9 +194,11 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
|
||||||
raise ValueError("Invalid day specified for weekly rollover: %s" % self.when)
|
raise ValueError("Invalid day specified for weekly rollover: %s" % self.when)
|
||||||
self.dayOfWeek = int(self.when[1])
|
self.dayOfWeek = int(self.when[1])
|
||||||
self.suffix = "%Y-%m-%d"
|
self.suffix = "%Y-%m-%d"
|
||||||
|
self.extMatch = r"^\d{4}-\d{2}-\d{2}$"
|
||||||
else:
|
else:
|
||||||
raise ValueError("Invalid rollover interval specified: %s" % self.when)
|
raise ValueError("Invalid rollover interval specified: %s" % self.when)
|
||||||
|
|
||||||
|
self.extMatch = re.compile(self.extMatch)
|
||||||
self.interval = self.interval * interval # multiply by units requested
|
self.interval = self.interval * interval # multiply by units requested
|
||||||
self.rolloverAt = currentTime + self.interval
|
self.rolloverAt = currentTime + self.interval
|
||||||
|
|
||||||
|
@ -235,16 +241,24 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
|
||||||
daysToWait = self.dayOfWeek - day
|
daysToWait = self.dayOfWeek - day
|
||||||
else:
|
else:
|
||||||
daysToWait = 6 - day + self.dayOfWeek + 1
|
daysToWait = 6 - day + self.dayOfWeek + 1
|
||||||
self.rolloverAt = self.rolloverAt + (daysToWait * (60 * 60 * 24))
|
newRolloverAt = self.rolloverAt + (daysToWait * (60 * 60 * 24))
|
||||||
|
dstNow = t[-1]
|
||||||
|
dstAtRollover = time.localtime(newRolloverAt)[-1]
|
||||||
|
if dstNow != dstAtRollover:
|
||||||
|
if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour
|
||||||
|
newRolloverAt = newRolloverAt - 3600
|
||||||
|
else: # DST bows out before next rollover, so we need to add an hour
|
||||||
|
newRolloverAt = newRolloverAt + 3600
|
||||||
|
self.rolloverAt = newRolloverAt
|
||||||
|
|
||||||
#print "Will rollover at %d, %d seconds from now" % (self.rolloverAt, self.rolloverAt - currentTime)
|
#print "Will rollover at %d, %d seconds from now" % (self.rolloverAt, self.rolloverAt - currentTime)
|
||||||
|
|
||||||
def shouldRollover(self, record):
|
def shouldRollover(self, record):
|
||||||
"""
|
"""
|
||||||
Determine if rollover should occur
|
Determine if rollover should occur.
|
||||||
|
|
||||||
record is not used, as we are just comparing times, but it is needed so
|
record is not used, as we are just comparing times, but it is needed so
|
||||||
the method siguratures are the same
|
the method signatures are the same
|
||||||
"""
|
"""
|
||||||
t = int(time.time())
|
t = int(time.time())
|
||||||
if t >= self.rolloverAt:
|
if t >= self.rolloverAt:
|
||||||
|
@ -252,6 +266,29 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
|
||||||
#print "No need to rollover: %d, %d" % (t, self.rolloverAt)
|
#print "No need to rollover: %d, %d" % (t, self.rolloverAt)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def getFilesToDelete(self):
|
||||||
|
"""
|
||||||
|
Determine the files to delete when rolling over.
|
||||||
|
|
||||||
|
More specific than the earlier method, which just used glob.glob().
|
||||||
|
"""
|
||||||
|
dirName, baseName = os.path.split(self.baseFilename)
|
||||||
|
fileNames = os.listdir(dirName)
|
||||||
|
result = []
|
||||||
|
prefix = baseName + "."
|
||||||
|
plen = len(prefix)
|
||||||
|
for fileName in fileNames:
|
||||||
|
if fileName[:plen] == prefix:
|
||||||
|
suffix = fileName[plen:]
|
||||||
|
if self.extMatch.match(suffix):
|
||||||
|
result.append(fileName)
|
||||||
|
result.sort()
|
||||||
|
if len(result) < self.backupCount:
|
||||||
|
result = []
|
||||||
|
else:
|
||||||
|
result = result[:len(result) - self.backupCount]
|
||||||
|
return result
|
||||||
|
|
||||||
def doRollover(self):
|
def doRollover(self):
|
||||||
"""
|
"""
|
||||||
do a rollover; in this case, a date/time stamp is appended to the filename
|
do a rollover; in this case, a date/time stamp is appended to the filename
|
||||||
|
@ -270,14 +307,29 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
|
||||||
os.rename(self.baseFilename, dfn)
|
os.rename(self.baseFilename, dfn)
|
||||||
if self.backupCount > 0:
|
if self.backupCount > 0:
|
||||||
# find the oldest log file and delete it
|
# find the oldest log file and delete it
|
||||||
s = glob.glob(self.baseFilename + ".20*")
|
#s = glob.glob(self.baseFilename + ".20*")
|
||||||
if len(s) > self.backupCount:
|
#if len(s) > self.backupCount:
|
||||||
s.sort()
|
# s.sort()
|
||||||
os.remove(s[0])
|
# os.remove(s[0])
|
||||||
|
for s in self.getFilesToDelete():
|
||||||
|
os.remove(s)
|
||||||
#print "%s -> %s" % (self.baseFilename, dfn)
|
#print "%s -> %s" % (self.baseFilename, dfn)
|
||||||
self.mode = 'w'
|
self.mode = 'w'
|
||||||
self.stream = self._open()
|
self.stream = self._open()
|
||||||
self.rolloverAt = self.rolloverAt + self.interval
|
newRolloverAt = self.rolloverAt + self.interval
|
||||||
|
currentTime = int(time.time())
|
||||||
|
while newRolloverAt <= currentTime:
|
||||||
|
newRolloverAt = newRolloverAt + self.interval
|
||||||
|
#If DST changes and midnight or weekly rollover, adjust for this.
|
||||||
|
if self.when == 'MIDNIGHT' or self.when.startswith('W'):
|
||||||
|
dstNow = time.localtime(currentTime)[-1]
|
||||||
|
dstAtRollover = time.localtime(newRolloverAt)[-1]
|
||||||
|
if dstNow != dstAtRollover:
|
||||||
|
if not dstNow: # DST kicks in before next rollover, so we need to deduct an hour
|
||||||
|
newRolloverAt = newRolloverAt - 3600
|
||||||
|
else: # DST bows out before next rollover, so we need to add an hour
|
||||||
|
newRolloverAt = newRolloverAt + 3600
|
||||||
|
self.rolloverAt = newRolloverAt
|
||||||
|
|
||||||
class WatchedFileHandler(logging.FileHandler):
|
class WatchedFileHandler(logging.FileHandler):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -122,3 +122,7 @@ def test_main(verbose=None):
|
||||||
from test.test_support import run_doctest
|
from test.test_support import run_doctest
|
||||||
from test import test_code
|
from test import test_code
|
||||||
run_doctest(test_code, verbose)
|
run_doctest(test_code, verbose)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_main()
|
||||||
|
|
|
@ -317,13 +317,12 @@ class TestCollectionABCs(unittest.TestCase):
|
||||||
self.failIf(issubclass(str, MutableSequence))
|
self.failIf(issubclass(str, MutableSequence))
|
||||||
|
|
||||||
import doctest, collections
|
import doctest, collections
|
||||||
NamedTupleDocs = doctest.DocTestSuite(module=collections)
|
|
||||||
|
|
||||||
def test_main(verbose=None):
|
def test_main(verbose=None):
|
||||||
import collections as CollectionsModule
|
NamedTupleDocs = doctest.DocTestSuite(module=collections)
|
||||||
test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs]
|
test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs]
|
||||||
test_support.run_unittest(*test_classes)
|
test_support.run_unittest(*test_classes)
|
||||||
test_support.run_doctest(CollectionsModule, verbose)
|
test_support.run_doctest(collections, verbose)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -574,6 +574,22 @@ class StatefulIncrementalDecoder(codecs.IncrementalDecoder):
|
||||||
self.buffer = bytearray()
|
self.buffer = bytearray()
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
codecEnabled = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def lookupTestDecoder(cls, name):
|
||||||
|
if cls.codecEnabled and name == 'test_decoder':
|
||||||
|
return codecs.CodecInfo(
|
||||||
|
name='test_decoder', encode=None, decode=None,
|
||||||
|
incrementalencoder=None,
|
||||||
|
streamreader=None, streamwriter=None,
|
||||||
|
incrementaldecoder=cls)
|
||||||
|
|
||||||
|
# Register the previous decoder for testing.
|
||||||
|
# Disabled by default, tests will enable it.
|
||||||
|
codecs.register(StatefulIncrementalDecoder.lookupTestDecoder)
|
||||||
|
|
||||||
|
|
||||||
class StatefulIncrementalDecoderTest(unittest.TestCase):
|
class StatefulIncrementalDecoderTest(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
Make sure the StatefulIncrementalDecoder actually works.
|
Make sure the StatefulIncrementalDecoder actually works.
|
||||||
|
@ -899,14 +915,6 @@ class TextIOWrapperTest(unittest.TestCase):
|
||||||
def testSeekAndTell(self):
|
def testSeekAndTell(self):
|
||||||
"""Test seek/tell using the StatefulIncrementalDecoder."""
|
"""Test seek/tell using the StatefulIncrementalDecoder."""
|
||||||
|
|
||||||
def lookupTestDecoder(name):
|
|
||||||
if self.codecEnabled and name == 'test_decoder':
|
|
||||||
return codecs.CodecInfo(
|
|
||||||
name='test_decoder', encode=None, decode=None,
|
|
||||||
incrementalencoder=None,
|
|
||||||
streamreader=None, streamwriter=None,
|
|
||||||
incrementaldecoder=StatefulIncrementalDecoder)
|
|
||||||
|
|
||||||
def testSeekAndTellWithData(data, min_pos=0):
|
def testSeekAndTellWithData(data, min_pos=0):
|
||||||
"""Tell/seek to various points within a data stream and ensure
|
"""Tell/seek to various points within a data stream and ensure
|
||||||
that the decoded data returned by read() is consistent."""
|
that the decoded data returned by read() is consistent."""
|
||||||
|
@ -927,9 +935,8 @@ class TextIOWrapperTest(unittest.TestCase):
|
||||||
self.assertEquals(f.read(), decoded[i:])
|
self.assertEquals(f.read(), decoded[i:])
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
# Register a special incremental decoder for testing.
|
# Enable the test decoder.
|
||||||
codecs.register(lookupTestDecoder)
|
StatefulIncrementalDecoder.codecEnabled = 1
|
||||||
self.codecEnabled = 1
|
|
||||||
|
|
||||||
# Run the tests.
|
# Run the tests.
|
||||||
try:
|
try:
|
||||||
|
@ -948,7 +955,7 @@ class TextIOWrapperTest(unittest.TestCase):
|
||||||
|
|
||||||
# Ensure our test decoder won't interfere with subsequent tests.
|
# Ensure our test decoder won't interfere with subsequent tests.
|
||||||
finally:
|
finally:
|
||||||
self.codecEnabled = 0
|
StatefulIncrementalDecoder.codecEnabled = 0
|
||||||
|
|
||||||
def testEncodedWrites(self):
|
def testEncodedWrites(self):
|
||||||
data = "1234567890"
|
data = "1234567890"
|
||||||
|
|
|
@ -13,3 +13,7 @@ def suite():
|
||||||
|
|
||||||
def test_main():
|
def test_main():
|
||||||
run_unittest(suite())
|
run_unittest(suite())
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test_main()
|
||||||
|
|
|
@ -28,6 +28,15 @@ def exit_subprocess():
|
||||||
os._exit(0)
|
os._exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
def ignoring_eintr(__func, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
return __func(*args, **kwargs)
|
||||||
|
except IOError as e:
|
||||||
|
if e.errno != signal.EINTR:
|
||||||
|
raise
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class InterProcessSignalTests(unittest.TestCase):
|
class InterProcessSignalTests(unittest.TestCase):
|
||||||
MAX_DURATION = 20 # Entire test should last at most 20 sec.
|
MAX_DURATION = 20 # Entire test should last at most 20 sec.
|
||||||
|
|
||||||
|
@ -77,8 +86,11 @@ class InterProcessSignalTests(unittest.TestCase):
|
||||||
if test_support.verbose:
|
if test_support.verbose:
|
||||||
print("test runner's pid is", pid)
|
print("test runner's pid is", pid)
|
||||||
|
|
||||||
child = subprocess.Popen(['kill', '-HUP', str(pid)])
|
child = ignoring_eintr(subprocess.Popen, ['kill', '-HUP', str(pid)])
|
||||||
self.wait(child)
|
if child:
|
||||||
|
self.wait(child)
|
||||||
|
if not self.a_called:
|
||||||
|
time.sleep(1) # Give the signal time to be delivered.
|
||||||
self.assertTrue(self.a_called)
|
self.assertTrue(self.a_called)
|
||||||
self.assertFalse(self.b_called)
|
self.assertFalse(self.b_called)
|
||||||
self.a_called = False
|
self.a_called = False
|
||||||
|
@ -87,6 +99,7 @@ class InterProcessSignalTests(unittest.TestCase):
|
||||||
child = subprocess.Popen(['kill', '-USR1', str(pid)])
|
child = subprocess.Popen(['kill', '-USR1', str(pid)])
|
||||||
# This wait should be interrupted by the signal's exception.
|
# This wait should be interrupted by the signal's exception.
|
||||||
self.wait(child)
|
self.wait(child)
|
||||||
|
time.sleep(1) # Give the signal time to be delivered.
|
||||||
self.fail('HandlerBCalled exception not thrown')
|
self.fail('HandlerBCalled exception not thrown')
|
||||||
except HandlerBCalled:
|
except HandlerBCalled:
|
||||||
self.assertTrue(self.b_called)
|
self.assertTrue(self.b_called)
|
||||||
|
@ -94,8 +107,9 @@ class InterProcessSignalTests(unittest.TestCase):
|
||||||
if test_support.verbose:
|
if test_support.verbose:
|
||||||
print("HandlerBCalled exception caught")
|
print("HandlerBCalled exception caught")
|
||||||
|
|
||||||
child = subprocess.Popen(['kill', '-USR2', str(pid)])
|
child = ignoring_eintr(subprocess.Popen, ['kill', '-USR2', str(pid)])
|
||||||
self.wait(child) # Nothing should happen.
|
if child:
|
||||||
|
self.wait(child) # Nothing should happen.
|
||||||
|
|
||||||
try:
|
try:
|
||||||
signal.alarm(1)
|
signal.alarm(1)
|
||||||
|
@ -103,14 +117,18 @@ class InterProcessSignalTests(unittest.TestCase):
|
||||||
# since alarm is going to raise a KeyboardException, which
|
# since alarm is going to raise a KeyboardException, which
|
||||||
# will skip the call.
|
# will skip the call.
|
||||||
signal.pause()
|
signal.pause()
|
||||||
|
# But if another signal arrives before the alarm, pause
|
||||||
|
# may return early.
|
||||||
|
time.sleep(1)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
if test_support.verbose:
|
if test_support.verbose:
|
||||||
print("KeyboardInterrupt (the alarm() went off)")
|
print("KeyboardInterrupt (the alarm() went off)")
|
||||||
except:
|
except:
|
||||||
self.fail('Some other exception woke us from pause: %s' %
|
self.fail("Some other exception woke us from pause: %s" %
|
||||||
traceback.format_exc())
|
traceback.format_exc())
|
||||||
else:
|
else:
|
||||||
self.fail('pause returned of its own accord')
|
self.fail("pause returned of its own accord, and the signal"
|
||||||
|
" didn't arrive after another second.")
|
||||||
|
|
||||||
def test_main(self):
|
def test_main(self):
|
||||||
# This function spawns a child process to insulate the main
|
# This function spawns a child process to insulate the main
|
||||||
|
|
|
@ -15,14 +15,6 @@ import array
|
||||||
from weakref import proxy
|
from weakref import proxy
|
||||||
import signal
|
import signal
|
||||||
|
|
||||||
# Temporary hack to see why test_socket hangs on one buildbot
|
|
||||||
if os.environ.get('COMPUTERNAME') == "GRAPE":
|
|
||||||
def verbose_write(arg):
|
|
||||||
print(arg, file=sys.__stdout__)
|
|
||||||
else:
|
|
||||||
def verbose_write(arg):
|
|
||||||
pass
|
|
||||||
|
|
||||||
PORT = 50007
|
PORT = 50007
|
||||||
HOST = 'localhost'
|
HOST = 'localhost'
|
||||||
MSG = b'Michael Gilfix was here\n'
|
MSG = b'Michael Gilfix was here\n'
|
||||||
|
@ -30,21 +22,15 @@ MSG = b'Michael Gilfix was here\n'
|
||||||
class SocketTCPTest(unittest.TestCase):
|
class SocketTCPTest(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
verbose_write(self)
|
|
||||||
self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||||
self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||||
verbose_write(str(self) + " socket created")
|
|
||||||
global PORT
|
global PORT
|
||||||
PORT = test_support.bind_port(self.serv, HOST, PORT)
|
PORT = test_support.bind_port(self.serv, HOST, PORT)
|
||||||
verbose_write(str(self) + " start listening")
|
|
||||||
self.serv.listen(1)
|
self.serv.listen(1)
|
||||||
verbose_write(str(self) + " started")
|
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
verbose_write(str(self) + " close")
|
|
||||||
self.serv.close()
|
self.serv.close()
|
||||||
self.serv = None
|
self.serv = None
|
||||||
verbose_write(str(self) + " done")
|
|
||||||
|
|
||||||
class SocketUDPTest(unittest.TestCase):
|
class SocketUDPTest(unittest.TestCase):
|
||||||
|
|
||||||
|
|
|
@ -381,19 +381,23 @@ def transient_internet():
|
||||||
|
|
||||||
|
|
||||||
@contextlib.contextmanager
|
@contextlib.contextmanager
|
||||||
def captured_stdout():
|
def captured_output(stream_name):
|
||||||
"""Run the with statement body using a StringIO object as sys.stdout.
|
"""Run the 'with' statement body using a StringIO object in place of a
|
||||||
Example use::
|
specific attribute on the sys module.
|
||||||
|
Example use (with 'stream_name=stdout')::
|
||||||
|
|
||||||
with captured_stdout() as s:
|
with captured_stdout() as s:
|
||||||
print "hello"
|
print "hello"
|
||||||
assert s.getvalue() == "hello"
|
assert s.getvalue() == "hello"
|
||||||
"""
|
"""
|
||||||
import io
|
import io
|
||||||
orig_stdout = sys.stdout
|
orig_stdout = getattr(sys, stream_name)
|
||||||
sys.stdout = io.StringIO()
|
setattr(sys, stream_name, io.StringIO())
|
||||||
yield sys.stdout
|
yield getattr(sys, stream_name)
|
||||||
sys.stdout = orig_stdout
|
setattr(sys, stream_name, orig_stdout)
|
||||||
|
|
||||||
|
def captured_stdout():
|
||||||
|
return captured_output("stdout")
|
||||||
|
|
||||||
|
|
||||||
#=======================================================================
|
#=======================================================================
|
||||||
|
|
195
Misc/NEWS
195
Misc/NEWS
|
@ -29,6 +29,19 @@ Library
|
||||||
as a build_py replacement to automatically run 2to3 on modules
|
as a build_py replacement to automatically run 2to3 on modules
|
||||||
that are going to be installed.
|
that are going to be installed.
|
||||||
|
|
||||||
|
- Issue #2315: logging.handlers: TimedRotatingFileHandler now accounts for
|
||||||
|
daylight savings time in calculating the next rollover.
|
||||||
|
|
||||||
|
- Issue #2316: logging.handlers: TimedRotatingFileHandler now calculates
|
||||||
|
rollovers correctly even when nothing is logged for a while.
|
||||||
|
|
||||||
|
- Issue #2317: logging.handlers: TimedRotatingFileHandler now uses improved
|
||||||
|
logic for removing old files.
|
||||||
|
|
||||||
|
- Issue #2495: tokenize.untokenize now inserts a space between two consecutive
|
||||||
|
string literals; previously, ["" ""] was rendered as [""""], which is
|
||||||
|
incorrect python code.
|
||||||
|
|
||||||
- A new pickle protocol (protocol 3) is added with explicit support
|
- A new pickle protocol (protocol 3) is added with explicit support
|
||||||
for bytes. This is the default protocol. It intentionally cannot
|
for bytes. This is the default protocol. It intentionally cannot
|
||||||
be unpickled by Python 2.x.
|
be unpickled by Python 2.x.
|
||||||
|
@ -57,6 +70,115 @@ Library
|
||||||
What's New in Python 3.0a3?
|
What's New in Python 3.0a3?
|
||||||
===========================
|
===========================
|
||||||
|
|
||||||
|
- Issue #1681432: Add triangular distribution to the random module
|
||||||
|
|
||||||
|
- Issue #2136: urllib2's auth handler now allows single-quoted realms in the
|
||||||
|
WWW-Authenticate header.
|
||||||
|
|
||||||
|
- Issue #2434: Enhanced platform.win32_ver() to also work on Python
|
||||||
|
installation which do not have the win32all package installed.
|
||||||
|
|
||||||
|
- Added support to platform.uname() to also report the machine
|
||||||
|
and processor information on Windows XP and later. As a result,
|
||||||
|
platform.machine() and platform.processor() will report this
|
||||||
|
information as well.
|
||||||
|
|
||||||
|
- The library implementing the 2to3 conversion, lib2to3, was added
|
||||||
|
to the standard distribution.
|
||||||
|
|
||||||
|
- Issue #1747858: Fix chown to work with large uid's and gid's on 64-bit
|
||||||
|
platforms.
|
||||||
|
|
||||||
|
- Issue #1202: zlib.crc32 and zlib.adler32 no longer return different values
|
||||||
|
on 32-bit vs. 64-bit python interpreters. Both were correct, but they now
|
||||||
|
both return a signed integer object for consistency.
|
||||||
|
|
||||||
|
- Issue #1158: add %f format (fractions of a second represented as
|
||||||
|
microseconds) to datetime objects. Understood by both strptime and
|
||||||
|
strftime.
|
||||||
|
|
||||||
|
- Issue #705836: struct.pack(">f", x) now raises OverflowError on all
|
||||||
|
platforms when x is too large to fit into an IEEE 754 float; previously
|
||||||
|
it only raised OverflowError on non IEEE 754 platforms.
|
||||||
|
|
||||||
|
- Issue #1106316: pdb.post_mortem()'s parameter, "traceback", is now
|
||||||
|
optional: it defaults to the traceback of the exception that is currently
|
||||||
|
being handled (is mandatory to be in the middle of an exception, otherwise
|
||||||
|
it raises ValueError).
|
||||||
|
|
||||||
|
- Issue #1193577: A .shutdown() method has been added to SocketServers
|
||||||
|
which terminates the .serve_forever() loop.
|
||||||
|
|
||||||
|
- Bug #2220: handle rlcompleter attribute match failure more gracefully.
|
||||||
|
|
||||||
|
- Issue #2225: py_compile, when executed as a script, now returns a non-
|
||||||
|
zero status code if not all files could be compiled successfully.
|
||||||
|
|
||||||
|
- Bug #1725737: In distutil's sdist, exclude RCS, CVS etc. also in the
|
||||||
|
root directory, and also exclude .hg, .git, .bzr, and _darcs.
|
||||||
|
|
||||||
|
- Issue #1872: The struct module typecode for _Bool has been changed
|
||||||
|
from 't' to '?'.
|
||||||
|
|
||||||
|
- The bundled libffi copy is now in sync with the recently released
|
||||||
|
libffi3.0.4 version, apart from some small changes to
|
||||||
|
Modules/_ctypes/libffi/configure.ac.
|
||||||
|
On OS X, preconfigured libffi files are used.
|
||||||
|
On all linux systems the --with-system-ffi configure option defaults
|
||||||
|
to "yes".
|
||||||
|
|
||||||
|
- Issue 1577: shutil.move() now calls os.rename() if the destination is a
|
||||||
|
directory instead of copying-then-remove-source.
|
||||||
|
|
||||||
|
Tests
|
||||||
|
-----
|
||||||
|
|
||||||
|
- test_nis no longer fails when test.test_support.verbose is true and NIS is
|
||||||
|
not set up on the testing machine.
|
||||||
|
|
||||||
|
- Output comparison tests are no longer supported.
|
||||||
|
|
||||||
|
- Rewrite test_errno to use unittest and no longer be a no-op.
|
||||||
|
|
||||||
|
- GHOP 234: Convert test_extcall to doctest.
|
||||||
|
|
||||||
|
- GHOP 290: Convert test_dbm and test_dummy_threading to unittest.
|
||||||
|
|
||||||
|
- GHOP 293: Convert test_strftime, test_getargs, and test_pep247 to unittest.
|
||||||
|
|
||||||
|
- Issue #2055: Convert test_fcntl to unittest.
|
||||||
|
|
||||||
|
- Issue 1960: Convert test_gdbm to unittest.
|
||||||
|
|
||||||
|
- GHOP 294: Convert test_contains, test_crypt, and test_select to unittest.
|
||||||
|
|
||||||
|
- GHOP 238: Convert test_tokenize to use doctest.
|
||||||
|
|
||||||
|
- GHOP 237: Rewrite test_thread using unittest.
|
||||||
|
|
||||||
|
- Patch #2232: os.tmpfile might fail on Windows if the user has no
|
||||||
|
permission to create files in the root directory.
|
||||||
|
|
||||||
|
Build
|
||||||
|
-----
|
||||||
|
|
||||||
|
- A new script 2to3 is now installed, to run the 2.x to 3.x converter.
|
||||||
|
|
||||||
|
- Python/memmove.c and Python/strerror.c have been removed; both functions are
|
||||||
|
in the C89 standard library.
|
||||||
|
|
||||||
|
- Patch #2284: Add -x64 option to rt.bat.
|
||||||
|
|
||||||
|
C API
|
||||||
|
-----
|
||||||
|
|
||||||
|
- Patch #2477: Added PyParser_ParseFileFlagsEx() and
|
||||||
|
PyParser_ParseStringFlagsFilenameEx()
|
||||||
|
|
||||||
|
What's New in Python 2.6 alpha 1?
|
||||||
|
=================================
|
||||||
|
|
||||||
|
>>>>>>> .merge-right.r62114
|
||||||
*Release date: 29-Feb-2008*
|
*Release date: 29-Feb-2008*
|
||||||
|
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
|
@ -64,6 +186,38 @@ Core and Builtins
|
||||||
|
|
||||||
- Issue #2282: io.TextIOWrapper was not overriding seekable() from io.IOBase.
|
- Issue #2282: io.TextIOWrapper was not overriding seekable() from io.IOBase.
|
||||||
|
|
||||||
|
- Issue #2067: file.__exit__() now calls subclasses' close() method.
|
||||||
|
|
||||||
|
- Patch #1759: Backport of PEP 3129 class decorators.
|
||||||
|
|
||||||
|
- Issue #1881: An internal parser limit has been increased. Also see
|
||||||
|
issue 215555 for a discussion.
|
||||||
|
|
||||||
|
- Added the future_builtins module, which contains hex() and oct().
|
||||||
|
These are the PEP 3127 version of these functions, designed to be
|
||||||
|
compatible with the hex() and oct() builtins from Python 3.0. They
|
||||||
|
differ slightly in their output formats from the existing, unchanged
|
||||||
|
Python 2.6 builtins. The expected usage of the future_builtins
|
||||||
|
module is:
|
||||||
|
from future_builtins import hex, oct
|
||||||
|
|
||||||
|
- Issue #1600: Modifed PyOS_ascii_formatd to use at most 2 digit
|
||||||
|
exponents for exponents with absolute value < 100. Follows C99
|
||||||
|
standard. This is a change on Windows, which would use 3 digits.
|
||||||
|
Also, added 'n' to the formats that PyOS_ascii_formatd understands,
|
||||||
|
so that any alterations it does to the resulting string will be
|
||||||
|
available in stringlib/formatter.h (for float.__format__).
|
||||||
|
|
||||||
|
- Implemented PEP 3101, Advanced String Formatting. This adds a new
|
||||||
|
builtin format(); a format() method for str and unicode; a
|
||||||
|
__format__() method to object, str, unicode, int, long, float, and
|
||||||
|
datetime; the class string.Formatter; and the C API
|
||||||
|
PyObject_Format().
|
||||||
|
|
||||||
|
- Fixed several potential crashes, all caused by specially crafted __del__
|
||||||
|
methods exploiting objects in temporarily inconsistent state.
|
||||||
|
|
||||||
|
>>>>>>> .merge-right.r62114
|
||||||
- Issue #2115: Important speedup in setting __slot__ attributes. Also
|
- Issue #2115: Important speedup in setting __slot__ attributes. Also
|
||||||
prevent a possible crash: an Abstract Base Class would try to access a slot
|
prevent a possible crash: an Abstract Base Class would try to access a slot
|
||||||
on a registered virtual subclass.
|
on a registered virtual subclass.
|
||||||
|
@ -106,6 +260,11 @@ Core and Builtins
|
||||||
|
|
||||||
- Issue #1969: split and rsplit in bytearray are inconsistent
|
- Issue #1969: split and rsplit in bytearray are inconsistent
|
||||||
|
|
||||||
|
- Issue #1920: "while 0" statements were completely removed by the compiler,
|
||||||
|
even in the presence of an "else" clause, which is supposed to be run when
|
||||||
|
the condition is false. Now the compiler correctly emits bytecode for the
|
||||||
|
"else" suite.
|
||||||
|
|
||||||
- map() and no longer accepts None for the first argument.
|
- map() and no longer accepts None for the first argument.
|
||||||
Use zip() instead.
|
Use zip() instead.
|
||||||
|
|
||||||
|
@ -496,9 +655,15 @@ C API
|
||||||
- Removed these C APIs:
|
- Removed these C APIs:
|
||||||
PyNumber_Coerce(), PyNumber_CoerceEx(), PyMember_Get, PyMember_Set
|
PyNumber_Coerce(), PyNumber_CoerceEx(), PyMember_Get, PyMember_Set
|
||||||
|
|
||||||
|
- ``PySet_Add()`` can now modify a newly created frozenset. Similarly to
|
||||||
|
``PyTuple_SetItem``, it can be used to populate a brand new frozenset; but
|
||||||
|
it does not steal a reference to the added item.
|
||||||
|
|
||||||
- Removed these C slots/fields:
|
- Removed these C slots/fields:
|
||||||
nb_divide, nb_inplace_divide
|
nb_divide, nb_inplace_divide
|
||||||
|
|
||||||
|
- Added ``PySet_Check()`` and ``PyFrozenSet_Check()`` to the set API.
|
||||||
|
|
||||||
- Removed these macros:
|
- Removed these macros:
|
||||||
staticforward, statichere, PyArg_GetInt, PyArg_NoArgs, _PyObject_Del
|
staticforward, statichere, PyArg_GetInt, PyArg_NoArgs, _PyObject_Del
|
||||||
|
|
||||||
|
@ -534,4 +699,34 @@ Platforms
|
||||||
Tools/Demos
|
Tools/Demos
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
- Bug #1542693: remove semi-colon at end of PyImport_ImportModuleEx macro
|
||||||
|
so it can be used as an expression.
|
||||||
|
|
||||||
|
|
||||||
|
Windows
|
||||||
|
-------
|
||||||
|
|
||||||
|
- Patch #1706: Drop support for Win9x, WinME and NT4. Python now requires
|
||||||
|
Windows 2000 or greater. The _WINVER and NTDDI_VERSION macros are set to
|
||||||
|
Win2k for x86/32bit builds and WinXP for AMD64 builds.
|
||||||
|
|
||||||
|
- Conditionalize definition of _CRT_SECURE_NO_DEPRECATE
|
||||||
|
and _CRT_NONSTDC_NO_DEPRECATE.
|
||||||
|
|
||||||
|
- Bug #1216: Restore support for Visual Studio 2002.
|
||||||
|
|
||||||
|
|
||||||
|
Mac
|
||||||
|
---
|
||||||
|
|
||||||
|
- cfmfile now raises a DeprecationWarning.
|
||||||
|
|
||||||
|
- buildtools now raises a DeprecationWarning.
|
||||||
|
|
||||||
|
- Removed the macfs module. It had been deprecated since Python 2.5. This
|
||||||
|
lead to the deprecation of macostools.touched() as it relied solely on macfs
|
||||||
|
and was a no-op under OS X.
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
**(For information about older versions, consult the HISTORY file.)**
|
**(For information about older versions, consult the HISTORY file.)**
|
||||||
|
|
8
README
8
README
|
@ -88,9 +88,11 @@ release under development).
|
||||||
Proposals for enhancement
|
Proposals for enhancement
|
||||||
------------------------------
|
------------------------------
|
||||||
|
|
||||||
If you have a proposal to change Python, it's best to submit a Python
|
If you have a proposal to change Python, you may want to send an email to the
|
||||||
Enhancement Proposal (PEP) first. All current PEPs, as well as guidelines for
|
comp.lang.python or python-ideas mailing lists for inital feedback. A Python
|
||||||
submitting a new PEP, are listed at http://www.python.org/dev/peps/.
|
Enhancement Proposal (PEP) may be submitted if your idea gains ground. All
|
||||||
|
current PEPs, as well as guidelines for submitting a new PEP, are listed at
|
||||||
|
http://www.python.org/dev/peps/.
|
||||||
|
|
||||||
Converting From Python 2.x to 3.0
|
Converting From Python 2.x to 3.0
|
||||||
---------------------------------
|
---------------------------------
|
||||||
|
|
Loading…
Reference in New Issue