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:
Benjamin Peterson 2008-04-02 21:49:44 +00:00
parent 84bea688c2
commit ad9d48d865
11 changed files with 333 additions and 61 deletions

View File

@ -1649,10 +1649,11 @@ timed intervals.
The system will save old log files by appending extensions to the filename.
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
interval. If *backupCount* is nonzero, at most *backupCount* files will be
kept, and if more would be created when rollover occurs, the oldest one is
deleted.
``%Y-%m-%d_%H-%M-%S`` or a leading portion thereof, depending on the
rollover interval. If *backupCount* is nonzero, at most *backupCount* files
will be kept, and if more would be created when rollover occurs, the oldest
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()

View File

@ -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
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!
"""
import logging, socket, os, pickle, struct, time, glob
import logging, socket, os, pickle, struct, time, re
from stat import ST_DEV, ST_INO
try:
@ -173,15 +173,19 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
if self.when == 'S':
self.interval = 1 # one second
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':
self.interval = 60 # one minute
self.suffix = "%Y-%m-%d_%H-%M"
self.extMatch = r"^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}$"
elif self.when == 'H':
self.interval = 60 * 60 # one hour
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':
self.interval = 60 * 60 * 24 # one day
self.suffix = "%Y-%m-%d"
self.extMatch = r"^\d{4}-\d{2}-\d{2}$"
elif self.when.startswith('W'):
self.interval = 60 * 60 * 24 * 7 # one week
if len(self.when) != 2:
@ -190,9 +194,11 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
raise ValueError("Invalid day specified for weekly rollover: %s" % self.when)
self.dayOfWeek = int(self.when[1])
self.suffix = "%Y-%m-%d"
self.extMatch = r"^\d{4}-\d{2}-\d{2}$"
else:
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.rolloverAt = currentTime + self.interval
@ -235,16 +241,24 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
daysToWait = self.dayOfWeek - day
else:
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)
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
the method siguratures are the same
the method signatures are the same
"""
t = int(time.time())
if t >= self.rolloverAt:
@ -252,6 +266,29 @@ class TimedRotatingFileHandler(BaseRotatingHandler):
#print "No need to rollover: %d, %d" % (t, self.rolloverAt)
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):
"""
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)
if self.backupCount > 0:
# find the oldest log file and delete it
s = glob.glob(self.baseFilename + ".20*")
if len(s) > self.backupCount:
s.sort()
os.remove(s[0])
#s = glob.glob(self.baseFilename + ".20*")
#if len(s) > self.backupCount:
# s.sort()
# os.remove(s[0])
for s in self.getFilesToDelete():
os.remove(s)
#print "%s -> %s" % (self.baseFilename, dfn)
self.mode = 'w'
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):
"""

View File

@ -122,3 +122,7 @@ def test_main(verbose=None):
from test.test_support import run_doctest
from test import test_code
run_doctest(test_code, verbose)
if __name__ == '__main__':
test_main()

View File

@ -317,13 +317,12 @@ class TestCollectionABCs(unittest.TestCase):
self.failIf(issubclass(str, MutableSequence))
import doctest, collections
NamedTupleDocs = doctest.DocTestSuite(module=collections)
def test_main(verbose=None):
import collections as CollectionsModule
NamedTupleDocs = doctest.DocTestSuite(module=collections)
test_classes = [TestNamedTuple, NamedTupleDocs, TestOneTrickPonyABCs, TestCollectionABCs]
test_support.run_unittest(*test_classes)
test_support.run_doctest(CollectionsModule, verbose)
test_support.run_doctest(collections, verbose)
if __name__ == "__main__":

View File

@ -574,6 +574,22 @@ class StatefulIncrementalDecoder(codecs.IncrementalDecoder):
self.buffer = bytearray()
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):
"""
Make sure the StatefulIncrementalDecoder actually works.
@ -899,14 +915,6 @@ class TextIOWrapperTest(unittest.TestCase):
def testSeekAndTell(self):
"""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):
"""Tell/seek to various points within a data stream and ensure
that the decoded data returned by read() is consistent."""
@ -927,9 +935,8 @@ class TextIOWrapperTest(unittest.TestCase):
self.assertEquals(f.read(), decoded[i:])
f.close()
# Register a special incremental decoder for testing.
codecs.register(lookupTestDecoder)
self.codecEnabled = 1
# Enable the test decoder.
StatefulIncrementalDecoder.codecEnabled = 1
# Run the tests.
try:
@ -948,7 +955,7 @@ class TextIOWrapperTest(unittest.TestCase):
# Ensure our test decoder won't interfere with subsequent tests.
finally:
self.codecEnabled = 0
StatefulIncrementalDecoder.codecEnabled = 0
def testEncodedWrites(self):
data = "1234567890"

View File

@ -13,3 +13,7 @@ def suite():
def test_main():
run_unittest(suite())
if __name__ == '__main__':
test_main()

View File

@ -28,6 +28,15 @@ def exit_subprocess():
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):
MAX_DURATION = 20 # Entire test should last at most 20 sec.
@ -77,8 +86,11 @@ class InterProcessSignalTests(unittest.TestCase):
if test_support.verbose:
print("test runner's pid is", pid)
child = subprocess.Popen(['kill', '-HUP', str(pid)])
self.wait(child)
child = ignoring_eintr(subprocess.Popen, ['kill', '-HUP', str(pid)])
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.assertFalse(self.b_called)
self.a_called = False
@ -87,6 +99,7 @@ class InterProcessSignalTests(unittest.TestCase):
child = subprocess.Popen(['kill', '-USR1', str(pid)])
# This wait should be interrupted by the signal's exception.
self.wait(child)
time.sleep(1) # Give the signal time to be delivered.
self.fail('HandlerBCalled exception not thrown')
except HandlerBCalled:
self.assertTrue(self.b_called)
@ -94,8 +107,9 @@ class InterProcessSignalTests(unittest.TestCase):
if test_support.verbose:
print("HandlerBCalled exception caught")
child = subprocess.Popen(['kill', '-USR2', str(pid)])
self.wait(child) # Nothing should happen.
child = ignoring_eintr(subprocess.Popen, ['kill', '-USR2', str(pid)])
if child:
self.wait(child) # Nothing should happen.
try:
signal.alarm(1)
@ -103,14 +117,18 @@ class InterProcessSignalTests(unittest.TestCase):
# since alarm is going to raise a KeyboardException, which
# will skip the call.
signal.pause()
# But if another signal arrives before the alarm, pause
# may return early.
time.sleep(1)
except KeyboardInterrupt:
if test_support.verbose:
print("KeyboardInterrupt (the alarm() went off)")
except:
self.fail('Some other exception woke us from pause: %s' %
self.fail("Some other exception woke us from pause: %s" %
traceback.format_exc())
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):
# This function spawns a child process to insulate the main

View File

@ -15,14 +15,6 @@ import array
from weakref import proxy
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
HOST = 'localhost'
MSG = b'Michael Gilfix was here\n'
@ -30,21 +22,15 @@ MSG = b'Michael Gilfix was here\n'
class SocketTCPTest(unittest.TestCase):
def setUp(self):
verbose_write(self)
self.serv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.serv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
verbose_write(str(self) + " socket created")
global PORT
PORT = test_support.bind_port(self.serv, HOST, PORT)
verbose_write(str(self) + " start listening")
self.serv.listen(1)
verbose_write(str(self) + " started")
def tearDown(self):
verbose_write(str(self) + " close")
self.serv.close()
self.serv = None
verbose_write(str(self) + " done")
class SocketUDPTest(unittest.TestCase):

View File

@ -381,19 +381,23 @@ def transient_internet():
@contextlib.contextmanager
def captured_stdout():
"""Run the with statement body using a StringIO object as sys.stdout.
Example use::
def captured_output(stream_name):
"""Run the 'with' statement body using a StringIO object in place of a
specific attribute on the sys module.
Example use (with 'stream_name=stdout')::
with captured_stdout() as s:
print "hello"
assert s.getvalue() == "hello"
"""
import io
orig_stdout = sys.stdout
sys.stdout = io.StringIO()
yield sys.stdout
sys.stdout = orig_stdout
orig_stdout = getattr(sys, stream_name)
setattr(sys, stream_name, io.StringIO())
yield getattr(sys, stream_name)
setattr(sys, stream_name, orig_stdout)
def captured_stdout():
return captured_output("stdout")
#=======================================================================

199
Misc/NEWS
View File

@ -29,6 +29,19 @@ Library
as a build_py replacement to automatically run 2to3 on modules
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
for bytes. This is the default protocol. It intentionally cannot
be unpickled by Python 2.x.
@ -57,6 +70,115 @@ Library
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*
Core and Builtins
@ -64,8 +186,40 @@ Core and Builtins
- Issue #2282: io.TextIOWrapper was not overriding seekable() from io.IOBase.
- Issue #2115: Important speedup in setting __slot__ attributes. Also
prevent a possible crash: an Abstract Base Class would try to access a slot
- 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
prevent a possible crash: an Abstract Base Class would try to access a slot
on a registered virtual subclass.
- Fixed repr() and str() of complex numbers with infinity or nan as real or
@ -106,6 +260,11 @@ Core and Builtins
- 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.
Use zip() instead.
@ -496,9 +655,15 @@ C API
- Removed these C APIs:
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:
nb_divide, nb_inplace_divide
- Added ``PySet_Check()`` and ``PyFrozenSet_Check()`` to the set API.
- Removed these macros:
staticforward, statichere, PyArg_GetInt, PyArg_NoArgs, _PyObject_Del
@ -534,4 +699,34 @@ Platforms
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.)**

8
README
View File

@ -88,9 +88,11 @@ release under development).
Proposals for enhancement
------------------------------
If you have a proposal to change Python, it's best to submit a Python
Enhancement Proposal (PEP) first. All current PEPs, as well as guidelines for
submitting a new PEP, are listed at http://www.python.org/dev/peps/.
If you have a proposal to change Python, you may want to send an email to the
comp.lang.python or python-ideas mailing lists for inital feedback. A Python
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
---------------------------------