From python-checkins at python.org Sat Jan 1 00:00:06 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 1 Jan 2011 00:00:06 +0100 (CET) Subject: [Python-checkins] r87593 - in python/branches/py3k: Doc/README.txt Doc/copyright.rst Doc/license.rst LICENSE PC/python_nt.rc README Message-ID: <20101231230006.1D430EE9E1@mail.python.org> Author: georg.brandl Date: Sat Jan 1 00:00:03 2011 New Revision: 87593 Log: Happy New Year! (CET edition) Modified: python/branches/py3k/Doc/README.txt python/branches/py3k/Doc/copyright.rst python/branches/py3k/Doc/license.rst python/branches/py3k/LICENSE python/branches/py3k/PC/python_nt.rc python/branches/py3k/README Modified: python/branches/py3k/Doc/README.txt ============================================================================== --- python/branches/py3k/Doc/README.txt (original) +++ python/branches/py3k/Doc/README.txt Sat Jan 1 00:00:03 2011 @@ -132,7 +132,7 @@ as long as you don't change or remove the copyright notice: ---------------------------------------------------------------------- -Copyright (c) 2000-2010 Python Software Foundation. +Copyright (c) 2000-2011 Python Software Foundation. All rights reserved. Copyright (c) 2000 BeOpen.com. Modified: python/branches/py3k/Doc/copyright.rst ============================================================================== --- python/branches/py3k/Doc/copyright.rst (original) +++ python/branches/py3k/Doc/copyright.rst Sat Jan 1 00:00:03 2011 @@ -4,7 +4,7 @@ Python and this documentation is: -Copyright ?? 2001-2010 Python Software Foundation. All rights reserved. +Copyright ?? 2001-2011 Python Software Foundation. All rights reserved. Copyright ?? 2000 BeOpen.com. All rights reserved. Modified: python/branches/py3k/Doc/license.rst ============================================================================== --- python/branches/py3k/Doc/license.rst (original) +++ python/branches/py3k/Doc/license.rst Sat Jan 1 00:00:03 2011 @@ -108,7 +108,7 @@ +----------------+--------------+------------+------------+-----------------+ | 3.1.2 | 3.1 | 2010 | PSF | yes | +----------------+--------------+------------+------------+-----------------+ -| 3.2 | 3.1 | 2010 | PSF | yes | +| 3.2 | 3.1 | 2011 | PSF | yes | +----------------+--------------+------------+------------+-----------------+ .. note:: @@ -138,7 +138,7 @@ analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python |release| alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of - copyright, i.e., "Copyright ?? 2001-2010 Python Software Foundation; All Rights + copyright, i.e., "Copyright ?? 2001-2011 Python Software Foundation; All Rights Reserved" are retained in Python |release| alone or in any derivative version prepared by Licensee. @@ -906,7 +906,7 @@ sources unless the zlib version found on the system is too old to be used for the build:: - Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler + Copyright (C) 1995-2011 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages Modified: python/branches/py3k/LICENSE ============================================================================== --- python/branches/py3k/LICENSE (original) +++ python/branches/py3k/LICENSE Sat Jan 1 00:00:03 2011 @@ -68,7 +68,7 @@ 3.1 3.0.1 2009 PSF yes 3.1.1 3.1 2009 PSF yes 3.1.2 3.1 2010 PSF yes - 3.2 3.1 2010 PSF yes + 3.2 3.1 2011 PSF yes Footnotes: @@ -103,9 +103,9 @@ analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, -i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 -Python Software Foundation; All Rights Reserved" are retained in Python alone or -in any derivative version prepared by Licensee. +i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, +2011 Python Software Foundation; All Rights Reserved" are retained in Python +alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make Modified: python/branches/py3k/PC/python_nt.rc ============================================================================== --- python/branches/py3k/PC/python_nt.rc (original) +++ python/branches/py3k/PC/python_nt.rc Sat Jan 1 00:00:03 2011 @@ -61,7 +61,7 @@ VALUE "FileDescription", "Python Core\0" VALUE "FileVersion", PYTHON_VERSION VALUE "InternalName", "Python DLL\0" - VALUE "LegalCopyright", "Copyright ? 2001-2010 Python Software Foundation. Copyright ? 2000 BeOpen.com. Copyright ? 1995-2001 CNRI. Copyright ? 1991-1995 SMC.\0" + VALUE "LegalCopyright", "Copyright ? 2001-2011 Python Software Foundation. Copyright ? 2000 BeOpen.com. Copyright ? 1995-2001 CNRI. Copyright ? 1991-1995 SMC.\0" VALUE "OriginalFilename", PYTHON_DLL_NAME "\0" VALUE "ProductName", "Python\0" VALUE "ProductVersion", PYTHON_VERSION Modified: python/branches/py3k/README ============================================================================== --- python/branches/py3k/README (original) +++ python/branches/py3k/README Sat Jan 1 00:00:03 2011 @@ -1,7 +1,7 @@ This is Python version 3.2 beta 2 ================================= -Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Python Software Foundation. All rights reserved. From python-checkins at python.org Sat Jan 1 00:16:17 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 1 Jan 2011 00:16:17 +0100 (CET) Subject: [Python-checkins] r87594 - in python/branches/py3k: Lib/collections.py Lib/test/test_collections.py Misc/NEWS Message-ID: <20101231231617.C148CEE9C5@mail.python.org> Author: raymond.hettinger Date: Sat Jan 1 00:16:17 2011 New Revision: 87594 Log: Fix OrderedDict.setdefault() to work for subclasses that define __missing__(). Modified: python/branches/py3k/Lib/collections.py python/branches/py3k/Lib/test/test_collections.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/collections.py ============================================================================== --- python/branches/py3k/Lib/collections.py (original) +++ python/branches/py3k/Lib/collections.py Sat Jan 1 00:16:17 2011 @@ -171,7 +171,6 @@ size += sizeof(self.__root) * n # proxy objects return size - setdefault = MutableMapping.setdefault update = MutableMapping.update pop = MutableMapping.pop keys = MutableMapping.keys @@ -179,6 +178,13 @@ items = MutableMapping.items __ne__ = MutableMapping.__ne__ + def setdefault(self, key, default=None): + 'OD.setdefault(k[,d]) -> OD.get(k,d), also set OD[k]=d if k not in OD' + if key in self: + return self[key] + self[key] = default + return default + @_recursive_repr() def __repr__(self): 'od.__repr__() <==> repr(od)' Modified: python/branches/py3k/Lib/test/test_collections.py ============================================================================== --- python/branches/py3k/Lib/test/test_collections.py (original) +++ python/branches/py3k/Lib/test/test_collections.py Sat Jan 1 00:16:17 2011 @@ -976,6 +976,12 @@ # make sure 'x' is added to the end self.assertEqual(list(od.items())[-1], ('x', 10)) + # make sure setdefault still works when __missing__ is defined + class Missing(OrderedDict): + def __missing__(self, key): + return 0 + self.assertEqual(Missing().setdefault(5, 9), 9) + def test_reinsert(self): # Given insert a, insert b, delete a, re-insert a, # verify that a is now later than b. Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 1 00:16:17 2011 @@ -20,6 +20,9 @@ Library ------- +- Fix collections.OrderedDict.setdefault() so that it works in + subclasses that define __missing__(). + - Issue 10786: unittest.TextTestRunner default stream no longer bound at import time. `sys.stderr` now looked up at instantiation time. Fix contributed by Mark Roddy. From python-checkins at python.org Sat Jan 1 00:23:06 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 1 Jan 2011 00:23:06 +0100 (CET) Subject: [Python-checkins] r87595 - python/branches/py3k/Misc/NEWS Message-ID: <20101231232306.E8C3EEE9C5@mail.python.org> Author: raymond.hettinger Date: Sat Jan 1 00:23:06 2011 New Revision: 87595 Log: Typo. Modified: python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 1 00:23:06 2011 @@ -74,7 +74,7 @@ - Issue #10750: The ``raw`` attribute of buffered IO objects is now read-only. -- Deprecated assertDictContainsSubclass() in the unittest module. +- Deprecated assertDictContainsSubset() in the unittest module. Build ----- From python-checkins at python.org Sat Jan 1 01:29:59 2011 From: python-checkins at python.org (terry.reedy) Date: Sat, 1 Jan 2011 01:29:59 +0100 (CET) Subject: [Python-checkins] r87596 - python/branches/release31-maint/Doc/library/threading.rst Message-ID: <20110101002959.BB195EE99B@mail.python.org> Author: terry.reedy Date: Sat Jan 1 01:29:59 2011 New Revision: 87596 Log: Issue 10789: Correct threading.Lock.acquire signature. Modified: python/branches/release31-maint/Doc/library/threading.rst Modified: python/branches/release31-maint/Doc/library/threading.rst ============================================================================== --- python/branches/release31-maint/Doc/library/threading.rst (original) +++ python/branches/release31-maint/Doc/library/threading.rst Sat Jan 1 01:29:59 2011 @@ -365,7 +365,7 @@ All methods are executed atomically. -.. method:: Lock.acquire(blocking=True) +.. method:: Lock.acquire([blocking]) Acquire a lock, blocking or non-blocking. From python-checkins at python.org Sat Jan 1 01:36:18 2011 From: python-checkins at python.org (terry.reedy) Date: Sat, 1 Jan 2011 01:36:18 +0100 (CET) Subject: [Python-checkins] r87597 - python/branches/release27-maint/Doc/library/threading.rst Message-ID: <20110101003618.2D1F6EE99B@mail.python.org> Author: terry.reedy Date: Sat Jan 1 01:36:18 2011 New Revision: 87597 Log: Issue 10789: Correct threading.Lock.acquire signature. Modified: python/branches/release27-maint/Doc/library/threading.rst Modified: python/branches/release27-maint/Doc/library/threading.rst ============================================================================== --- python/branches/release27-maint/Doc/library/threading.rst (original) +++ python/branches/release27-maint/Doc/library/threading.rst Sat Jan 1 01:36:18 2011 @@ -388,7 +388,7 @@ All methods are executed atomically. -.. method:: Lock.acquire([blocking=1]) +.. method:: Lock.acquire([blocking]) Acquire a lock, blocking or non-blocking. From nnorwitz at gmail.com Sat Jan 1 01:39:33 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Fri, 31 Dec 2010 19:39:33 -0500 Subject: [Python-checkins] Python Regression Test Failures all (1) Message-ID: <20110101003933.GA2910@kbk-i386-bb.dyndns.org> 352 tests OK. 1 test failed: test_sqlite 28 tests skipped: test_aepack test_al test_applesingle test_bsddb185 test_cd test_cl test_epoll test_gdb test_gl test_imgfile test_ioctl test_kqueue test_macos test_macostools test_multiprocessing test_pep277 test_py3kwarn test_scriptpackages test_startfile test_sunaudiodev test_tcl test_tk test_ttk_guionly test_ttk_textonly test_unicode_file test_winreg test_winsound test_zipfile64 7 skips unexpected on linux2: test_epoll test_gdb test_ioctl test_multiprocessing test_tk test_ttk_guionly test_ttk_textonly == CPython 2.7 (trunk:87592M, Dec 31 2010, 16:04:00) [GCC 3.3.4 20040623 (Gentoo Linux 3.3.4-r1, ssp-3.3.2-2, pie-8.7.6)] == Linux-2.6.9-gentoo-r1-i686-AMD_Athlon-tm-_XP_3000+-with-gentoo-1.4.16 little-endian == /tmp/test_python_27021 test_grammar test_opcodes test_dict test_builtin test_exceptions test_types test_unittest test_doctest test_doctest2 test_MimeWriter test_SimpleHTTPServer test_StringIO test___all__ test___future__ test__locale test_abc test_abstract_numbers test_aepack test_aepack skipped -- No module named aetypes test_aifc test_al test_al skipped -- No module named al test_anydbm test_applesingle test_applesingle skipped -- No module named MacOS test_argparse test_array test_ascii_formatd test_ast test_asynchat test_asyncore test_atexit test_audioop test_augassign test_base64 test_bastion test_bigaddrspace test_bigmem test_binascii test_binhex test_binop test_bisect test_bool test_bsddb test_bsddb185 test_bsddb185 skipped -- No module named bsddb185 test_bsddb3 Sleepycat Software: Berkeley DB 4.1.25: (December 19, 2002) Test path prefix: /tmp/z-test_bsddb3-27021 test_buffer test_bufio test_bytes test_bz2 test_calendar test_call test_capi test_cd test_cd skipped -- No module named cd test_cfgparser test_cgi test_charmapcodec test_cl test_cl skipped -- No module named cl test_class test_cmath test_cmd test_cmd_line test_cmd_line_script test_code test_codeccallbacks test_codecencodings_cn test_codecencodings_hk test_codecencodings_jp test_codecencodings_kr test_codecencodings_tw test_codecmaps_cn test_codecmaps_hk test_codecmaps_jp test_codecmaps_kr test_codecmaps_tw test_codecs test_codeop test_coding test_coercion test_collections test_colorsys test_commands test_compare test_compile test_compileall test_compiler testCompileLibrary still working, be patient... test_complex test_complex_args test_contains test_contextlib test_cookie test_cookielib test_copy test_copy_reg test_cpickle test_cprofile test_crypt test_csv test_ctypes test_datetime test_dbm test_decimal test_decorators test_defaultdict test_deque test_descr test_descrtut test_dictcomps test_dictviews test_difflib test_dircache test_dis test_distutils [19643 refs] test_dl test_docxmlrpc test_dumbdbm test_dummy_thread test_dummy_threading test_email test_email_codecs test_email_renamed test_enumerate test_eof test_epoll test_epoll skipped -- kernel doesn't support epoll() test_errno test_exception_variations test_extcall test_fcntl test_file test_file2k test_filecmp test_fileinput test_fileio test_float test_fnmatch test_fork1 test_format test_fpformat test_fractions test_frozen test_ftplib test_funcattrs test_functools test_future test_future3 test_future4 test_future5 test_future_builtins test_gc test_gdb test_gdb skipped -- gdb versions before 7.0 didn't support python embedding Saw: GNU gdb 6.2.1 Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-pc-linux-gnu". test_gdbm test_generators test_genericpath test_genexps test_getargs test_getargs2 test_getopt test_gettext test_gl test_gl skipped -- No module named gl test_glob test_global test_grp test_gzip test_hash test_hashlib test_heapq test_hmac test_hotshot test_htmllib test_htmlparser test_httplib test_httpservers [15648 refs] [15648 refs] [15648 refs] [25315 refs] test_imageop test_imaplib test_imgfile test_imgfile skipped -- No module named imgfile test_imp test_import test_importhooks test_importlib test_index test_inspect test_int test_int_literal test_io test_ioctl test_ioctl skipped -- Unable to open /dev/tty test_isinstance test_iter test_iterlen test_itertools test_json test_kqueue test_kqueue skipped -- test works only on BSD test_largefile test_lib2to3 test_linecache test_list test_locale test_logging test_long test_long_future test_longexp test_macos test_macos skipped -- No module named MacOS test_macostools test_macostools skipped -- No module named MacOS test_macpath test_mailbox test_marshal test_math test_md5 test_memoryio test_memoryview test_mhlib test_mimetools test_mimetypes test_minidom test_mmap test_module test_modulefinder test_multibytecodec test_multibytecodec_support test_multifile test_multiprocessing test_multiprocessing skipped -- This platform lacks a functioning sem_open implementation, therefore, the required synchronization primitives needed will not function, see issue 3770. test_mutants test_mutex test_netrc test_new test_nis test_normalization test_ntpath test_old_mailbox test_openpty test_operator test_optparse test_os [15648 refs] [15648 refs] test_parser Expecting 's_push: parser stack overflow' in next line s_push: parser stack overflow test_pdb test_peepholer test_pep247 test_pep263 test_pep277 test_pep277 skipped -- only NT+ and systems with Unicode-friendly filesystem encoding test_pep292 test_pep352 test_pickle test_pickletools test_pipes test_pkg test_pkgimport test_pkgutil test_platform [17044 refs] [17044 refs] test_plistlib test_poll test_popen [15653 refs] [15653 refs] [15653 refs] test_popen2 test_poplib test_posix test_posixpath test_pow test_pprint test_print test_profile test_profilehooks test_property test_pstats test_pty test_pwd test_py3kwarn test_py3kwarn skipped -- test.test_py3kwarn must be run with the -3 flag test_pyclbr test_pydoc [20862 refs] [20862 refs] [20862 refs] [20862 refs] [20862 refs] [20861 refs] [20861 refs] test_pyexpat test_queue test_quopri [18479 refs] [18479 refs] test_random test_re test_readline test_repr test_resource test_rfc822 test_richcmp test_robotparser test_runpy test_sax test_scope test_scriptpackages test_scriptpackages skipped -- No module named aetools test_select test_set test_setcomps test_sets test_sgmllib test_sha test_shelve test_shlex test_shutil test_signal test_site [15648 refs] [15648 refs] [15648 refs] [15648 refs] test_slice test_smtplib test_smtpnet test_socket test_socketserver test_softspace test_sort test_sqlite test test_sqlite failed -- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/sqlite3/test/types.py", line 388, in CheckSqlTimestamp self.assertEqual(ts.year, now.year) AssertionError: 2011 != 2010 Re-running test 'test_sqlite' in verbose mode CheckAPILevel (sqlite3.test.dbapi.ModuleTests) ... ok CheckDataError (sqlite3.test.dbapi.ModuleTests) ... ok CheckDatabaseError (sqlite3.test.dbapi.ModuleTests) ... ok CheckError (sqlite3.test.dbapi.ModuleTests) ... ok CheckIntegrityError (sqlite3.test.dbapi.ModuleTests) ... ok CheckInterfaceError (sqlite3.test.dbapi.ModuleTests) ... ok CheckInternalError (sqlite3.test.dbapi.ModuleTests) ... ok CheckNotSupportedError (sqlite3.test.dbapi.ModuleTests) ... ok CheckOperationalError (sqlite3.test.dbapi.ModuleTests) ... ok CheckParamStyle (sqlite3.test.dbapi.ModuleTests) ... ok CheckProgrammingError (sqlite3.test.dbapi.ModuleTests) ... ok CheckThreadSafety (sqlite3.test.dbapi.ModuleTests) ... ok CheckWarning (sqlite3.test.dbapi.ModuleTests) ... ok CheckClose (sqlite3.test.dbapi.ConnectionTests) ... ok CheckCommit (sqlite3.test.dbapi.ConnectionTests) ... ok CheckCommitAfterNoChanges (sqlite3.test.dbapi.ConnectionTests) ... ok CheckCursor (sqlite3.test.dbapi.ConnectionTests) ... ok CheckExceptions (sqlite3.test.dbapi.ConnectionTests) ... ok CheckFailedOpen (sqlite3.test.dbapi.ConnectionTests) ... ok CheckRollback (sqlite3.test.dbapi.ConnectionTests) ... ok CheckRollbackAfterNoChanges (sqlite3.test.dbapi.ConnectionTests) ... ok CheckArraySize (sqlite3.test.dbapi.CursorTests) ... ok CheckClose (sqlite3.test.dbapi.CursorTests) ... ok CheckCursorConnection (sqlite3.test.dbapi.CursorTests) ... ok CheckCursorWrongClass (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteArgFloat (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteArgInt (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteArgString (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteDictMapping (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteDictMappingNoArgs (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteDictMappingTooLittleArgs (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteDictMappingUnnamed (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteDictMapping_Mapping (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteIllegalSql (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteManyGenerator (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteManyIterator (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteManyNotIterable (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteManySelect (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteManySequence (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteManyWrongSqlArg (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteNoArgs (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteParamList (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteParamSequence (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteTooMuchSql (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteTooMuchSql2 (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteTooMuchSql3 (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteWrongNoOfArgs1 (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteWrongNoOfArgs2 (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteWrongNoOfArgs3 (sqlite3.test.dbapi.CursorTests) ... ok CheckExecuteWrongSqlArg (sqlite3.test.dbapi.CursorTests) ... ok CheckFetchIter (sqlite3.test.dbapi.CursorTests) ... ok CheckFetchall (sqlite3.test.dbapi.CursorTests) ... ok CheckFetchmany (sqlite3.test.dbapi.CursorTests) ... ok CheckFetchmanyKwArg (sqlite3.test.dbapi.CursorTests) Checks if fetchmany works with keyword arguments ... ok CheckFetchone (sqlite3.test.dbapi.CursorTests) ... ok CheckFetchoneNoStatement (sqlite3.test.dbapi.CursorTests) ... ok CheckRowcountExecute (sqlite3.test.dbapi.CursorTests) ... ok CheckRowcountExecutemany (sqlite3.test.dbapi.CursorTests) ... ok CheckRowcountSelect (sqlite3.test.dbapi.CursorTests) ... ok CheckSetinputsizes (sqlite3.test.dbapi.CursorTests) ... ok CheckSetoutputsize (sqlite3.test.dbapi.CursorTests) ... ok CheckSetoutputsizeNoColumn (sqlite3.test.dbapi.CursorTests) ... ok CheckTotalChanges (sqlite3.test.dbapi.CursorTests) ... ok CheckWrongCursorCallable (sqlite3.test.dbapi.CursorTests) ... ok CheckConClose (sqlite3.test.dbapi.ThreadTests) ... ok CheckConCommit (sqlite3.test.dbapi.ThreadTests) ... ok CheckConCursor (sqlite3.test.dbapi.ThreadTests) ... ok CheckConRollback (sqlite3.test.dbapi.ThreadTests) ... ok CheckCurClose (sqlite3.test.dbapi.ThreadTests) ... ok CheckCurExecute (sqlite3.test.dbapi.ThreadTests) ... ok CheckCurImplicitBegin (sqlite3.test.dbapi.ThreadTests) ... ok CheckCurIterNext (sqlite3.test.dbapi.ThreadTests) ... ok CheckBinary (sqlite3.test.dbapi.ConstructorTests) ... ok CheckDate (sqlite3.test.dbapi.ConstructorTests) ... ok CheckDateFromTicks (sqlite3.test.dbapi.ConstructorTests) ... ok CheckTime (sqlite3.test.dbapi.ConstructorTests) ... ok CheckTimeFromTicks (sqlite3.test.dbapi.ConstructorTests) ... ok CheckTimestamp (sqlite3.test.dbapi.ConstructorTests) ... ok CheckTimestampFromTicks (sqlite3.test.dbapi.ConstructorTests) ... ok CheckConnectionExecute (sqlite3.test.dbapi.ExtensionTests) ... ok CheckConnectionExecutemany (sqlite3.test.dbapi.ExtensionTests) ... ok CheckConnectionExecutescript (sqlite3.test.dbapi.ExtensionTests) ... ok CheckScriptErrorNormal (sqlite3.test.dbapi.ExtensionTests) ... ok CheckScriptStringSql (sqlite3.test.dbapi.ExtensionTests) ... ok CheckScriptStringUnicode (sqlite3.test.dbapi.ExtensionTests) ... ok CheckScriptSyntaxError (sqlite3.test.dbapi.ExtensionTests) ... ok CheckClosedCall (sqlite3.test.dbapi.ClosedConTests) ... ok CheckClosedConCommit (sqlite3.test.dbapi.ClosedConTests) ... ok CheckClosedConCursor (sqlite3.test.dbapi.ClosedConTests) ... ok CheckClosedConRollback (sqlite3.test.dbapi.ClosedConTests) ... ok CheckClosedCreateAggregate (sqlite3.test.dbapi.ClosedConTests) ... ok CheckClosedCreateFunction (sqlite3.test.dbapi.ClosedConTests) ... ok CheckClosedCurExecute (sqlite3.test.dbapi.ClosedConTests) ... ok CheckClosedSetAuthorizer (sqlite3.test.dbapi.ClosedConTests) ... ok CheckClosedSetProgressCallback (sqlite3.test.dbapi.ClosedConTests) ... ok CheckClosed (sqlite3.test.dbapi.ClosedCurTests) ... ok CheckBlob (sqlite3.test.types.SqliteTypeTests) ... ok CheckFloat (sqlite3.test.types.SqliteTypeTests) ... ok CheckLargeInt (sqlite3.test.types.SqliteTypeTests) ... ok CheckNonUtf8_Default (sqlite3.test.types.SqliteTypeTests) ... ok CheckNonUtf8_TextFactoryOptimizedUnicode (sqlite3.test.types.SqliteTypeTests) ... ok CheckNonUtf8_TextFactoryString (sqlite3.test.types.SqliteTypeTests) ... ok CheckSmallInt (sqlite3.test.types.SqliteTypeTests) ... ok CheckString (sqlite3.test.types.SqliteTypeTests) ... ok CheckUnicodeExecute (sqlite3.test.types.SqliteTypeTests) ... ok CheckBlob (sqlite3.test.types.DeclTypesTests) ... ok CheckBool (sqlite3.test.types.DeclTypesTests) ... ok CheckFloat (sqlite3.test.types.DeclTypesTests) ... ok CheckFoo (sqlite3.test.types.DeclTypesTests) ... ok CheckLargeInt (sqlite3.test.types.DeclTypesTests) ... ok CheckNumber1 (sqlite3.test.types.DeclTypesTests) ... ok CheckNumber2 (sqlite3.test.types.DeclTypesTests) Checks wether converter names are cut off at '(' characters ... ok CheckSmallInt (sqlite3.test.types.DeclTypesTests) ... ok CheckString (sqlite3.test.types.DeclTypesTests) ... ok CheckUnicode (sqlite3.test.types.DeclTypesTests) ... ok CheckUnsupportedDict (sqlite3.test.types.DeclTypesTests) ... ok CheckUnsupportedSeq (sqlite3.test.types.DeclTypesTests) ... ok CheckCaseInConverterName (sqlite3.test.types.ColNamesTests) ... ok CheckColName (sqlite3.test.types.ColNamesTests) ... ok CheckCursorDescriptionNoRow (sqlite3.test.types.ColNamesTests) ... ok CheckDeclTypeNotUsed (sqlite3.test.types.ColNamesTests) ... ok CheckNone (sqlite3.test.types.ColNamesTests) ... ok CheckCasterIsUsed (sqlite3.test.types.ObjectAdaptationTests) ... ok CheckBinaryInputForConverter (sqlite3.test.types.BinaryConverterTests) ... ok CheckDateTimeSubSeconds (sqlite3.test.types.DateTimeTests) ... ok CheckDateTimeSubSecondsFloatingPoint (sqlite3.test.types.DateTimeTests) ... ok CheckSqlTimestamp (sqlite3.test.types.DateTimeTests) ... FAIL CheckSqliteDate (sqlite3.test.types.DateTimeTests) ... ok CheckSqliteTimestamp (sqlite3.test.types.DateTimeTests) ... ok CheckFuncErrorOnCreate (sqlite3.test.userfunctions.FunctionTests) ... ok CheckFuncException (sqlite3.test.userfunctions.FunctionTests) ... ok CheckFuncRefCount (sqlite3.test.userfunctions.FunctionTests) ... ok CheckFuncReturnBlob (sqlite3.test.userfunctions.FunctionTests) ... ok CheckFuncReturnFloat (sqlite3.test.userfunctions.FunctionTests) ... ok CheckFuncReturnInt (sqlite3.test.userfunctions.FunctionTests) ... ok CheckFuncReturnNull (sqlite3.test.userfunctions.FunctionTests) ... ok CheckFuncReturnText (sqlite3.test.userfunctions.FunctionTests) ... ok CheckFuncReturnUnicode (sqlite3.test.userfunctions.FunctionTests) ... ok CheckParamBlob (sqlite3.test.userfunctions.FunctionTests) ... ok CheckParamFloat (sqlite3.test.userfunctions.FunctionTests) ... ok CheckParamInt (sqlite3.test.userfunctions.FunctionTests) ... ok CheckParamNone (sqlite3.test.userfunctions.FunctionTests) ... ok CheckParamString (sqlite3.test.userfunctions.FunctionTests) ... ok CheckAggrCheckAggrSum (sqlite3.test.userfunctions.AggregateTests) ... ok CheckAggrCheckParamBlob (sqlite3.test.userfunctions.AggregateTests) ... ok CheckAggrCheckParamFloat (sqlite3.test.userfunctions.AggregateTests) ... ok CheckAggrCheckParamInt (sqlite3.test.userfunctions.AggregateTests) ... ok CheckAggrCheckParamNone (sqlite3.test.userfunctions.AggregateTests) ... ok CheckAggrCheckParamStr (sqlite3.test.userfunctions.AggregateTests) ... ok CheckAggrErrorOnCreate (sqlite3.test.userfunctions.AggregateTests) ... ok CheckAggrExceptionInFinalize (sqlite3.test.userfunctions.AggregateTests) ... ok CheckAggrExceptionInInit (sqlite3.test.userfunctions.AggregateTests) ... ok CheckAggrExceptionInStep (sqlite3.test.userfunctions.AggregateTests) ... ok CheckAggrNoFinalize (sqlite3.test.userfunctions.AggregateTests) ... ok CheckAggrNoStep (sqlite3.test.userfunctions.AggregateTests) ... ok CheckColumnAccess (sqlite3.test.userfunctions.AuthorizerTests) ... ok CheckTableAccess (sqlite3.test.userfunctions.AuthorizerTests) ... ok CheckContextManager (sqlite3.test.py25tests.ContextTests) Can the connection be used as a context manager at all? ... ok CheckContextManagerCommit (sqlite3.test.py25tests.ContextTests) Is a commit called in the context manager? ... ok CheckContextManagerRollback (sqlite3.test.py25tests.ContextTests) Is a rollback called in the context manager? ... ok CheckIsInstance (sqlite3.test.factory.ConnectionFactoryTests) ... ok CheckIsInstance (sqlite3.test.factory.CursorFactoryTests) ... ok CheckIsProducedByFactory (sqlite3.test.factory.RowFactoryTestsBackwardsCompat) ... ok CheckCustomFactory (sqlite3.test.factory.RowFactoryTests) ... ok CheckSqliteRowAsDict (sqlite3.test.factory.RowFactoryTests) Checks if the row object can be correctly converted to a dictionary ... ok CheckSqliteRowAsTuple (sqlite3.test.factory.RowFactoryTests) Checks if the row object can be converted to a tuple ... ok CheckSqliteRowHashCmp (sqlite3.test.factory.RowFactoryTests) Checks if the row object compares and hashes correctly ... ok CheckSqliteRowIndex (sqlite3.test.factory.RowFactoryTests) ... ok CheckSqliteRowIter (sqlite3.test.factory.RowFactoryTests) Checks if the row object is iterable ... ok CheckCustom (sqlite3.test.factory.TextFactoryTests) ... ok CheckOptimizedUnicode (sqlite3.test.factory.TextFactoryTests) ... ok CheckString (sqlite3.test.factory.TextFactoryTests) ... ok CheckUnicode (sqlite3.test.factory.TextFactoryTests) ... ok CheckDMLdoesAutoCommitBefore (sqlite3.test.transactions.TransactionTests) ... ok CheckDeleteStartsTransaction (sqlite3.test.transactions.TransactionTests) ... ok CheckInsertStartsTransaction (sqlite3.test.transactions.TransactionTests) ... ok CheckLocking (sqlite3.test.transactions.TransactionTests) ... ok CheckRaiseTimeout (sqlite3.test.transactions.TransactionTests) ... ok CheckReplaceStartsTransaction (sqlite3.test.transactions.TransactionTests) ... ok CheckRollbackCursorConsistency (sqlite3.test.transactions.TransactionTests) ... ok CheckToggleAutoCommit (sqlite3.test.transactions.TransactionTests) ... ok CheckUpdateStartsTransaction (sqlite3.test.transactions.TransactionTests) ... ok CheckDropTable (sqlite3.test.transactions.SpecialCommandTests) ... ok CheckPragma (sqlite3.test.transactions.SpecialCommandTests) ... ok CheckVacuum (sqlite3.test.transactions.SpecialCommandTests) ... ok CheckCollationIsUsed (sqlite3.test.hooks.CollationTests) ... ok CheckCollationRegisterTwice (sqlite3.test.hooks.CollationTests) ... ok CheckCreateCollationNotAscii (sqlite3.test.hooks.CollationTests) ... ok CheckCreateCollationNotCallable (sqlite3.test.hooks.CollationTests) ... ok CheckDeregisterCollation (sqlite3.test.hooks.CollationTests) ... ok CheckCancelOperation (sqlite3.test.hooks.ProgressTests) ... ok CheckClearHandler (sqlite3.test.hooks.ProgressTests) ... ok CheckOpcodeCount (sqlite3.test.hooks.ProgressTests) ... ok CheckProgressHandlerUsed (sqlite3.test.hooks.ProgressTests) ... ok CheckAutoCommit (sqlite3.test.regression.RegressionTests) ... ok CheckColumnNameWithSpaces (sqlite3.test.regression.RegressionTests) ... ok CheckConnectionCall (sqlite3.test.regression.RegressionTests) ... ok CheckConnectionConstructorCallCheck (sqlite3.test.regression.RegressionTests) ... ok CheckCursorConstructorCallCheck (sqlite3.test.regression.RegressionTests) ... ok CheckCursorRegistration (sqlite3.test.regression.RegressionTests) ... ok CheckEmptyStatement (sqlite3.test.regression.RegressionTests) ... ok CheckOnConflictRollback (sqlite3.test.regression.RegressionTests) ... ok CheckPragmaAutocommit (sqlite3.test.regression.RegressionTests) ... ok CheckPragmaSchemaVersion (sqlite3.test.regression.RegressionTests) ... ok CheckPragmaUserVersion (sqlite3.test.regression.RegressionTests) ... ok CheckRegisterAdapter (sqlite3.test.regression.RegressionTests) ... ok CheckSetDict (sqlite3.test.regression.RegressionTests) ... ok CheckSetIsolationLevel (sqlite3.test.regression.RegressionTests) ... ok CheckStatementFinalizationOnCloseDb (sqlite3.test.regression.RegressionTests) ... ok CheckStatementReset (sqlite3.test.regression.RegressionTests) ... ok CheckTypeMapUsage (sqlite3.test.regression.RegressionTests) ... ok CheckUnicodeConnect (sqlite3.test.regression.RegressionTests) ... ok CheckWorkaroundForBuggySqliteTransferBindings (sqlite3.test.regression.RegressionTests) ... ok CheckTableDump (sqlite3.test.dump.DumpTests) ... ok ====================================================================== FAIL: CheckSqlTimestamp (sqlite3.test.types.DateTimeTests) ---------------------------------------------------------------------- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/sqlite3/test/types.py", line 388, in CheckSqlTimestamp self.assertEqual(ts.year, now.year) AssertionError: 2011 != 2010 ---------------------------------------------------------------------- Ran 214 tests in 0.317s FAILED (failures=1) test test_sqlite failed -- Traceback (most recent call last): File "/tmp/python-test/local/lib/python2.7/sqlite3/test/types.py", line 388, in CheckSqlTimestamp self.assertEqual(ts.year, now.year) AssertionError: 2011 != 2010 test_ssl test_startfile test_startfile skipped -- module os has no attribute startfile test_str test_strftime test_string test_stringprep test_strop test_strptime test_strtod test_struct test_structmembers test_structseq test_subprocess [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15863 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] . [15648 refs] [15648 refs] this bit of output is from a test of stdout in a different process ... [15648 refs] [15648 refs] [15863 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15863 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] [15648 refs] . [15648 refs] [15648 refs] this bit of output is from a test of stdout in a different process ... [15648 refs] [15648 refs] [15863 refs] test_sunaudiodev test_sunaudiodev skipped -- No module named sunaudiodev test_sundry test_symtable test_syntax test_sys [15648 refs] [15648 refs] [15648 refs] [15877 refs] [15671 refs] test_sysconfig [15648 refs] [15648 refs] test_tarfile test_tcl test_tcl skipped -- No module named _tkinter test_telnetlib test_tempfile [15648 refs] test_textwrap test_thread test_threaded_import test_threadedtempfile test_threading [18948 refs] [20223 refs] [20035 refs] [20035 refs] [20035 refs] [20035 refs] test_threading_local test_threadsignals test_time test_timeout test_tk test_tk skipped -- No module named _tkinter test_tokenize test_trace test_traceback test_transformer test_ttk_guionly test_ttk_guionly skipped -- No module named _tkinter test_ttk_textonly test_ttk_textonly skipped -- No module named _tkinter test_tuple test_typechecks test_ucn test_unary test_undocumented_details test_unicode test_unicode_file test_unicode_file skipped -- No Unicode filesystem semantics on this platform. test_unicodedata test_univnewlines test_univnewlines2k test_unpack test_urllib test_urllib2 test_urllib2_localnet test_urllib2net test_urllibnet test_urlparse test_userdict test_userlist test_userstring test_uu test_uuid test_wait3 test_wait4 test_warnings [15679 refs] [15679 refs] [15672 refs] [15679 refs] [15679 refs] [15672 refs] test_wave test_weakref test_weakset test_whichdb test_winreg test_winreg skipped -- No module named _winreg test_winsound test_winsound skipped -- No module named winsound test_with test_wsgiref test_xdrlib test_xml_etree test_xml_etree_c test_xmllib test_xmlrpc test_xpickle sh: line 1: python2.4: command not found sh: line 1: python2.6: command not found test_xrange test_zipfile test_zipfile64 test_zipfile64 skipped -- test requires loads of disk-space bytes and a long time to run test_zipimport test_zipimport_support test_zlib 352 tests OK. 1 test failed: test_sqlite 28 tests skipped: test_aepack test_al test_applesingle test_bsddb185 test_cd test_cl test_epoll test_gdb test_gl test_imgfile test_ioctl test_kqueue test_macos test_macostools test_multiprocessing test_pep277 test_py3kwarn test_scriptpackages test_startfile test_sunaudiodev test_tcl test_tk test_ttk_guionly test_ttk_textonly test_unicode_file test_winreg test_winsound test_zipfile64 7 skips unexpected on linux2: test_epoll test_gdb test_ioctl test_multiprocessing test_tk test_ttk_guionly test_ttk_textonly [985087 refs] From python-checkins at python.org Sat Jan 1 03:25:36 2011 From: python-checkins at python.org (terry.reedy) Date: Sat, 1 Jan 2011 03:25:36 +0100 (CET) Subject: [Python-checkins] r87598 - python/branches/py3k/Lib/idlelib/EditorWindow.py Message-ID: <20110101022536.637D8EE9A0@mail.python.org> Author: terry.reedy Date: Sat Jan 1 03:25:36 2011 New Revision: 87598 Log: Issue 6285: catch missing IDLE help file. Modified: python/branches/py3k/Lib/idlelib/EditorWindow.py Modified: python/branches/py3k/Lib/idlelib/EditorWindow.py ============================================================================== --- python/branches/py3k/Lib/idlelib/EditorWindow.py (original) +++ python/branches/py3k/Lib/idlelib/EditorWindow.py Sat Jan 1 03:25:36 2011 @@ -450,7 +450,11 @@ def python_docs(self, event=None): if sys.platform[:3] == 'win': - os.startfile(self.help_url) + try: + os.startfile(self.help_url) + except WindowsError as why: + tkMessageBox.showerror(title='Document Start Failure', + message=str(why), parent=self.text) else: webbrowser.open(self.help_url) return "break" @@ -753,9 +757,13 @@ "Create a callback with the helpfile value frozen at definition time" def display_extra_help(helpfile=helpfile): if not helpfile.startswith(('www', 'http')): - url = os.path.normpath(helpfile) + helpfile = os.path.normpath(helpfile) if sys.platform[:3] == 'win': - os.startfile(helpfile) + try: + os.startfile(helpfile) + except WindowsError as why: + tkMessageBox.showerror(title='Document Start Failure', + message=str(why), parent=self.text) else: webbrowser.open(helpfile) return display_extra_help From python-checkins at python.org Sat Jan 1 03:28:54 2011 From: python-checkins at python.org (terry.reedy) Date: Sat, 1 Jan 2011 03:28:54 +0100 (CET) Subject: [Python-checkins] r87599 - python/branches/release31-maint/Lib/idlelib/EditorWindow.py Message-ID: <20110101022854.C2CD0EE9A0@mail.python.org> Author: terry.reedy Date: Sat Jan 1 03:28:54 2011 New Revision: 87599 Log: Issue 6285: catch missing IDLE help file. Modified: python/branches/release31-maint/Lib/idlelib/EditorWindow.py Modified: python/branches/release31-maint/Lib/idlelib/EditorWindow.py ============================================================================== --- python/branches/release31-maint/Lib/idlelib/EditorWindow.py (original) +++ python/branches/release31-maint/Lib/idlelib/EditorWindow.py Sat Jan 1 03:28:54 2011 @@ -451,7 +451,11 @@ def python_docs(self, event=None): if sys.platform[:3] == 'win': - os.startfile(self.help_url) + try: + os.startfile(self.help_url) + except WindowsError as why: + tkMessageBox.showerror(title='Document Start Failure', + message=str(why), parent=self.text) else: webbrowser.open(self.help_url) return "break" @@ -754,9 +758,13 @@ "Create a callback with the helpfile value frozen at definition time" def display_extra_help(helpfile=helpfile): if not helpfile.startswith(('www', 'http')): - url = os.path.normpath(helpfile) + helpfile = os.path.normpath(helpfile) if sys.platform[:3] == 'win': - os.startfile(helpfile) + try: + os.startfile(helpfile) + except WindowsError as why: + tkMessageBox.showerror(title='Document Start Failure', + message=str(why), parent=self.text) else: webbrowser.open(helpfile) return display_extra_help From python-checkins at python.org Sat Jan 1 03:32:46 2011 From: python-checkins at python.org (terry.reedy) Date: Sat, 1 Jan 2011 03:32:46 +0100 (CET) Subject: [Python-checkins] r87600 - python/branches/release27-maint/Lib/idlelib/EditorWindow.py Message-ID: <20110101023246.64363EE987@mail.python.org> Author: terry.reedy Date: Sat Jan 1 03:32:46 2011 New Revision: 87600 Log: Issue 6285: catch missing IDLE help file. Backport from 3.2. Modified: python/branches/release27-maint/Lib/idlelib/EditorWindow.py Modified: python/branches/release27-maint/Lib/idlelib/EditorWindow.py ============================================================================== --- python/branches/release27-maint/Lib/idlelib/EditorWindow.py (original) +++ python/branches/release27-maint/Lib/idlelib/EditorWindow.py Sat Jan 1 03:32:46 2011 @@ -452,7 +452,11 @@ def python_docs(self, event=None): if sys.platform[:3] == 'win': - os.startfile(self.help_url) + try: + os.startfile(self.help_url) + except WindowsError as why: + tkMessageBox.showerror(title='Document Start Failure', + message=str(why), parent=self.text) else: webbrowser.open(self.help_url) return "break" @@ -747,9 +751,13 @@ "Create a callback with the helpfile value frozen at definition time" def display_extra_help(helpfile=helpfile): if not helpfile.startswith(('www', 'http')): - url = os.path.normpath(helpfile) + helpfile = os.path.normpath(helpfile) if sys.platform[:3] == 'win': - os.startfile(helpfile) + try: + os.startfile(helpfile) + except WindowsError as why: + tkMessageBox.showerror(title='Document Start Failure', + message=str(why), parent=self.text) else: webbrowser.open(helpfile) return display_extra_help From python-checkins at python.org Sat Jan 1 03:54:11 2011 From: python-checkins at python.org (terry.reedy) Date: Sat, 1 Jan 2011 03:54:11 +0100 (CET) Subject: [Python-checkins] r87601 - python/branches/py3k/Misc/NEWS Message-ID: <20110101025411.4710EEEA8B@mail.python.org> Author: terry.reedy Date: Sat Jan 1 03:54:11 2011 New Revision: 87601 Log: Modified: python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 1 03:54:11 2011 @@ -20,6 +20,9 @@ Library ------- +- Issue 6285: IDLE no longer crashes on missing help file; patch by Scott David + Daniels. + - Fix collections.OrderedDict.setdefault() so that it works in subclasses that define __missing__(). From python-checkins at python.org Sat Jan 1 03:59:12 2011 From: python-checkins at python.org (terry.reedy) Date: Sat, 1 Jan 2011 03:59:12 +0100 (CET) Subject: [Python-checkins] r87601 - svn:log Message-ID: <20110101025912.25ADEEE99B@mail.python.org> Author: terry.reedy Revision: 87601 Property Name: svn:log Action: modified Property diff: --- old property value +++ new property value @@ -0,0 +1 @@ +Issue 6285: add NEWS entry for 3.2 \ No newline at end of file From python-checkins at python.org Sat Jan 1 04:47:24 2011 From: python-checkins at python.org (terry.reedy) Date: Sat, 1 Jan 2011 04:47:24 +0100 (CET) Subject: [Python-checkins] r87601 - svn:log Message-ID: <20110101034724.7E147EE9D8@mail.python.org> Author: terry.reedy Revision: 87601 Property Name: svn:log Action: modified Property diff: --- old property value +++ new property value @@ -1 +1 @@ -Issue 6285: add NEWS entry for 3.2 \ No newline at end of file +Issue 6285: add NEWS entry for 3.2. From solipsis at pitrou.net Sat Jan 1 04:55:21 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 01 Jan 2011 04:55:21 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r87598): sum=0 Message-ID: py3k results for svn r87598 (hg cset d166e319d298) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflogD-6Thw', '-x'] From python-checkins at python.org Sat Jan 1 05:32:14 2011 From: python-checkins at python.org (richard.tew) Date: Sat, 1 Jan 2011 05:32:14 +0100 (CET) Subject: [Python-checkins] r87602 - svn:log Message-ID: <20110101043214.F178CEEB0B@mail.python.org> Author: richard.tew Revision: 87602 Property Name: svn:log Action: modified Property diff: --- old property value +++ new property value @@ -8717,8 +8717,3 @@ 2.7.1 final version bump ................ - -Remaining work before release: -- 'test__all__' modifies the environment and raises a flag in Python unit test execution. -- 'configure' needs to be rebuilt. -- Kristjan wants to check in some changes to get them included. \ No newline at end of file From python-checkins at python.org Sat Jan 1 10:06:37 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 01 Jan 2011 10:06:37 +0100 Subject: [Python-checkins] distutils2: allowing predicates without parenthesis -- that's how the install script will Message-ID: tarek.ziade pushed edb34bfee375 to distutils2: http://hg.python.org/distutils2/rev/edb34bfee375 changeset: 853:edb34bfee375 tag: tip user: Tarek Ziade date: Sat Jan 01 10:05:56 2011 +0100 summary: allowing predicates without parenthesis -- that's how the install script will work files: distutils2/tests/test_version.py distutils2/version.py diff --git a/distutils2/tests/test_version.py b/distutils2/tests/test_version.py --- a/distutils2/tests/test_version.py +++ b/distutils2/tests/test_version.py @@ -196,6 +196,8 @@ self.assertRaises(ValueError, VersionPredicate, '') + self.assertTrue(VersionPredicate('Hey 2.5').match('2.5.1')) + # XXX need to silent the micro version in this case #assert not VersionPredicate('Ho (<3.0,!=2.6)').match('2.6.3') @@ -220,6 +222,7 @@ for version in other_versions: self.assertFalse(V(version).is_final) + class VersionWhiteBoxTestCase(unittest.TestCase): def test_parse_numdots(self): diff --git a/distutils2/version.py b/distutils2/version.py --- a/distutils2/version.py +++ b/distutils2/version.py @@ -323,7 +323,7 @@ _PREDICATE = re.compile(r"(?i)^\s*([a-z_][\sa-zA-Z_-]*(?:\.[a-z_]\w*)*)(.*)") -_VERSIONS = re.compile(r"^\s*\((.*)\)\s*$") +_VERSIONS = re.compile(r"^\s*\((?P.*)\)\s*$|^\s*(?P.*)\s*$") _PLAIN_VERSIONS = re.compile(r"^\s*(.*)\s*$") _SPLIT_CMP = re.compile(r"^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$") @@ -358,14 +358,20 @@ name, predicates = match.groups() self.name = name.strip() - predicates = predicates.strip() - predicates = _VERSIONS.match(predicates) + self.predicates = [] + predicates = _VERSIONS.match(predicates.strip()) if predicates is not None: - predicates = predicates.groups()[0] - self.predicates = [_split_predicate(pred.strip()) - for pred in predicates.split(',')] - else: - self.predicates = [] + predicates = predicates.groupdict() + if predicates['versions'] is not None: + versions = predicates['versions'] + else: + versions = predicates.get('versions2') + + if versions is not None: + for version in versions.split(','): + if version.strip() == '': + continue + self.predicates.append(_split_predicate(version)) def match(self, version): """Check if the provided version matches the predicates.""" -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 1 10:48:12 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 01 Jan 2011 10:48:12 +0100 Subject: [Python-checkins] distutils2: added a log Message-ID: tarek.ziade pushed 9ddc3c5388e6 to distutils2: http://hg.python.org/distutils2/rev/9ddc3c5388e6 changeset: 855:9ddc3c5388e6 user: Tarek Ziade date: Sat Jan 01 10:14:04 2011 +0100 summary: added a log files: distutils2/index/simple.py diff --git a/distutils2/index/simple.py b/distutils2/index/simple.py --- a/distutils2/index/simple.py +++ b/distutils2/index/simple.py @@ -14,6 +14,7 @@ import logging import os +from distutils2 import logger from distutils2.index.base import BaseClient from distutils2.index.dist import (ReleasesList, EXTENSIONS, get_infos_from_url, MD5_HASH) @@ -167,6 +168,7 @@ if predicate.name.lower() in self._projects and not force_update: return self._projects.get(predicate.name.lower()) prefer_final = self._get_prefer_final(prefer_final) + logger.info('Reading info on PyPI about %s' % predicate.name) self._process_index_page(predicate.name) if predicate.name.lower() not in self._projects: -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 1 10:48:12 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 01 Jan 2011 10:48:12 +0100 Subject: [Python-checkins] distutils2: make sure get_last() returns None in case no release matches Message-ID: tarek.ziade pushed 4ee28ba88ed4 to distutils2: http://hg.python.org/distutils2/rev/4ee28ba88ed4 changeset: 854:4ee28ba88ed4 user: Tarek Ziade date: Sat Jan 01 10:13:28 2011 +0100 summary: make sure get_last() returns None in case no release matches files: distutils2/index/dist.py distutils2/tests/test_index_dist.py diff --git a/distutils2/index/dist.py b/distutils2/index/dist.py --- a/distutils2/index/dist.py +++ b/distutils2/index/dist.py @@ -376,6 +376,8 @@ """ predicate = get_version_predicate(requirements) releases = self.filter(predicate) + if len(releases) == 0: + return None releases.sort_releases(prefer_final, reverse=True) return releases[0] diff --git a/distutils2/tests/test_index_dist.py b/distutils2/tests/test_index_dist.py --- a/distutils2/tests/test_index_dist.py +++ b/distutils2/tests/test_index_dist.py @@ -237,6 +237,10 @@ # dists.sort_distributions(prefer_source=True) # self.assertEqual(fb2_binary, dists[0]) + def test_get_last(self): + dists = ReleasesList('Foo') + self.assertEqual(dists.get_last('Foo 1.0'), None) + def test_suite(): suite = unittest.TestSuite() -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 1 10:48:12 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 01 Jan 2011 10:48:12 +0100 Subject: [Python-checkins] distutils2: make sure project that have numbers in their names can be parsed Message-ID: tarek.ziade pushed 0de7d5f4dae5 to distutils2: http://hg.python.org/distutils2/rev/0de7d5f4dae5 changeset: 856:0de7d5f4dae5 tag: tip user: Tarek Ziade date: Sat Jan 01 10:47:44 2011 +0100 summary: make sure project that have numbers in their names can be parsed files: distutils2/tests/test_version.py distutils2/version.py diff --git a/distutils2/tests/test_version.py b/distutils2/tests/test_version.py --- a/distutils2/tests/test_version.py +++ b/distutils2/tests/test_version.py @@ -201,6 +201,15 @@ # XXX need to silent the micro version in this case #assert not VersionPredicate('Ho (<3.0,!=2.6)').match('2.6.3') + + # Make sure a predicate that ends with a number works + self.assertTrue(VersionPredicate('virtualenv5 (1.0)').match('1.0')) + self.assertTrue(VersionPredicate('virtualenv5').match('1.0')) + self.assertTrue(VersionPredicate('vi5two').match('1.0')) + self.assertTrue(VersionPredicate('5two').match('1.0')) + self.assertTrue(VersionPredicate('vi5two 1.0').match('1.0')) + self.assertTrue(VersionPredicate('5two 1.0').match('1.0')) + # test repr for predicate in predicates: self.assertEqual(str(VersionPredicate(predicate)), predicate) diff --git a/distutils2/version.py b/distutils2/version.py --- a/distutils2/version.py +++ b/distutils2/version.py @@ -322,7 +322,8 @@ return None -_PREDICATE = re.compile(r"(?i)^\s*([a-z_][\sa-zA-Z_-]*(?:\.[a-z_]\w*)*)(.*)") +# A predicate is: "ProjectName (VERSION1, VERSION2, ..) +_PREDICATE = re.compile(r"(?i)^\s*(\w[\s\w-]*(?:\.\w*)*)(.*)") _VERSIONS = re.compile(r"^\s*\((?P.*)\)\s*$|^\s*(?P.*)\s*$") _PLAIN_VERSIONS = re.compile(r"^\s*(.*)\s*$") _SPLIT_CMP = re.compile(r"^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$") @@ -359,19 +360,24 @@ name, predicates = match.groups() self.name = name.strip() self.predicates = [] + if predicates is None: + return + predicates = _VERSIONS.match(predicates.strip()) - if predicates is not None: - predicates = predicates.groupdict() - if predicates['versions'] is not None: - versions = predicates['versions'] - else: - versions = predicates.get('versions2') + if predicates is None: + return - if versions is not None: - for version in versions.split(','): - if version.strip() == '': - continue - self.predicates.append(_split_predicate(version)) + predicates = predicates.groupdict() + if predicates['versions'] is not None: + versions = predicates['versions'] + else: + versions = predicates.get('versions2') + + if versions is not None: + for version in versions.split(','): + if version.strip() == '': + continue + self.predicates.append(_split_predicate(version)) def match(self, version): """Check if the provided version matches the predicates.""" -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 1 11:07:30 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 1 Jan 2011 11:07:30 +0100 (CET) Subject: [Python-checkins] r87603 - python/branches/py3k/Misc/NEWS Message-ID: <20110101100730.BE5B9EE987@mail.python.org> Author: georg.brandl Date: Sat Jan 1 11:07:30 2011 New Revision: 87603 Log: Fix issue references. Modified: python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 1 11:07:30 2011 @@ -20,27 +20,27 @@ Library ------- -- Issue 6285: IDLE no longer crashes on missing help file; patch by Scott David - Daniels. +- Issue #6285: IDLE no longer crashes on missing help file; patch by Scott + David Daniels. - Fix collections.OrderedDict.setdefault() so that it works in subclasses that define __missing__(). -- Issue 10786: unittest.TextTestRunner default stream no longer bound at - import time. `sys.stderr` now looked up at instantiation time. Fix contributed - by Mark Roddy. +- Issue #10786: unittest.TextTestRunner default stream no longer bound at + import time. `sys.stderr` now looked up at instantiation time. Fix + contributed by Mark Roddy. -- Issue 10753 - Characters ';','=' and ',' in the PATH_INFO environment +- Issue #10753: Characters ';','=' and ',' in the PATH_INFO environment variable won't be quoted when the URI is constructed by the wsgiref.util 's request_uri method. According to RFC 3986, these characters can be a part of params in PATH component of URI and need not be quoted. -- Issue 10738: Fix webbrowser.Opera.raise_opts +- Issue #10738: Fix webbrowser.Opera.raise_opts. -- Issue 9824: SimpleCookie now encodes , and ; in values to cater to how +- Issue #9824: SimpleCookie now encodes , and ; in values to cater to how browsers actually parse cookies. -- Issue 9333: os.symlink now available regardless of user privileges. +- Issue #9333: os.symlink now available regardless of user privileges. The function now raises OSError on Windows >=6.0 when the user is unable to create symbolic links. XP and 2003 still raise NotImplementedError. From python-checkins at python.org Sat Jan 1 11:09:32 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 1 Jan 2011 11:09:32 +0100 (CET) Subject: [Python-checkins] r87604 - in python/branches/py3k: Lib/test/test_zipfile.py Lib/test/zip_cp437_header.zip Lib/zipfile.py Misc/NEWS Message-ID: <20110101100932.C595DEE9E1@mail.python.org> Author: georg.brandl Date: Sat Jan 1 11:09:32 2011 New Revision: 87604 Log: #10801: In zipfile, support different encodings for the header and the filenames. Patch by MvL, test by Eli Bendersky. Added: python/branches/py3k/Lib/test/zip_cp437_header.zip (contents, props changed) Modified: python/branches/py3k/Lib/test/test_zipfile.py python/branches/py3k/Lib/zipfile.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/test/test_zipfile.py ============================================================================== --- python/branches/py3k/Lib/test/test_zipfile.py (original) +++ python/branches/py3k/Lib/test/test_zipfile.py Sat Jan 1 11:09:32 2011 @@ -6,6 +6,7 @@ import io import os +import sys import imp import time import shutil @@ -23,6 +24,7 @@ TESTFN2 = TESTFN + "2" TESTFNDIR = TESTFN + "d" FIXEDTEST_SIZE = 1000 +DATAFILES_DIR = 'zipfile_datafiles' SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'), ('ziptest2dir/_ziptest2', 'qawsedrftg'), @@ -487,6 +489,18 @@ except zipfile.BadZipFile: self.assertTrue(zipfp2.fp is None, 'zipfp is not closed') + def test_unicode_filenames(self): + if __name__ == '__main__': + myfile = sys.argv[0] + else: + myfile = __file__ + + mydir = os.path.dirname(myfile) or os.curdir + fname = os.path.join(mydir, 'zip_cp437_header.zip') + + with zipfile.ZipFile(fname) as zipfp: + zipfp.extractall() + def tearDown(self): unlink(TESTFN) unlink(TESTFN2) Added: python/branches/py3k/Lib/test/zip_cp437_header.zip ============================================================================== Binary file. No diff available. Modified: python/branches/py3k/Lib/zipfile.py ============================================================================== --- python/branches/py3k/Lib/zipfile.py (original) +++ python/branches/py3k/Lib/zipfile.py Sat Jan 1 11:09:32 2011 @@ -930,7 +930,13 @@ if fheader[_FH_EXTRA_FIELD_LENGTH]: zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH]) - if fname != zinfo.orig_filename.encode("utf-8"): + if zinfo.flag_bits & 0x800: + # UTF-8 filename + fname_str = fname.decode("utf-8") + else: + fname_str = fname.decode("cp437") + + if fname_str != zinfo.orig_filename: if not self._filePassed: zef_file.close() raise BadZipFile( Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 1 11:09:32 2011 @@ -20,6 +20,9 @@ Library ------- +- Issue #10801: In zipfile, support different encodings for the header and + the filenames. + - Issue #6285: IDLE no longer crashes on missing help file; patch by Scott David Daniels. From python-checkins at python.org Sat Jan 1 11:42:32 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 1 Jan 2011 11:42:32 +0100 (CET) Subject: [Python-checkins] r87606 - python/branches/py3k/Lib/test/test_zipfile.py Message-ID: <20110101104232.09AFAEE9A3@mail.python.org> Author: georg.brandl Date: Sat Jan 1 11:42:31 2011 New Revision: 87606 Log: #10801: do not actually extract, just open() the files in the test zipfile. Modified: python/branches/py3k/Lib/test/test_zipfile.py Modified: python/branches/py3k/Lib/test/test_zipfile.py ============================================================================== --- python/branches/py3k/Lib/test/test_zipfile.py (original) +++ python/branches/py3k/Lib/test/test_zipfile.py Sat Jan 1 11:42:31 2011 @@ -490,16 +490,11 @@ self.assertTrue(zipfp2.fp is None, 'zipfp is not closed') def test_unicode_filenames(self): - if __name__ == '__main__': - myfile = sys.argv[0] - else: - myfile = __file__ - - mydir = os.path.dirname(myfile) or os.curdir - fname = os.path.join(mydir, 'zip_cp437_header.zip') - + # bug #10801 + fname = findfile('zip_cp437_header.zip') with zipfile.ZipFile(fname) as zipfp: - zipfp.extractall() + for name in zipfp.namelist(): + zipfp.open(name).close() def tearDown(self): unlink(TESTFN) From python-checkins at python.org Sat Jan 1 15:28:32 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 1 Jan 2011 15:28:32 +0100 (CET) Subject: [Python-checkins] r87607 - python/branches/py3k/Python/getcopyright.c Message-ID: <20110101142832.3515BEE98A@mail.python.org> Author: benjamin.peterson Date: Sat Jan 1 15:28:31 2011 New Revision: 87607 Log: update copyright to 2011 Modified: python/branches/py3k/Python/getcopyright.c Modified: python/branches/py3k/Python/getcopyright.c ============================================================================== --- python/branches/py3k/Python/getcopyright.c (original) +++ python/branches/py3k/Python/getcopyright.c Sat Jan 1 15:28:31 2011 @@ -4,7 +4,7 @@ static char cprt[] = "\ -Copyright (c) 2001-2010 Python Software Foundation.\n\ +Copyright (c) 2001-2011 Python Software Foundation.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 2000 BeOpen.com.\n\ From python-checkins at python.org Sat Jan 1 15:30:24 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 1 Jan 2011 15:30:24 +0100 (CET) Subject: [Python-checkins] r87608 - in python/branches/release27-maint: Python/getcopyright.c Message-ID: <20110101143024.7E149EE98A@mail.python.org> Author: benjamin.peterson Date: Sat Jan 1 15:30:24 2011 New Revision: 87608 Log: Merged revisions 87607 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87607 | benjamin.peterson | 2011-01-01 08:28:31 -0600 (Sat, 01 Jan 2011) | 1 line update copyright to 2011 ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Python/getcopyright.c Modified: python/branches/release27-maint/Python/getcopyright.c ============================================================================== --- python/branches/release27-maint/Python/getcopyright.c (original) +++ python/branches/release27-maint/Python/getcopyright.c Sat Jan 1 15:30:24 2011 @@ -4,7 +4,7 @@ static char cprt[] = "\ -Copyright (c) 2001-2010 Python Software Foundation.\n\ +Copyright (c) 2001-2011 Python Software Foundation.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 2000 BeOpen.com.\n\ From python-checkins at python.org Sat Jan 1 16:32:26 2011 From: python-checkins at python.org (benjamin.peterson) Date: Sat, 1 Jan 2011 16:32:26 +0100 (CET) Subject: [Python-checkins] r87609 - in python/branches/release31-maint: Python/getcopyright.c Message-ID: <20110101153226.74922EE983@mail.python.org> Author: benjamin.peterson Date: Sat Jan 1 16:32:26 2011 New Revision: 87609 Log: Merged revisions 87607 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87607 | benjamin.peterson | 2011-01-01 08:28:31 -0600 (Sat, 01 Jan 2011) | 1 line update copyright to 2011 ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Python/getcopyright.c Modified: python/branches/release31-maint/Python/getcopyright.c ============================================================================== --- python/branches/release31-maint/Python/getcopyright.c (original) +++ python/branches/release31-maint/Python/getcopyright.c Sat Jan 1 16:32:26 2011 @@ -4,7 +4,7 @@ static char cprt[] = "\ -Copyright (c) 2001-2010 Python Software Foundation.\n\ +Copyright (c) 2001-2011 Python Software Foundation.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 2000 BeOpen.com.\n\ From python-checkins at python.org Sat Jan 1 22:18:46 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sat, 1 Jan 2011 22:18:46 +0100 (CET) Subject: [Python-checkins] r87610 - python/branches/py3k/Include/patchlevel.h Message-ID: <20110101211846.63121EE981@mail.python.org> Author: gregory.p.smith Date: Sat Jan 1 22:18:46 2011 New Revision: 87610 Log: post release bump Modified: python/branches/py3k/Include/patchlevel.h Modified: python/branches/py3k/Include/patchlevel.h ============================================================================== --- python/branches/py3k/Include/patchlevel.h (original) +++ python/branches/py3k/Include/patchlevel.h Sat Jan 1 22:18:46 2011 @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.2b2" +#define PY_VERSION "3.2b2+" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository) */ From python-checkins at python.org Sat Jan 1 23:38:00 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 1 Jan 2011 23:38:00 +0100 (CET) Subject: [Python-checkins] r87611 - in python/branches/py3k/Lib: collections.py test/test_collections.py Message-ID: <20110101223800.55157EE9B4@mail.python.org> Author: raymond.hettinger Date: Sat Jan 1 23:38:00 2011 New Revision: 87611 Log: Make it easier to extend OrderedDict without breaking it. Modified: python/branches/py3k/Lib/collections.py python/branches/py3k/Lib/test/test_collections.py Modified: python/branches/py3k/Lib/collections.py ============================================================================== --- python/branches/py3k/Lib/collections.py (original) +++ python/branches/py3k/Lib/collections.py Sat Jan 1 23:38:00 2011 @@ -52,7 +52,7 @@ self.__root = root = _proxy(self.__hardroot) root.prev = root.next = root self.__map = {} - self.update(*args, **kwds) + self.__update(*args, **kwds) def __setitem__(self, key, value, dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link): @@ -171,7 +171,7 @@ size += sizeof(self.__root) * n # proxy objects return size - update = MutableMapping.update + update = __update = MutableMapping.update pop = MutableMapping.pop keys = MutableMapping.keys values = MutableMapping.values Modified: python/branches/py3k/Lib/test/test_collections.py ============================================================================== --- python/branches/py3k/Lib/test/test_collections.py (original) +++ python/branches/py3k/Lib/test/test_collections.py Sat Jan 1 23:38:00 2011 @@ -1012,6 +1012,14 @@ od = OrderedDict(**d) self.assertGreater(sys.getsizeof(od), sys.getsizeof(d)) + def test_override_update(self): + # Verify that subclasses can override update() without breaking __init__() + class MyOD(OrderedDict): + def update(self, *args, **kwds): + raise Exception() + items = [('a', 1), ('c', 3), ('b', 2)] + self.assertEqual(list(MyOD(items).items()), items) + class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): type2test = OrderedDict From python-checkins at python.org Sun Jan 2 00:51:55 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 2 Jan 2011 00:51:55 +0100 (CET) Subject: [Python-checkins] r87612 - in python/branches/py3k/Lib: collections.py test/test_collections.py Message-ID: <20110101235155.59973EE981@mail.python.org> Author: raymond.hettinger Date: Sun Jan 2 00:51:55 2011 New Revision: 87612 Log: Fix OrderedDic.pop() to work for subclasses that define __missing__(). Modified: python/branches/py3k/Lib/collections.py python/branches/py3k/Lib/test/test_collections.py Modified: python/branches/py3k/Lib/collections.py ============================================================================== --- python/branches/py3k/Lib/collections.py (original) +++ python/branches/py3k/Lib/collections.py Sun Jan 2 00:51:55 2011 @@ -22,7 +22,7 @@ class _Link(object): __slots__ = 'prev', 'next', 'key', '__weakref__' -class OrderedDict(dict, MutableMapping): +class OrderedDict(dict): 'Dictionary that remembers insertion order' # An inherited dict maps keys to values. # The inherited dict provides __getitem__, __len__, __contains__, and get. @@ -172,12 +172,22 @@ return size update = __update = MutableMapping.update - pop = MutableMapping.pop keys = MutableMapping.keys values = MutableMapping.values items = MutableMapping.items __ne__ = MutableMapping.__ne__ + __marker = object() + + def pop(self, key, default=__marker): + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + def setdefault(self, key, default=None): 'OD.setdefault(k[,d]) -> OD.get(k,d), also set OD[k]=d if k not in OD' if key in self: Modified: python/branches/py3k/Lib/test/test_collections.py ============================================================================== --- python/branches/py3k/Lib/test/test_collections.py (original) +++ python/branches/py3k/Lib/test/test_collections.py Sun Jan 2 00:51:55 2011 @@ -834,6 +834,10 @@ self.assertEqual(list(d.items()), [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)]) + def test_abc(self): + self.assertIsInstance(OrderedDict(), MutableMapping) + self.assertTrue(issubclass(OrderedDict, MutableMapping)) + def test_clear(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) @@ -892,6 +896,17 @@ self.assertEqual(len(od), 0) self.assertEqual(od.pop(k, 12345), 12345) + # make sure pop still works when __missing__ is defined + class Missing(OrderedDict): + def __missing__(self, key): + return 0 + m = Missing(a=1) + self.assertEqual(m.pop('b', 5), 5) + self.assertEqual(m.pop('a', 6), 1) + self.assertEqual(m.pop('a', 6), 6) + with self.assertRaises(KeyError): + m.pop('a') + def test_equality(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) From python-checkins at python.org Sun Jan 2 02:03:27 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 2 Jan 2011 02:03:27 +0100 (CET) Subject: [Python-checkins] r87613 - in python/branches/release27-maint: Lib/collections.py Lib/test/test_collections.py Misc/NEWS Message-ID: <20110102010327.5A6ABEE9C1@mail.python.org> Author: raymond.hettinger Date: Sun Jan 2 02:03:26 2011 New Revision: 87613 Log: Raymond-Hettingers-MacBook-Pro:py27 raymondhettinger$ cat svn-commit.tmp Backport r87594 r87611 and r87612 so that OrderedDict subclassing behavior better matches dict subclassing (i.e. adding __missing__ works and extending/overriding the update() methods doesn't break __init__()). Modified: python/branches/release27-maint/Lib/collections.py python/branches/release27-maint/Lib/test/test_collections.py python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Lib/collections.py ============================================================================== --- python/branches/release27-maint/Lib/collections.py (original) +++ python/branches/release27-maint/Lib/collections.py Sun Jan 2 02:03:26 2011 @@ -43,7 +43,7 @@ ### OrderedDict ################################################################################ -class OrderedDict(dict, MutableMapping): +class OrderedDict(dict): 'Dictionary that remembers insertion order' # An inherited dict maps keys to values. # The inherited dict provides __getitem__, __len__, __contains__, and get. @@ -71,7 +71,7 @@ NEXT = 1 root[PREV] = root[NEXT] = root self.__map = {} - self.update(*args, **kwds) + self.__update(*args, **kwds) def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__): 'od.__setitem__(i, y) <==> od[i]=y' @@ -134,9 +134,7 @@ pass dict.clear(self) - setdefault = MutableMapping.setdefault - update = MutableMapping.update - pop = MutableMapping.pop + update = __update = MutableMapping.update keys = MutableMapping.keys values = MutableMapping.values items = MutableMapping.items @@ -157,6 +155,24 @@ "od.viewitems() -> a set-like object providing a view on od's items" return ItemsView(self) + __marker = object() + + def pop(self, key, default=__marker): + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + def popitem(self, last=True): '''od.popitem() -> (k, v), return and remove a (key, value) pair. Pairs are returned in LIFO order if last is true or FIFO order if false. Modified: python/branches/release27-maint/Lib/test/test_collections.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_collections.py (original) +++ python/branches/release27-maint/Lib/test/test_collections.py Sun Jan 2 02:03:26 2011 @@ -812,6 +812,10 @@ self.assertEqual(list(d.items()), [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)]) + def test_abc(self): + self.assertIsInstance(OrderedDict(), MutableMapping) + self.assertTrue(issubclass(OrderedDict, MutableMapping)) + def test_clear(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) @@ -873,6 +877,17 @@ self.assertEqual(len(od), 0) self.assertEqual(od.pop(k, 12345), 12345) + # make sure pop still works when __missing__ is defined + class Missing(OrderedDict): + def __missing__(self, key): + return 0 + m = Missing(a=1) + self.assertEqual(m.pop('b', 5), 5) + self.assertEqual(m.pop('a', 6), 1) + self.assertEqual(m.pop('a', 6), 6) + with self.assertRaises(KeyError): + m.pop('a') + def test_equality(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) @@ -956,6 +971,12 @@ # make sure 'x' is added to the end self.assertEqual(list(od.items())[-1], ('x', 10)) + # make sure setdefault still works when __missing__ is defined + class Missing(OrderedDict): + def __missing__(self, key): + return 0 + self.assertEqual(Missing().setdefault(5, 9), 9) + def test_reinsert(self): # Given insert a, insert b, delete a, re-insert a, # verify that a is now later than b. @@ -973,6 +994,13 @@ self.assertEqual(list(od.viewvalues()), [None for k in s]) self.assertEqual(list(od.viewitems()), [(k, None) for k in s]) + def test_override_update(self): + # Verify that subclasses can override update() without breaking __init__() + class MyOD(OrderedDict): + def update(self, *args, **kwds): + raise Exception() + items = [('a', 1), ('c', 3), ('b', 2)] + self.assertEqual(list(MyOD(items).items()), items) class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): type2test = OrderedDict Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Sun Jan 2 02:03:26 2011 @@ -22,6 +22,8 @@ Library ------- +- Subclasses of collections.OrderedDict now work correctly with __missing__. + - Issue 10753 - Characters ';','=' and ',' in the PATH_INFO environment variable won't be quoted when the URI is constructed by the wsgiref.util 's request_uri method. According to RFC 3986, these characters can be a part of From solipsis at pitrou.net Sun Jan 2 04:55:30 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 02 Jan 2011 04:55:30 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r87612): sum=0 Message-ID: py3k results for svn r87612 (hg cset 936cee5928d7) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflogIKcdtq', '-x'] From python-checkins at python.org Sun Jan 2 09:03:33 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 2 Jan 2011 09:03:33 +0100 (CET) Subject: [Python-checkins] r87615 - python/branches/py3k/Lib/collections.py Message-ID: <20110102080333.624BFEE993@mail.python.org> Author: raymond.hettinger Date: Sun Jan 2 09:03:33 2011 New Revision: 87615 Log: Fix doctest to not rely on order of dictionary entries. Use super() instead of direct references to the dict superclass. Modified: python/branches/py3k/Lib/collections.py Modified: python/branches/py3k/Lib/collections.py ============================================================================== --- python/branches/py3k/Lib/collections.py (original) +++ python/branches/py3k/Lib/collections.py Sun Jan 2 09:03:33 2011 @@ -366,16 +366,16 @@ or multiset. Elements are stored as dictionary keys and their counts are stored as dictionary values. - >>> c = Counter('abracadabra') # count elements from a string + >>> c = Counter('abcdeabcdabcaba') # count elements from a string >>> c.most_common(3) # three most common elements - [('a', 5), ('r', 2), ('b', 2)] + [('a', 5), ('b', 4), ('c', 3)] >>> sorted(c) # list all unique elements - ['a', 'b', 'c', 'd', 'r'] + ['a', 'b', 'c', 'd', 'e'] >>> ''.join(sorted(c.elements())) # list elements with repetitions - 'aaaaabbcdrr' + 'aaaaabbbbcccdde' >>> sum(c.values()) # total of all counts - 11 + 15 >>> c['a'] # count of letter 'a' 5 @@ -383,8 +383,8 @@ ... c[elem] += 1 # by adding 1 to each element's count >>> c['a'] # now there are seven 'a' 7 - >>> del c['r'] # remove all 'r' - >>> c['r'] # now there are zero 'r' + >>> del c['b'] # remove all 'b' + >>> c['b'] # now there are zero 'b' 0 >>> d = Counter('simsalabim') # make another counter @@ -423,6 +423,7 @@ >>> c = Counter(a=4, b=2) # a new counter from keyword args ''' + super().__init__() self.update(iterable, **kwds) def __missing__(self, key): @@ -434,8 +435,8 @@ '''List the n most common elements and their counts from the most common to the least. If n is None, then list all element counts. - >>> Counter('abracadabra').most_common(3) - [('a', 5), ('r', 2), ('b', 2)] + >>> Counter('abcdeabcdabcaba').most_common(3) + [('a', 5), ('b', 4), ('c', 3)] ''' # Emulate Bag.sortedByCount from Smalltalk @@ -501,7 +502,7 @@ for elem, count in iterable.items(): self[elem] = count + self_get(elem, 0) else: - dict.update(self, iterable) # fast path when counter is empty + super().update(iterable) # fast path when counter is empty else: _count_elements(self, iterable) if kwds: @@ -541,7 +542,7 @@ def __delitem__(self, elem): 'Like dict.__delitem__() but does not raise KeyError for missing values.' if elem in self: - dict.__delitem__(self, elem) + super().__delitem__(elem) def __repr__(self): if not self: From python-checkins at python.org Sun Jan 2 13:18:44 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 13:18:44 +0100 (CET) Subject: [Python-checkins] r87616 - in python/branches/py3k-cdecimal: .gitignore Demo Doc/ACKS.txt Doc/README.txt Doc/c-api/buffer.rst Doc/c-api/codec.rst Doc/c-api/exceptions.rst Doc/c-api/import.rst Doc/c-api/init.rst Doc/c-api/intro.rst Doc/c-api/list.rst Doc/c-api/slice.rst Doc/c-api/typeobj.rst Doc/c-api/unicode.rst Doc/c-api/veryhigh.rst Doc/copyright.rst Doc/distutils/apiref.rst Doc/documenting/markup.rst Doc/extending/embedding.rst Doc/extending/extending.rst Doc/extending/windows.rst Doc/faq/extending.rst Doc/glossary.rst Doc/howto/index.rst Doc/howto/logging-cookbook.rst Doc/howto/logging.rst Doc/includes/tzinfo-examples.py Doc/install/index.rst Doc/library/_thread.rst Doc/library/allos.rst Doc/library/argparse.rst Doc/library/array.rst Doc/library/bdb.rst Doc/library/builtins.rst Doc/library/codecs.rst Doc/library/collections.rst Doc/library/compileall.rst Doc/library/concurrent.futures.rst Doc/library/configparser.rst Doc/library/ctypes.rst Doc/library/curses.rst Doc/library/dbm.rst Doc/library/difflib.rst Doc/library/dis.rst Doc/library/doctest.rst Doc/library/email.header.rst Doc/library/email.message.rst Doc/library/email.util.rst Doc/library/exceptions.rst Doc/library/fileformats.rst Doc/library/functions.rst Doc/library/functools.rst Doc/library/grp.rst Doc/library/hashlib.rst Doc/library/heapq.rst Doc/library/html.parser.rst Doc/library/http.client.rst Doc/library/imp.rst Doc/library/inspect.rst Doc/library/io.rst Doc/library/itertools.rst Doc/library/logging.config.rst Doc/library/logging.handlers.rst Doc/library/logging.rst Doc/library/msilib.rst Doc/library/multiprocessing.rst Doc/library/os.path.rst Doc/library/os.rst Doc/library/parser.rst Doc/library/pdb.rst Doc/library/pickle.rst Doc/library/pkgutil.rst Doc/library/platform.rst Doc/library/pty.rst Doc/library/py_compile.rst Doc/library/pydoc.rst Doc/library/random.rst Doc/library/re.rst Doc/library/runpy.rst Doc/library/shelve.rst Doc/library/socket.rst Doc/library/someos.rst Doc/library/sqlite3.rst Doc/library/stdtypes.rst Doc/library/string.rst Doc/library/struct.rst Doc/library/subprocess.rst Doc/library/sys.rst Doc/library/test.rst Doc/library/textwrap.rst Doc/library/threading.rst Doc/library/tkinter.rst Doc/library/tkinter.tix.rst Doc/library/trace.rst Doc/library/turtle.rst Doc/library/unicodedata.rst Doc/library/unittest.rst Doc/library/urllib.parse.rst Doc/library/urllib.request.rst Doc/library/warnings.rst Doc/library/xml.dom.minidom.rst Doc/library/zipfile.rst Doc/license.rst Doc/reference/datamodel.rst Doc/reference/expressions.rst Doc/reference/lexical_analysis.rst Doc/tools/sphinxext/static/basic.css Doc/tools/sphinxext/susp-ignored.csv Doc/tutorial/interpreter.rst Doc/tutorial/stdlib.rst Doc/using/cmdline.rst Doc/whatsnew/2.7.rst Doc/whatsnew/3.2.rst Include/Python.h Include/abstract.h Include/ast.h Include/bytearrayobject.h Include/bytes_methods.h Include/bytesobject.h Include/cellobject.h Include/ceval.h Include/classobject.h Include/code.h Include/codecs.h Include/compile.h Include/complexobject.h Include/datetime.h Include/descrobject.h Include/dictobject.h Include/dtoa.h Include/eval.h Include/fileobject.h Include/floatobject.h Include/frameobject.h Include/funcobject.h Include/genobject.h Include/import.h Include/listobject.h Include/longintrepr.h Include/longobject.h Include/marshal.h Include/memoryobject.h Include/methodobject.h Include/modsupport.h Include/moduleobject.h Include/object.h Include/objimpl.h Include/parsetok.h Include/patchlevel.h Include/pyarena.h Include/pyatomic.h Include/pyctype.h Include/pydebug.h Include/pyerrors.h Include/pygetopt.h Include/pymath.h Include/pystate.h Include/pystrtod.h Include/pythonrun.h Include/pythread.h Include/pytime.h Include/setobject.h Include/sliceobject.h Include/structseq.h Include/symtable.h Include/sysmodule.h Include/timefuncs.h Include/token.h Include/traceback.h Include/tupleobject.h Include/typeslots.h Include/ucnhash.h Include/unicodeobject.h Include/warnings.h Include/weakrefobject.h LICENSE Lib/_abcoll.py Lib/_pyio.py Lib/_weakrefset.py Lib/argparse.py Lib/bdb.py Lib/codecs.py Lib/collections.py Lib/compileall.py Lib/concurrent/futures/_base.py Lib/concurrent/futures/process.py Lib/configparser.py Lib/dbm/dumb.py Lib/decimal.py Lib/difflib.py Lib/distutils/__init__.py Lib/distutils/archive_util.py Lib/distutils/command/build_ext.py Lib/distutils/command/install.py Lib/distutils/sysconfig.py Lib/doctest.py Lib/email/_parseaddr.py Lib/email/generator.py Lib/email/header.py Lib/email/message.py Lib/email/test/test_email.py Lib/email/utils.py Lib/encodings/aliases.py Lib/encodings/base64_codec.py Lib/encodings/bz2_codec.py Lib/encodings/hex_codec.py Lib/encodings/quopri_codec.py Lib/encodings/rot_13.py Lib/encodings/uu_codec.py Lib/encodings/zlib_codec.py Lib/functools.py Lib/getpass.py Lib/gettext.py Lib/html/parser.py Lib/http/client.py Lib/http/cookies.py Lib/http/server.py Lib/idlelib/Bindings.py Lib/idlelib/EditorWindow.py Lib/idlelib/FileList.py Lib/idlelib/IOBinding.py Lib/idlelib/idlever.py Lib/idlelib/macosxSupport.py Lib/inspect.py Lib/json/tests Lib/lib2to3 Lib/lib2to3/fixes/fix_urllib.py Lib/lib2to3/main.py Lib/lib2to3/refactor.py Lib/lib2to3/tests/test_refactor.py Lib/lib2to3/tests/test_util.py Lib/logging/__init__.py Lib/mimetypes.py Lib/multiprocessing/__init__.py Lib/multiprocessing/connection.py Lib/multiprocessing/dummy/__init__.py Lib/multiprocessing/dummy/connection.py Lib/multiprocessing/forking.py Lib/multiprocessing/heap.py Lib/multiprocessing/managers.py Lib/multiprocessing/pool.py Lib/multiprocessing/process.py Lib/multiprocessing/queues.py Lib/multiprocessing/reduction.py Lib/multiprocessing/sharedctypes.py Lib/multiprocessing/synchronize.py Lib/multiprocessing/util.py Lib/netrc.py Lib/numbers.py Lib/os.py Lib/pdb.py Lib/py_compile.py Lib/pydoc.py Lib/pydoc_data/_pydoc.css Lib/pydoc_data/topics.py Lib/random.py Lib/shelve.py Lib/shutil.py Lib/site.py Lib/smtpd.py Lib/subprocess.py Lib/sysconfig.py Lib/tabnanny.py Lib/telnetlib.py Lib/tempfile.py Lib/test/__main__.py Lib/test/crashers/README Lib/test/datetimetester.py Lib/test/json_tests Lib/test/pystone.py Lib/test/regrtest.py Lib/test/script_helper.py Lib/test/subprocessdata Lib/test/support.py Lib/test/symlink_support.py Lib/test/test_abc.py Lib/test/test_argparse.py Lib/test/test_array.py Lib/test/test_asyncore.py Lib/test/test_bool.py Lib/test/test_builtin.py Lib/test/test_calendar.py Lib/test/test_cfgparser.py Lib/test/test_cgi.py Lib/test/test_cmath.py Lib/test/test_cmd_line.py Lib/test/test_codecs.py Lib/test/test_collections.py Lib/test/test_compileall.py Lib/test/test_complex.py Lib/test/test_concurrent_futures.py Lib/test/test_contextlib.py Lib/test/test_csv.py Lib/test/test_dbm_gnu.py Lib/test/test_decimal.py Lib/test/test_descr.py Lib/test/test_difflib.py Lib/test/test_dis.py Lib/test/test_float.py Lib/test/test_fork1.py Lib/test/test_fractions.py Lib/test/test_functools.py Lib/test/test_grp.py Lib/test/test_htmlparser.py Lib/test/test_http_cookies.py Lib/test/test_httplib.py Lib/test/test_httpservers.py Lib/test/test_import.py Lib/test/test_inspect.py Lib/test/test_int.py Lib/test/test_io.py Lib/test/test_itertools.py Lib/test/test_json.py Lib/test/test_listcomps.py Lib/test/test_logging.py Lib/test/test_long.py Lib/test/test_math.py Lib/test/test_memoryview.py Lib/test/test_multiprocessing.py Lib/test/test_netrc.py Lib/test/test_normalization.py Lib/test/test_ntpath.py Lib/test/test_os.py Lib/test/test_pdb.py Lib/test/test_posixpath.py Lib/test/test_pydoc.py Lib/test/test_pyexpat.py Lib/test/test_random.py Lib/test/test_range.py Lib/test/test_runpy.py Lib/test/test_shelve.py Lib/test/test_shutil.py Lib/test/test_site.py Lib/test/test_smtpd.py Lib/test/test_smtplib.py Lib/test/test_socket.py Lib/test/test_ssl.py Lib/test/test_struct.py Lib/test/test_subprocess.py Lib/test/test_sys.py Lib/test/test_syslog.py Lib/test/test_telnetlib.py Lib/test/test_tempfile.py Lib/test/test_threadsignals.py Lib/test/test_time.py Lib/test/test_trace.py Lib/test/test_tuple.py Lib/test/test_types.py Lib/test/test_unicode.py Lib/test/test_unicodedata.py Lib/test/test_unittest.py Lib/test/test_urllib.py Lib/test/test_urllib2.py Lib/test/test_urllibnet.py Lib/test/test_urlparse.py Lib/test/test_weakset.py Lib/test/test_winsound.py Lib/test/test_wsgiref.py Lib/test/test_xml_etree.py Lib/test/test_xml_etree_c.py Lib/test/test_xmlrpc.py Lib/test/test_zipfile.py Lib/test/test_zipimport_support.py Lib/test/test_zlib.py Lib/test/win_console_handler.py Lib/test/zip_cp437_header.zip Lib/threading.py Lib/tkinter/__init__.py Lib/tkinter/scrolledtext.py Lib/tkinter/test/test_ttk/test_widgets.py Lib/tkinter/tix.py Lib/turtle.py Lib/turtledemo/__main__.py Lib/turtledemo/about_turtledemo.txt Lib/turtledemo/demohelp.txt Lib/unittest/case.py Lib/unittest/main.py Lib/unittest/runner.py Lib/unittest/suite.py Lib/unittest/test/_test_warnings.py Lib/unittest/test/test_assertions.py Lib/unittest/test/test_break.py Lib/unittest/test/test_case.py Lib/unittest/test/test_discovery.py Lib/unittest/test/test_functiontestcase.py Lib/unittest/test/test_loader.py Lib/unittest/test/test_program.py Lib/unittest/test/test_runner.py Lib/unittest/test/test_setups.py Lib/unittest/test/test_suite.py Lib/unittest/util.py Lib/urllib/parse.py Lib/urllib/request.py Lib/wave.py Lib/weakref.py Lib/webbrowser.py Lib/wsgiref/util.py Lib/xml/etree/ElementTree.py Lib/xmlrpc/client.py Lib/zipfile.py Mac/BuildScript/build-installer.py Mac/Makefile.in Mac/README Makefile.pre.in Misc/ACKS Misc/NEWS Misc/README Misc/RFD Misc/RPM/python-3.2.spec Misc/SpecialBuilds.txt Misc/pymemcompat.h Misc/python-wing4.wpr Misc/python.man Misc/python.pc.in Misc/setuid-prog.c Modules/_collectionsmodule.c Modules/_ctypes/_ctypes.c Modules/_ctypes/cfield.c Modules/_datetimemodule.c Modules/_elementtree.c Modules/_functoolsmodule.c Modules/_gdbmmodule.c Modules/_io/bufferedio.c Modules/_lsprof.c Modules/_posixsubprocess.c Modules/_ssl.c Modules/_struct.c Modules/_testcapimodule.c Modules/_threadmodule.c Modules/arraymodule.c Modules/getpath.c Modules/grpmodule.c Modules/itertoolsmodule.c Modules/main.c Modules/mmapmodule.c Modules/parsermodule.c Modules/posixmodule.c Modules/pwdmodule.c Modules/pyexpat.c Modules/readline.c Modules/resource.c Modules/signalmodule.c Modules/socketmodule.c Modules/socketmodule.h Modules/spwdmodule.c Modules/symtablemodule.c Modules/syslogmodule.c Modules/timemodule.c Modules/unicodedata.c Modules/xxlimited.c Objects/bytearrayobject.c Objects/bytesobject.c Objects/complexobject.c Objects/descrobject.c Objects/floatobject.c Objects/funcobject.c Objects/genobject.c Objects/listobject.c Objects/longobject.c Objects/memoryobject.c Objects/moduleobject.c Objects/object.c Objects/obmalloc.c Objects/rangeobject.c Objects/setobject.c Objects/sliceobject.c Objects/stringlib/formatter.h Objects/structseq.c Objects/tupleobject.c Objects/typeobject.c Objects/typeslots.inc Objects/typeslots.py Objects/unicodectype.c Objects/unicodeobject.c PC/VC6/readme.txt PC/getpathp.c PC/pyconfig.h PC/python3.def PC/python3.mak PC/python32gen.py PC/python32stub.def PC/python3dll.c PC/python_nt.rc PCbuild/build_tkinter.py PCbuild/make_buildinfo.c PCbuild/pcbuild.sln PCbuild/pyproject.vsprops PCbuild/python3dll.vcproj PCbuild/pythoncore.vcproj PCbuild/readme.txt PCbuild/xxlimited.vcproj Parser/pgenmain.c Parser/printgrammar.c Parser/tokenizer.c Python/_warnings.c Python/ast.c Python/bltinmodule.c Python/ceval.c Python/compile.c Python/dynload_shlib.c Python/dynload_win.c Python/errors.c Python/future.c Python/getcopyright.c Python/import.c Python/peephole.c Python/pyarena.c Python/pythonrun.c Python/sysmodule.c Python/thread_nt.h Python/thread_pthread.h Python/traceback.c README Tools/README Tools/buildbot/external-amd64.bat Tools/buildbot/external-common.bat Tools/buildbot/external.bat Tools/buildbot/test.bat Tools/demo Tools/framer Tools/msi/msi.py Tools/parser Tools/scripts/README Tools/scripts/abitype.py Tools/scripts/find-uname.py Tools/scripts/get-remote-certificate.py Tools/scripts/redemo.py Tools/scripts/untabify.py Tools/ssl Tools/test2to3 Tools/unicode/gencodec.py Tools/world configure configure.in pyconfig.h.in runtests.sh setup.py Message-ID: <20110102121844.23065EE986@mail.python.org> Author: stefan.krah Date: Sun Jan 2 13:18:37 2011 New Revision: 87616 Log: Merged revisions 86689-86690,86693-86694,86697,86699-86702,86705,86708,86713,86717,86720,86725,86727,86729-86734,86737,86743-86747,86750-86751,86758-86759,86791,86794-86795,86797-86801,86804,86808,86819,86823-86825,86828-86829,86837-86839,86842-86845,86854-86857,86861,86864,86867-86870,86874-86875,86878-86884,86887-86893,86895-86896,86901-86903,86905-86925,86928-86937,86940,86943-86971,86974-86977,86979-86981,86983-86986,86993,86996-87004,87007-87014,87017-87032,87036,87038-87045,87047-87048,87050-87052,87054,87056-87060,87062-87084,87086,87088,87093-87094,87101-87110,87112-87119,87124-87137,87140-87141,87145-87161,87171-87177,87179-87186,87188-87194,87197-87198,87201-87210,87212-87217,87221-87222,87225,87228-87230,87233,87236,87238,87241,87245-87248,87251,87256,87258,87260-87277,87280,87283-87284,87288-87289,87292-87304,87306,87312,87315-87317,87323-87324,87327-87329,87337-87341,87344-87346,87348,87350-87356,87359-87368,87371-87374,87377-87378,87381,87384,87389-87400,87402-87403,87408,87411,87415,87418,87421,87424-87427,87430,87433,87435-87443,87445-87448,87451,87454-87455,87458-87463,87466-87479,87482-87483,87485-87486,87489,87492-87493,87496-87498,87501,87504-87508,87512-87514,87516-87539,87542,87547-87550,87553,87556-87564,87567,87569,87571,87573,87575,87577,87579-87590,87593-87595,87598,87601,87603-87604,87606-87607,87610-87612,87615 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ................ r86689 | kristjan.jonsson | 2010-11-22 12:37:06 +0100 (Mon, 22 Nov 2010) | 3 lines issue 10501 make_buildinfo regression with unquoted path Make_buildinfo.exe should be called with a quoted path, and should quote the full paths to its temp files, to support spaces in filenames. ................ r86690 | ezio.melotti | 2010-11-22 13:56:58 +0100 (Mon, 22 Nov 2010) | 1 line #9424: add a DeprecationWarning for assertEquals, assertNotEquals, assertAlmostEquals, assertNotAlmostEquals, and assert_ ................ r86693 | antoine.pitrou | 2010-11-22 17:19:04 +0100 (Mon, 22 Nov 2010) | 3 lines Fix tests when ctypes isn't available ................ r86694 | antoine.pitrou | 2010-11-22 17:26:21 +0100 (Mon, 22 Nov 2010) | 3 lines Fix test_multiprocessing when ctypes isn't available ................ r86697 | alexander.belopolsky | 2010-11-22 20:40:51 +0100 (Mon, 22 Nov 2010) | 1 line Issue #6878: Fixed return type of tkinter methods documented to return lists. ................ r86699 | lukasz.langa | 2010-11-23 00:31:26 +0100 (Tue, 23 Nov 2010) | 3 lines Issue #9846: ZipExtFile provides no mechanism for closing the underlying file object ................ r86700 | lukasz.langa | 2010-11-23 01:15:02 +0100 (Tue, 23 Nov 2010) | 3 lines zipfile: remove remaining ResourceWarnings ................ r86701 | lukasz.langa | 2010-11-23 01:19:53 +0100 (Tue, 23 Nov 2010) | 3 lines information on Issue #9846 ................ r86702 | terry.reedy | 2010-11-23 07:01:31 +0100 (Tue, 23 Nov 2010) | 2 lines Issue 9222 Fix filetypes for open dialog ................ r86705 | georg.brandl | 2010-11-23 08:54:19 +0100 (Tue, 23 Nov 2010) | 1 line #10468: document Unicode exception creation and access functions. ................ r86708 | georg.brandl | 2010-11-23 09:37:54 +0100 (Tue, 23 Nov 2010) | 2 lines #10511: clarification of what heaps are; suggested by Johannes Hoff. ................ r86713 | georg.brandl | 2010-11-23 19:14:57 +0100 (Tue, 23 Nov 2010) | 1 line assert.h is also included. Thanks to Savio Sena. ................ r86717 | terry.reedy | 2010-11-23 21:17:24 +0100 (Tue, 23 Nov 2010) | 2 lines Issue 1859: Doc that textwrap does not break on \n (pending possible behavior patch). Patch by Jeremy Thurgood. ................ r86720 | terry.reedy | 2010-11-23 21:32:47 +0100 (Tue, 23 Nov 2010) | 2 lines IssIssue 1859: Add Jeremy Thurgood to Misc/ACKS ................ r86725 | georg.brandl | 2010-11-24 10:09:29 +0100 (Wed, 24 Nov 2010) | 1 line Remove UTF-8 BOM. ................ r86727 | brian.curtin | 2010-11-24 14:14:05 +0100 (Wed, 24 Nov 2010) | 7 lines Fix #10027. st_nlink not set on Windows calls to os.stat/lstat. Note: This patch has no tests because as of now there is no way to create links. #8879 adds that and the tests will go in there. I've manually observed that existing links on my system function properly with this. ................ r86729 | brian.curtin | 2010-11-24 14:23:18 +0100 (Wed, 24 Nov 2010) | 2 lines ifdef a Windows specific section. ................ r86730 | barry.warsaw | 2010-11-24 19:18:21 +0100 (Wed, 24 Nov 2010) | 2 lines Remove unnecessary import. ................ r86731 | barry.warsaw | 2010-11-24 20:43:47 +0100 (Wed, 24 Nov 2010) | 2 lines Final patch for issue 9807. ................ r86732 | ezio.melotti | 2010-11-24 21:18:02 +0100 (Wed, 24 Nov 2010) | 1 line #10299: Add a table that lists all the built-in functions in functions.rst ................ r86733 | brian.curtin | 2010-11-24 21:24:31 +0100 (Wed, 24 Nov 2010) | 8 lines Fix #8879. Add os.link support to Windows. Additionally, the st_ino attribute of stat structures was not being filled in. This was left out of the fix to #10027 and was noticed due to test_tarfile failing when applying the patch for this issue. An earlier version of the fix to #10027 included st_ino, but that attribute got lost in the shuffle of a few review/fix cycles. All tests pass. ................ r86734 | barry.warsaw | 2010-11-24 21:30:00 +0100 (Wed, 24 Nov 2010) | 5 lines Put /usr/local paths after the relative paths in library_dirs and include_dirs, so installed non-matching shared libraries don't break extension module linking. Fixes issue 10520. ................ r86737 | ezio.melotti | 2010-11-24 23:02:18 +0100 (Wed, 24 Nov 2010) | 1 line Add NEWS entry for r86732 and fix double function in the table. ................ r86743 | barry.warsaw | 2010-11-25 02:34:47 +0100 (Thu, 25 Nov 2010) | 2 lines sys.abiflags may not be defined on all platforms. ................ r86744 | barry.warsaw | 2010-11-25 04:46:44 +0100 (Thu, 25 Nov 2010) | 2 lines sys.abiflags is not defined on all platforms. ................ r86745 | terry.reedy | 2010-11-25 07:12:34 +0100 (Thu, 25 Nov 2010) | 2 lines Issue 2986: Add autojunk paramater to SequenceMatcher to turn off heuristic. Patch by Terry Reedy, Eli Bendersky, and Simon Cross ................ r86746 | raymond.hettinger | 2010-11-25 09:11:57 +0100 (Thu, 25 Nov 2010) | 1 line Clean-up docstring, comments, and whitespace. ................ r86747 | amaury.forgeotdarc | 2010-11-25 09:13:35 +0100 (Thu, 25 Nov 2010) | 3 lines Fix compilation warnings seen on Windows. 'typecode' is always an ascii letter, there was no data lost. ................ r86750 | senthil.kumaran | 2010-11-25 15:56:44 +0100 (Thu, 25 Nov 2010) | 3 lines Mouse support and colour to Demo/curses/life.py by Dafydd Crosby ................ r86751 | eric.smith | 2010-11-25 17:08:06 +0100 (Thu, 25 Nov 2010) | 1 line Issue #7094: Add alternate ('#') flag to __format__ methods for float, complex and Decimal. Allows greater control over when decimal points appear. Added to make transitioning from %-formatting easier. '#g' still has a problem with Decimal which I'll fix soon. ................ r86758 | eric.araujo | 2010-11-26 01:39:59 +0100 (Fri, 26 Nov 2010) | 2 lines #10453 follow-up: Fix test_quiet on Windows, thanks to Stephan Krah. ................ r86759 | senthil.kumaran | 2010-11-26 03:20:04 +0100 (Fri, 26 Nov 2010) | 3 lines s/colour/color/g ................ r86791 | stefan.krah | 2010-11-26 11:54:09 +0100 (Fri, 26 Nov 2010) | 1 line Indentation cleanup. ................ r86794 | georg.brandl | 2010-11-26 12:50:13 +0100 (Fri, 26 Nov 2010) | 1 line #10526: fix typo. ................ r86795 | georg.brandl | 2010-11-26 12:55:48 +0100 (Fri, 26 Nov 2010) | 1 line Use PyLong_FromLong where appropriate. ................ r86797 | georg.brandl | 2010-11-26 13:05:27 +0100 (Fri, 26 Nov 2010) | 1 line Modernize code in effective(). ................ r86798 | georg.brandl | 2010-11-26 13:05:48 +0100 (Fri, 26 Nov 2010) | 1 line #10420: fix docs of bdb.effective(). ................ r86799 | georg.brandl | 2010-11-26 13:08:19 +0100 (Fri, 26 Nov 2010) | 1 line Remove parenthetical remark that is confusing now that the module is not named "__builtin__" anymore. ................ r86800 | georg.brandl | 2010-11-26 13:10:06 +0100 (Fri, 26 Nov 2010) | 1 line Typo fix. ................ r86801 | georg.brandl | 2010-11-26 13:12:14 +0100 (Fri, 26 Nov 2010) | 1 line Better example for os.system(): do not change the system time. ................ r86804 | stefan.krah | 2010-11-26 13:58:05 +0100 (Fri, 26 Nov 2010) | 1 line Issue #10383: Fix two leaks. ................ r86808 | stefan.krah | 2010-11-26 17:16:47 +0100 (Fri, 26 Nov 2010) | 1 line Further indentation cleanup. ................ r86819 | alexander.belopolsky | 2010-11-26 19:51:39 +0100 (Fri, 26 Nov 2010) | 1 line Fixed deprecation warnings. ................ r86823 | eric.araujo | 2010-11-27 00:31:07 +0100 (Sat, 27 Nov 2010) | 2 lines Use link-generating markup (see #9312) ................ r86824 | eric.araujo | 2010-11-27 00:46:18 +0100 (Sat, 27 Nov 2010) | 2 lines Rewrap long lines + minor edits ................ r86825 | raymond.hettinger | 2010-11-27 09:09:40 +0100 (Sat, 27 Nov 2010) | 1 line Replace _nbits() with int.bit_length(). ................ r86828 | raymond.hettinger | 2010-11-27 10:31:37 +0100 (Sat, 27 Nov 2010) | 1 line Issue 10242: unittest.assertItemsEqual makes too many assumptions. ................ r86829 | stefan.krah | 2010-11-27 12:44:18 +0100 (Sat, 27 Nov 2010) | 1 line Fix additional leaks. ................ r86837 | barry.warsaw | 2010-11-27 21:03:03 +0100 (Sat, 27 Nov 2010) | 2 lines Roumen Petrov's fix for when all paths are absolute. (Issue 10520) ................ r86838 | antoine.pitrou | 2010-11-27 21:40:43 +0100 (Sat, 27 Nov 2010) | 3 lines Make doc for PyErr_Format() up to date. ................ r86839 | terry.reedy | 2010-11-27 21:52:14 +0100 (Sat, 27 Nov 2010) | 2 lines Add version-added note twice for new difflib SequenceMatcher autojunk parameter. ................ r86842 | antoine.pitrou | 2010-11-27 23:00:11 +0100 (Sat, 27 Nov 2010) | 4 lines Issue #10518: Bring back the callable() builtin. Approved by Guido (BDFL) and Georg (RM). ................ r86843 | stefan.krah | 2010-11-27 23:06:49 +0100 (Sat, 27 Nov 2010) | 1 line Windows: fix leak in posix_listdir. ................ r86844 | benjamin.peterson | 2010-11-28 03:51:28 +0100 (Sun, 28 Nov 2010) | 1 line there's now a setup.py switch for this ................ r86845 | ezio.melotti | 2010-11-28 05:18:54 +0100 (Sun, 28 Nov 2010) | 1 line Add callable() to the built-in functions table. ................ r86854 | brian.curtin | 2010-11-29 00:59:46 +0100 (Mon, 29 Nov 2010) | 6 lines Fix for #8879. Amaury noticed that this was originally written in a way that would fail on names that can't be encoded with the mbcs codec. Restructured the function to work with wide names first then narrow names second, to fall in line with the way other functions are written in posixmodule.c. ................ r86855 | raymond.hettinger | 2010-11-29 02:38:25 +0100 (Mon, 29 Nov 2010) | 1 line Do not add an obsolete unittest name to Py3.2. ................ r86856 | ezio.melotti | 2010-11-29 03:02:10 +0100 (Mon, 29 Nov 2010) | 1 line Use assertCountEqual instead of assertItemsEqual ................ r86857 | raymond.hettinger | 2010-11-29 04:56:12 +0100 (Mon, 29 Nov 2010) | 1 line Issue #10565: Iterator ABC should require both __next__ and __iter__. ................ r86861 | senthil.kumaran | 2010-11-29 12:54:17 +0100 (Mon, 29 Nov 2010) | 5 lines Fix #10561 - Fix pdb behavior. Delete the breakpoints by breakpoint number. Handle multiple breakpoints at same line. Update docs/test. Patch by Xavier de Gaye. ................ r86864 | senthil.kumaran | 2010-11-29 13:42:29 +0100 (Mon, 29 Nov 2010) | 3 lines Remove the comment used while testing. ................ r86867 | georg.brandl | 2010-11-29 15:50:54 +0100 (Mon, 29 Nov 2010) | 1 line Fix indentation bug. ................ r86868 | georg.brandl | 2010-11-29 15:53:15 +0100 (Mon, 29 Nov 2010) | 1 line Fix heading style inconsistencies. ................ r86869 | georg.brandl | 2010-11-29 21:12:24 +0100 (Mon, 29 Nov 2010) | 1 line Code style cleanup in bdb. ................ r86870 | georg.brandl | 2010-11-29 21:19:15 +0100 (Mon, 29 Nov 2010) | 1 line Use booleans where applicable. ................ r86874 | raymond.hettinger | 2010-11-30 03:49:29 +0100 (Tue, 30 Nov 2010) | 1 line Issue #10323: Predictable final state for slice(). ................ r86875 | alexander.belopolsky | 2010-11-30 04:03:30 +0100 (Tue, 30 Nov 2010) | 3 lines Issue #10572: Moved json tests to Lib/test/json_tests. Approved by Raymond Hettinger. ................ r86878 | nick.coghlan | 2010-11-30 07:19:46 +0100 (Tue, 30 Nov 2010) | 1 line Issue 10586: change the new functools.lru_cache implementation to expose the maximum and current cache sizes through the public statistics API. This API is now a single function that returns a named tuple. ................ r86879 | nick.coghlan | 2010-11-30 07:36:04 +0100 (Tue, 30 Nov 2010) | 1 line Issue 10220: switch to using string constants rather than integers for inspect.getgeneratorstate() return values and make debugging friendly str() and repr() for generator states a requirement in the test suite ................ r86880 | raymond.hettinger | 2010-11-30 08:13:04 +0100 (Tue, 30 Nov 2010) | 1 line Neaten-up a bit. ................ r86881 | georg.brandl | 2010-11-30 08:43:28 +0100 (Tue, 30 Nov 2010) | 1 line #10584: fix bad links. ................ r86882 | georg.brandl | 2010-11-30 09:20:16 +0100 (Tue, 30 Nov 2010) | 1 line Fix input type for zlib. ................ r86883 | georg.brandl | 2010-11-30 10:30:54 +0100 (Tue, 30 Nov 2010) | 1 line Include structseq.h in Python.h, and remove now-redundant includes in individual sources. ................ r86884 | georg.brandl | 2010-11-30 10:41:01 +0100 (Tue, 30 Nov 2010) | 1 line Remove redundant includes of headers that are already included by Python.h. ................ r86887 | georg.brandl | 2010-11-30 15:57:54 +0100 (Tue, 30 Nov 2010) | 1 line Fix typo. ................ r86888 | brian.curtin | 2010-11-30 16:40:04 +0100 (Tue, 30 Nov 2010) | 3 lines Try to fix failures on platforms that can't encode the test characters. Skip the test if encoding fails. ................ r86889 | nick.coghlan | 2010-11-30 16:48:08 +0100 (Tue, 30 Nov 2010) | 1 line Issue 9873: the URL parsing functions now accept ASCII encoded byte sequences in addition to character strings ................ r86890 | brian.curtin | 2010-11-30 16:54:04 +0100 (Tue, 30 Nov 2010) | 2 lines Actually fix what I attempted to fix in r86888... ................ r86891 | alexander.belopolsky | 2010-11-30 17:56:15 +0100 (Tue, 30 Nov 2010) | 1 line Issue #10552: Partially fixed a sort error in Tools/unicode/gencodec.py ................ r86892 | eric.araujo | 2010-11-30 18:20:31 +0100 (Tue, 30 Nov 2010) | 2 lines Let???s keep ???throw??? for the generator method and use ???raise??? elsewhere. ................ r86893 | alexander.belopolsky | 2010-11-30 18:30:43 +0100 (Tue, 30 Nov 2010) | 1 line Issue #9598: untabify.py will now respect encoding cookie in the files it processes ................ r86895 | raymond.hettinger | 2010-11-30 18:45:41 +0100 (Tue, 30 Nov 2010) | 1 line Add some internal links. ................ r86896 | daniel.stutzbach | 2010-11-30 18:49:53 +0100 (Tue, 30 Nov 2010) | 1 line Fix typo: "ofbytes" should be "of bytes" ................ r86901 | raymond.hettinger | 2010-11-30 20:15:45 +0100 (Tue, 30 Nov 2010) | 1 line Add example, tighten text, and minor clean-ups. ................ r86902 | raymond.hettinger | 2010-11-30 21:02:57 +0100 (Tue, 30 Nov 2010) | 1 line Documentation nits. ................ r86903 | raymond.hettinger | 2010-11-30 21:32:59 +0100 (Tue, 30 Nov 2010) | 1 line Add link to specification. ................ r86905 | antoine.pitrou | 2010-11-30 23:23:20 +0100 (Tue, 30 Nov 2010) | 4 lines Issue #8685: Speed up set difference `a - b` when source set `a` is much larger than operand `b`. Patch by Andrew Bennetts. ................ r86906 | brian.curtin | 2010-12-01 00:46:54 +0100 (Wed, 01 Dec 2010) | 3 lines Fix #10591. Fix test_os for refleak runs. Split a common setUp/tearDown into the appropriate parts. ................ r86907 | raymond.hettinger | 2010-12-01 01:47:56 +0100 (Wed, 01 Dec 2010) | 1 line Doc and docstring nits. ................ r86908 | ezio.melotti | 2010-12-01 01:56:10 +0100 (Wed, 01 Dec 2010) | 1 line #10535: Enable silenced warnings in unittest by default ................ r86909 | ezio.melotti | 2010-12-01 02:45:53 +0100 (Wed, 01 Dec 2010) | 1 line Fix test failure in debug builds and add NEWS entry for r86908 ................ r86910 | ezio.melotti | 2010-12-01 03:32:32 +0100 (Wed, 01 Dec 2010) | 1 line #10273: Rename assertRegexpMatches and assertRaisesRegexp to assertRegex and assertRaisesRegex. ................ r86911 | raymond.hettinger | 2010-12-01 04:45:41 +0100 (Wed, 01 Dec 2010) | 1 line Issue 10593: Adopt Nick's suggestion for an lru_cache with maxsize=None. ................ r86912 | raymond.hettinger | 2010-12-01 11:49:19 +0100 (Wed, 01 Dec 2010) | 1 line Add recipe to itertools doc. ................ r86913 | georg.brandl | 2010-12-01 16:32:43 +0100 (Wed, 01 Dec 2010) | 1 line Add missing word, and add a better reference to the actual function. ................ r86914 | georg.brandl | 2010-12-01 16:36:33 +0100 (Wed, 01 Dec 2010) | 1 line #10594: fix parameter names in PyList API docs. ................ r86915 | georg.brandl | 2010-12-01 16:44:25 +0100 (Wed, 01 Dec 2010) | 1 line Fix some markup and style in the unittest docs. ................ r86916 | alexander.belopolsky | 2010-12-01 21:05:49 +0100 (Wed, 01 Dec 2010) | 1 line Issue #4113: Added custom __repr__ method to functools.partial. ................ r86917 | alexander.belopolsky | 2010-12-01 22:55:40 +0100 (Wed, 01 Dec 2010) | 1 line Reverted unintended change from r86916 ................ r86918 | raymond.hettinger | 2010-12-01 23:48:00 +0100 (Wed, 01 Dec 2010) | 1 line Add itertools.accumulate(). ................ r86919 | raymond.hettinger | 2010-12-01 23:50:36 +0100 (Wed, 01 Dec 2010) | 1 line Add itertools.accumulate(). ................ r86920 | raymond.hettinger | 2010-12-02 00:45:20 +0100 (Thu, 02 Dec 2010) | 1 line Clean-up last update (missing comma, unnecessary spacing change, spurious backtick). ................ r86921 | alexander.belopolsky | 2010-12-02 01:05:57 +0100 (Thu, 02 Dec 2010) | 1 line With Raymond's approval added a paragraph describing Unicode 6.0.0 changes. Not reST formatted. ................ r86922 | alexander.belopolsky | 2010-12-02 01:10:11 +0100 (Thu, 02 Dec 2010) | 1 line Issue4335: Added a test for inspect.getsourcelines with a module without EOL at EOF. ................ r86923 | raymond.hettinger | 2010-12-02 02:38:25 +0100 (Thu, 02 Dec 2010) | 1 line Fix markup ................ r86924 | raymond.hettinger | 2010-12-02 03:41:33 +0100 (Thu, 02 Dec 2010) | 1 line Add an example to the random docs. ................ r86925 | r.david.murray | 2010-12-02 03:58:07 +0100 (Thu, 02 Dec 2010) | 4 lines #10464: fix netrc handling of lines with embedded '#" characters. Patch by Xuanji Li. ................ r86928 | nick.coghlan | 2010-12-02 05:11:46 +0100 (Thu, 02 Dec 2010) | 1 line Issue #9573: os.fork now works when triggered as a side effect of import (the wisdom of actually relying on this remains questionable!) ................ r86929 | raymond.hettinger | 2010-12-02 06:35:35 +0100 (Thu, 02 Dec 2010) | 1 line Neaten-up random module docs. ................ r86930 | terry.reedy | 2010-12-02 08:05:56 +0100 (Thu, 02 Dec 2010) | 2 lines Issue 9299 Add exist_ok parameter to os.makedirs to suppress 'File exists' exception. Patch by Ray Allen. ................ r86931 | georg.brandl | 2010-12-02 10:06:12 +0100 (Thu, 02 Dec 2010) | 1 line Fix-up documentation of makedirs(). ................ r86932 | david.malcolm | 2010-12-02 17:41:00 +0100 (Thu, 02 Dec 2010) | 2 lines Fix spelling of Jamie Zawinski's surname in urllib.parse docstring (issue 10606) ................ r86933 | georg.brandl | 2010-12-02 19:02:01 +0100 (Thu, 02 Dec 2010) | 1 line #10597: fix Py_SetPythonHome docs by pointing to where the meaning of PYTHONHOME is already documented. ................ r86934 | georg.brandl | 2010-12-02 19:06:51 +0100 (Thu, 02 Dec 2010) | 1 line #7475: add (un)transform method to bytes/bytearray and str, add back codecs that can be used with them from Python 2. ................ r86935 | brian.curtin | 2010-12-02 19:29:18 +0100 (Thu, 02 Dec 2010) | 17 lines Fix #9333. Expose os.symlink on Windows only when usable. In order to create symlinks on Windows, SeCreateSymbolicLinkPrivilege is an account privilege that is required to be held by the user. Not only must the privilege be enabled for the account, the activated privileges for the currently running application must be adjusted to enable the requested privilege. Rather than exposing an additional function to be called prior to the user's first os.symlink call, we handle the AdjustTokenPrivileges Windows API call internally and only expose os.symlink when the privilege escalation was successful. Due to the change of only exposing os.symlink when it's available, we can go back to the original test skipping methods of checking via `hasattr`. ................ r86936 | r.david.murray | 2010-12-02 22:47:19 +0100 (Thu, 02 Dec 2010) | 4 lines #8989: add 'domain' keyword to make_msgid. Patch by Adrian von Bidder. ................ r86937 | daniel.stutzbach | 2010-12-02 22:55:33 +0100 (Thu, 02 Dec 2010) | 1 line Issue9915: speeding up sorting with a key ................ r86940 | eric.araujo | 2010-12-02 23:16:19 +0100 (Thu, 02 Dec 2010) | 2 lines Fix wrong test code in test_csv (#10602) ................ r86943 | georg.brandl | 2010-12-02 23:35:25 +0100 (Thu, 02 Dec 2010) | 1 line Re-add accidentally removed line. ................ r86944 | michael.foord | 2010-12-03 01:53:09 +0100 (Fri, 03 Dec 2010) | 1 line Issue 7911: unittest.TestCase.longMessage defaults to True for improved failure messages by default ................ r86945 | michael.foord | 2010-12-03 02:34:01 +0100 (Fri, 03 Dec 2010) | 1 line Initial implementation of Lib/test/__main__.py so we can run tests with 'python -m test' ................ r86946 | benjamin.peterson | 2010-12-03 02:44:10 +0100 (Fri, 03 Dec 2010) | 1 line code style ................ r86947 | michael.foord | 2010-12-03 03:03:30 +0100 (Fri, 03 Dec 2010) | 1 line Set test.regrtest.TEMPDIR correctly when run with 'python -m test' ................ r86948 | raymond.hettinger | 2010-12-03 03:09:34 +0100 (Fri, 03 Dec 2010) | 1 line Simplify the signature for itertools.accumulate() to match numpy. Handle one item iterable the same way as min()/max(). ................ r86949 | michael.foord | 2010-12-03 03:27:44 +0100 (Fri, 03 Dec 2010) | 1 line Remove test/__main__.py until runpy tests can be fixed ................ r86950 | raymond.hettinger | 2010-12-03 03:33:53 +0100 (Fri, 03 Dec 2010) | 1 line Update the itertools.accumulate() docs. ................ r86951 | brian.curtin | 2010-12-03 03:46:02 +0100 (Fri, 03 Dec 2010) | 6 lines Fix #10554. Added context manager support to Popen objects. Added a few common Popen uses to the tests like we've done for a few other instances of adding context managers. Eventually the entire test suite could be converted to use the context manager format. ................ r86952 | r.david.murray | 2010-12-03 05:06:39 +0100 (Fri, 03 Dec 2010) | 12 lines #1486713: Add a tolerant mode to HTMLParser. The motivation for adding this option is that the the functionality it provides used to be provided by sgmllib in Python2, and was used by, for example, BeautifulSoup. Without this option, the Python3 version of BeautifulSoup and the many programs that use it are crippled. The original patch was by 'kxroberto'. I modified it heavily but kept his heuristics and test. I also added additional heuristics to fix #975556, #1046092, and part of #6191. This patch should be completely backward compatible: the behavior with the default strict=True is unchanged. ................ r86953 | r.david.murray | 2010-12-03 05:26:18 +0100 (Fri, 03 Dec 2010) | 2 lines Add missing versionchanged, correct 'throw' wording to 'raise'. ................ r86954 | georg.brandl | 2010-12-03 08:37:16 +0100 (Fri, 03 Dec 2010) | 1 line Move entries from "core" section to where they belong. ................ r86955 | georg.brandl | 2010-12-03 08:38:22 +0100 (Fri, 03 Dec 2010) | 1 line #1745035: add limits for command and data size to smtpd; patch by Savio Sena. ................ r86956 | nick.coghlan | 2010-12-03 08:44:33 +0100 (Fri, 03 Dec 2010) | 1 line Partially revert r78719 - it removed a check that is still needed in some cases (i.e. this will allow Michael to add the test.__main__ support that broke the buildbots previously) ................ r86957 | georg.brandl | 2010-12-03 08:47:22 +0100 (Fri, 03 Dec 2010) | 1 line #940286: pydoc.Helper.help() ignores input/output init parameters. ................ r86958 | georg.brandl | 2010-12-03 08:49:09 +0100 (Fri, 03 Dec 2010) | 1 line Use booleans. ................ r86959 | georg.brandl | 2010-12-03 08:54:09 +0100 (Fri, 03 Dec 2010) | 1 line Remove redundant check for PyBytes in unicode_encode. ................ r86960 | georg.brandl | 2010-12-03 08:55:44 +0100 (Fri, 03 Dec 2010) | 1 line #10360: catch TypeError in WeakSet.__contains__, just like WeakKeyDictionary does. ................ r86961 | georg.brandl | 2010-12-03 10:18:37 +0100 (Fri, 03 Dec 2010) | 1 line Rewrap NEWS (Builbot test commit.) ................ r86962 | nick.coghlan | 2010-12-03 10:29:11 +0100 (Fri, 03 Dec 2010) | 14 lines Improve Pydoc interactive browsing (#2001). Patch by Ron Adam. * A -b option to start an enhanced browsing session. * Allow -b and -p options to be used together. * Specifying port 0 will pick an arbitrary unused socket port. * A new browse() function to start the new server and browser. * Show Python version information in the header. * A *Get* field which takes the same input as the help() function. * A *Search* field which replaces the Tkinter search box. * Links to *Module Index*, *Topics*, and *Keywords*. * Improved source file viewing. * An HTMLDoc.filelink() method. * The -g option and the gui() and serve() functions are deprecated. ................ r86963 | georg.brandl | 2010-12-03 10:45:33 +0100 (Fri, 03 Dec 2010) | 1 line Add a line with the actual changes. ................ r86964 | georg.brandl | 2010-12-03 10:58:38 +0100 (Fri, 03 Dec 2010) | 1 line #10549: fix interface of docclass() for text documenter. ................ r86965 | michael.foord | 2010-12-03 11:42:03 +0100 (Fri, 03 Dec 2010) | 1 line Adding lib/test/__main__.py for running tests with 'python -m test' ................ r86966 | michael.foord | 2010-12-03 11:59:15 +0100 (Fri, 03 Dec 2010) | 1 line Fix lib/test/__main__.py to work even outside a Python build. ................ r86967 | vinay.sajip | 2010-12-03 12:50:38 +0100 (Fri, 03 Dec 2010) | 1 line logging: Added getLogRecordFactory/setLogRecordFactory with docs and tests. ................ r86968 | michael.foord | 2010-12-03 13:27:40 +0100 (Fri, 03 Dec 2010) | 1 line Factor out common code from lib/test/__main__.py and lib/test/regrtest.py into a function. ................ r86969 | vinay.sajip | 2010-12-03 14:01:11 +0100 (Fri, 03 Dec 2010) | 1 line logging: tidied up some docstrings. ................ r86970 | nick.coghlan | 2010-12-03 15:26:13 +0100 (Fri, 03 Dec 2010) | 3 lines Issue 2690: Add support for slicing and negative indices to range objects (includes precalculation and storage of the range length). Refer to the tracker issue for the language moratorium implications of this change ................ r86971 | nick.coghlan | 2010-12-03 15:30:41 +0100 (Fri, 03 Dec 2010) | 1 line Add missing CSS file from r86962 ................ r86974 | georg.brandl | 2010-12-03 16:30:09 +0100 (Fri, 03 Dec 2010) | 1 line Markup consistency fixes. ................ r86975 | nick.coghlan | 2010-12-03 17:08:46 +0100 (Fri, 03 Dec 2010) | 1 line Handle Windows paths and don't double up on HTML header sections in new pydoc URL handler ................ r86976 | lukasz.langa | 2010-12-03 17:28:00 +0100 (Fri, 03 Dec 2010) | 2 lines Issue 10499: Modular interpolation in configparser ................ r86977 | victor.stinner | 2010-12-03 17:51:33 +0100 (Fri, 03 Dec 2010) | 1 line #6780: fix complex() constructor TypeError message ................ r86979 | victor.stinner | 2010-12-03 18:06:43 +0100 (Fri, 03 Dec 2010) | 4 lines import: use PyUnicode_FSConverter to support bytes path and PEP 383 (instead of PyArg_Parse*() with "es" format and Py_FileSystemDefaultEncoding) ................ r86980 | georg.brandl | 2010-12-03 18:19:27 +0100 (Fri, 03 Dec 2010) | 1 line Fix punctuation. ................ r86981 | antoine.pitrou | 2010-12-03 19:41:39 +0100 (Fri, 03 Dec 2010) | 5 lines Issue #10478: Reentrant calls inside buffered IO objects (for example by way of a signal handler) now raise a RuntimeError instead of freezing the current process. ................ r86983 | terry.reedy | 2010-12-03 19:57:42 +0100 (Fri, 03 Dec 2010) | 1 line ................ r86984 | antoine.pitrou | 2010-12-03 20:14:17 +0100 (Fri, 03 Dec 2010) | 3 lines Add an "advanced topics" section to the io doc. ................ r86985 | eric.araujo | 2010-12-03 20:19:17 +0100 (Fri, 03 Dec 2010) | 5 lines Fix incorrect use of gettext in argparse (#10497). Steven, the maintainer of argparse, agreed to have this committed without tests for now, since the fix is obvious. See the bug log. ................ r86986 | michael.foord | 2010-12-03 20:20:44 +0100 (Fri, 03 Dec 2010) | 1 line Fix so that test.test_unittest can be executed by unittest and not just regrtest ................ r86993 | eric.araujo | 2010-12-03 20:41:00 +0100 (Fri, 03 Dec 2010) | 7 lines Allow translators to reorder placeholders in localizable messages from argparse (#10528). There is no unit test; I checked with xgettext that no more warnings were emitted. Steven approved the change. ................ r86996 | georg.brandl | 2010-12-03 20:56:42 +0100 (Fri, 03 Dec 2010) | 1 line Fix indentation. ................ r86997 | antoine.pitrou | 2010-12-03 20:59:41 +0100 (Fri, 03 Dec 2010) | 4 lines Issue #10272: The ssl module now raises socket.timeout instead of a generic SSLError on socket timeouts. ................ r86998 | martin.v.loewis | 2010-12-03 21:14:31 +0100 (Fri, 03 Dec 2010) | 2 lines Merge branches/pep-0384. ................ r86999 | lukasz.langa | 2010-12-03 23:15:19 +0100 (Fri, 03 Dec 2010) | 3 lines %s -> %r correction after review by ??ric Araujo ................ r87000 | terry.reedy | 2010-12-03 23:29:40 +0100 (Fri, 03 Dec 2010) | 3 lines Issue 10534 deprecate isbjunk and isbpopular methods. Will add gone in 3.3 test later. ................ r87001 | terry.reedy | 2010-12-03 23:50:06 +0100 (Fri, 03 Dec 2010) | 2 lines Issue #10534: add NEWS entry for r86983 and r87000. ................ r87002 | martin.v.loewis | 2010-12-04 00:11:07 +0100 (Sat, 04 Dec 2010) | 21 lines Merged revisions 85551,86156-86157,86464 via svnmerge from svn+ssh://pythondev at svn.python.org/sandbox/trunk/2to3/lib2to3 ........ r85551 | benjamin.peterson | 2010-10-15 23:57:29 +0200 (Fr, 15 Okt 2010) | 1 line escape() is now in the html module ........ r86156 | georg.brandl | 2010-11-04 09:34:57 +0100 (Do, 04 Nov 2010) | 1 line Consistency fixes in option parser help texts. ........ r86157 | georg.brandl | 2010-11-04 09:35:30 +0100 (Do, 04 Nov 2010) | 1 line #10286: fix urllib class names. ........ r86464 | benjamin.peterson | 2010-11-14 16:28:52 +0100 (So, 14 Nov 2010) | 1 line match only .py files #10416 ........ ................ r87003 | michael.foord | 2010-12-04 02:11:21 +0100 (Sat, 04 Dec 2010) | 1 line Issue 10620: Specifying test modules by path instead of module name to 'python -m unittest' ................ r87004 | michael.foord | 2010-12-04 02:43:59 +0100 (Sat, 04 Dec 2010) | 1 line Correct comment in unittest test ................ r87007 | alexander.belopolsky | 2010-12-04 04:38:46 +0100 (Sat, 04 Dec 2010) | 5 lines Issue #10557: Fixed error messages from float() and other numeric types. Added a new API function, PyUnicode_TransformDecimalToASCII(), which transforms non-ASCII decimal digits in a Unicode string to their ASCII equivalents. ................ r87008 | georg.brandl | 2010-12-04 10:04:04 +0100 (Sat, 04 Dec 2010) | 1 line Fix typo. ................ r87009 | martin.v.loewis | 2010-12-04 10:08:10 +0100 (Sat, 04 Dec 2010) | 2 lines Make script 2-vs-3-agnostic. ................ r87010 | gregory.p.smith | 2010-12-04 10:10:44 +0100 (Sat, 04 Dec 2010) | 11 lines issue7213 + issue2320: Cause a DeprecationWarning if the close_fds argument is not passed to subprocess.Popen as the default value will be changing in a future Python to the safer and more often desired value of True. DeprecationWarnings that show up in a lot of existing code are controversial and have caused pain in the past. I'd like to leave this on for 3.2 beta1 and see how things go. We can remove the warning if it is deemed too noisy during any betas. (case study: the md5 and sha module DeprecationWarnings are loathed around the world as those modules were never going to be removed in 2.x and 2to3 has a fixer for code that uses them) ................ r87011 | martin.v.loewis | 2010-12-04 10:11:41 +0100 (Sat, 04 Dec 2010) | 2 lines Add Revision keyword. ................ r87012 | martin.v.loewis | 2010-12-04 10:12:14 +0100 (Sat, 04 Dec 2010) | 2 lines Regenerate. ................ r87013 | georg.brandl | 2010-12-04 10:14:36 +0100 (Sat, 04 Dec 2010) | 1 line #6045: provide at least get() and setdefault() for all dbm modules. ................ r87014 | senthil.kumaran | 2010-12-04 10:44:30 +0100 (Sat, 04 Dec 2010) | 3 lines Add the NEWS entry for issue7904 ................ r87017 | gregory.p.smith | 2010-12-04 10:59:52 +0100 (Sat, 04 Dec 2010) | 2 lines refactor the warning test. ................ r87018 | hirokazu.yamamoto | 2010-12-04 11:16:05 +0100 (Sat, 04 Dec 2010) | 6 lines Fixed several corner case issues on os.stat/os.lstat related to reparse points. (Windows) - Set S_IEXEC via final path name not link name. - Set S_IFLNK also via FindFirstFile (when CreateFile fails) ................ r87019 | georg.brandl | 2010-12-04 11:26:46 +0100 (Sat, 04 Dec 2010) | 1 line Add an "optimize" parameter to compile() to control the optimization level, and provide an interface to it in py_compile, compileall and PyZipFile. ................ r87020 | georg.brandl | 2010-12-04 11:39:14 +0100 (Sat, 04 Dec 2010) | 1 line #1513299: cleanup some map() uses where a comprehension works better. ................ r87021 | georg.brandl | 2010-12-04 11:47:18 +0100 (Sat, 04 Dec 2010) | 1 line #1772833: add -q command line option. ................ r87022 | georg.brandl | 2010-12-04 12:02:04 +0100 (Sat, 04 Dec 2010) | 1 line #1569291: speed up array.repeat() by making only O(log n) memcpy() calls; the code follows unicode_repeat. ................ r87023 | mark.dickinson | 2010-12-04 12:06:25 +0100 (Sat, 04 Dec 2010) | 1 line Fix indentation in Objects/longobject.c ................ r87024 | georg.brandl | 2010-12-04 12:12:43 +0100 (Sat, 04 Dec 2010) | 1 line #7905: Actually respect the keyencoding parameter to shelve.Shelf. ................ r87025 | georg.brandl | 2010-12-04 12:20:26 +0100 (Sat, 04 Dec 2010) | 1 line Add the "interact" pdb command from pdb++. ................ r87026 | gregory.p.smith | 2010-12-04 12:22:11 +0100 (Sat, 04 Dec 2010) | 3 lines issue6559: Adds a pass_fds parameter to subprocess.Popen that allows the caller to list exactly which file descriptors should be kept open. ................ r87027 | gregory.p.smith | 2010-12-04 12:36:58 +0100 (Sat, 04 Dec 2010) | 3 lines issue10622: fix superflous scrollbar on the right side of
 boxes in the
  generated html docs.  visible in chrome, possibly other webkit browsers.
................
  r87028 | lukasz.langa | 2010-12-04 12:48:11 +0100 (Sat, 04 Dec 2010) | 3 lines
  
  configparser: minute refactoring of RawConfigParser.items()
................
  r87029 | mark.dickinson | 2010-12-04 12:52:58 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Remove some unecessary '#ifdef Py_NAN's from floatobject.c
................
  r87030 | martin.v.loewis | 2010-12-04 13:00:49 +0100 (Sat, 04 Dec 2010) | 3 lines
  
  Expose CompileString, not CompileStringFlags under the
  limited API.
................
  r87031 | hirokazu.yamamoto | 2010-12-04 13:20:57 +0100 (Sat, 04 Dec 2010) | 2 lines
  
  I hope this will fix Win2008(x64) buildbot error.
................
  r87032 | mark.dickinson | 2010-12-04 13:25:30 +0100 (Sat, 04 Dec 2010) | 3 lines
  
  Issue #10596: Fix float.__mod__ to have the same behaviour as
  float.__divmod__ with respect to signed zeros.
................
  r87036 | lukasz.langa | 2010-12-04 13:46:01 +0100 (Sat, 04 Dec 2010) | 5 lines
  
  configparser: fixed inconsistency where in SafeConfigParser option values
   were ensured to be strings but section names and option keys were not.
   Behaviour unchanged for RawConfigParser and ConfigParser.
................
  r87038 | mark.dickinson | 2010-12-04 14:14:29 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Use copysign to produce appropriately signed zeros instead of trying to worm around possible compiler optimizations.
................
  r87039 | eric.smith | 2010-12-04 14:27:34 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Removed static function complex_format, moved it into complex_repr. Modified tests to check both str and repr, which are the same for complex.
................
  r87040 | eric.smith | 2010-12-04 14:32:18 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Issue #10624: Move requires_IEEE_754 into test.support. I'll fix up other uses of it shortly.
................
  r87041 | lukasz.langa | 2010-12-04 14:48:13 +0100 (Sat, 04 Dec 2010) | 4 lines
  
  support for checking test coverage added.
  70% coverage at the moment (not tragic but needs work).
................
  r87042 | martin.v.loewis | 2010-12-04 14:49:32 +0100 (Sat, 04 Dec 2010) | 2 lines
  
  Fix PEP number.
................
  r87043 | eric.smith | 2010-12-04 16:17:38 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Issue #10624: Use support.requires_IEEE_754 in all appropriate tests.
................
  r87044 | eric.smith | 2010-12-04 16:26:13 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Issue 10625: Add tests for negative zeros in complex str and repr.
................
  r87045 | georg.brandl | 2010-12-04 17:00:47 +0100 (Sat, 04 Dec 2010) | 1 line
  
  #7245: Add a SIGINT handler on continue in pdb that allows to break a program again by pressing Ctrl-C.
................
  r87047 | georg.brandl | 2010-12-04 17:21:42 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Add display/undisplay pdb commands.
................
  r87048 | georg.brandl | 2010-12-04 17:22:44 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Fix accidental checkin.
................
  r87050 | georg.brandl | 2010-12-04 18:09:30 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Fix typo.
................
  r87051 | georg.brandl | 2010-12-04 18:11:36 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Fix test suite to not activate new sigint behavior in pdb.
................
  r87052 | eric.smith | 2010-12-04 18:12:41 +0100 (Sat, 04 Dec 2010) | 1 line
  
  More issue #10624: Add requires_IEEE_754 to __all__.
................
  r87054 | victor.stinner | 2010-12-04 18:24:33 +0100 (Sat, 04 Dec 2010) | 3 lines
  
  Issue #10601: sys.displayhook uses 'backslashreplace' error handler on
  UnicodeEncodeError.
................
  r87056 | eric.araujo | 2010-12-04 18:31:49 +0100 (Sat, 04 Dec 2010) | 2 lines
  
  Use proper plural forms in argparse (#4391)
................
  r87057 | lukasz.langa | 2010-12-04 18:48:18 +0100 (Sat, 04 Dec 2010) | 2 lines
  
  configparser: mapping protocol access get() handles configparser-specific arguments as well
................
  r87058 | gregory.p.smith | 2010-12-04 19:11:44 +0100 (Sat, 04 Dec 2010) | 2 lines
  
  clarify the docs and new warning message.
................
  r87059 | antoine.pitrou | 2010-12-04 19:36:03 +0100 (Sat, 04 Dec 2010) | 3 lines
  
  Silence compile error
................
  r87060 | georg.brandl | 2010-12-04 20:01:29 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Update pydoc topics.
................
  r87062 | georg.brandl | 2010-12-04 20:06:14 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Update suspicious exceptions.
................
  r87063 | georg.brandl | 2010-12-04 20:06:18 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Fix markup errors.
................
  r87064 | georg.brandl | 2010-12-04 20:09:24 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Bump to 3.2b1.
................
  r87065 | raymond.hettinger | 2010-12-04 21:51:36 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Doc nit.
................
  r87066 | raymond.hettinger | 2010-12-04 23:56:25 +0100 (Sat, 04 Dec 2010) | 1 line
  
  Fill-in stub for concurrent.futures
................
  r87067 | raymond.hettinger | 2010-12-05 00:42:12 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Mention itertools.accumulate().
................
  r87068 | raymond.hettinger | 2010-12-05 01:39:18 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Start the argparse entry.
................
  r87069 | raymond.hettinger | 2010-12-05 02:01:52 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Optimization of Timsort.
................
  r87070 | hirokazu.yamamoto | 2010-12-05 03:04:16 +0100 (Sun, 05 Dec 2010) | 3 lines
  
  Now can reproduce the error on AMD64 Windows Server 2008
  even where os.symlink is not supported.
................
  r87071 | hirokazu.yamamoto | 2010-12-05 03:41:46 +0100 (Sun, 05 Dec 2010) | 2 lines
  
  Avoid possible zombi process.
................
  r87072 | hirokazu.yamamoto | 2010-12-05 03:48:08 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Sorry, I had introduced tab in source code.
................
  r87073 | raymond.hettinger | 2010-12-05 03:56:21 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Note the updates to range objects.
................
  r87074 | raymond.hettinger | 2010-12-05 05:04:21 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Describe the transform/untranform methods
................
  r87075 | hirokazu.yamamoto | 2010-12-05 05:16:47 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Should use posix_error here.
................
  r87076 | raymond.hettinger | 2010-12-05 06:39:54 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Optimization notes.
................
  r87077 | raymond.hettinger | 2010-12-05 07:35:16 +0100 (Sun, 05 Dec 2010) | 1 line
  
  New string format character.
................
  r87078 | nick.coghlan | 2010-12-05 07:45:03 +0100 (Sun, 05 Dec 2010) | 2 lines
  
  Issue 10626 investigation: regrtest now checks for alterations to the logging state in the current process (and yes, test_pydoc alters it)
................
  r87079 | raymond.hettinger | 2010-12-05 08:02:45 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Update the unittest section.
................
  r87080 | raymond.hettinger | 2010-12-05 08:06:47 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Spelling
................
  r87081 | nick.coghlan | 2010-12-05 08:17:25 +0100 (Sun, 05 Dec 2010) | 1 line
  
  More fine-grained monitoring of alterations to logging state
................
  r87082 | georg.brandl | 2010-12-05 08:51:39 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Temporarily disable newly failing test for the release.
................
  r87083 | georg.brandl | 2010-12-05 08:59:29 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Apply rest of #10628, and add a few todo comments.
................
  r87084 | raymond.hettinger | 2010-12-05 09:35:21 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Nits and todos
................
  r87086 | georg.brandl | 2010-12-05 12:40:48 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Take PyUnicode_TransformDecimalToASCII out of the limited API.
................
  r87088 | georg.brandl | 2010-12-05 12:42:38 +0100 (Sun, 05 Dec 2010) | 1 line
  
  Fix title.
................
  r87093 | martin.v.loewis | 2010-12-06 00:07:58 +0100 (Mon, 06 Dec 2010) | 2 lines
  
  Automate build for python3.dll.
  Package missing files.
................
  r87094 | raymond.hettinger | 2010-12-06 05:31:40 +0100 (Mon, 06 Dec 2010) | 2 lines
  
  Typo fixups.
................
  r87101 | georg.brandl | 2010-12-06 23:02:48 +0100 (Mon, 06 Dec 2010) | 1 line
  
  Remove visible XXX comments.
................
  r87102 | georg.brandl | 2010-12-06 23:25:25 +0100 (Mon, 06 Dec 2010) | 1 line
  
  Don't use deprecated aliases.
................
  r87103 | raymond.hettinger | 2010-12-07 00:31:36 +0100 (Tue, 07 Dec 2010) | 1 line
  
  Note improvements to the docs.
................
  r87104 | david.malcolm | 2010-12-07 01:32:04 +0100 (Tue, 07 Dec 2010) | 2 lines
  
  Fix typo
................
  r87105 | raymond.hettinger | 2010-12-07 02:47:52 +0100 (Tue, 07 Dec 2010) | 1 line
  
  Add entry for the new sysconfig module.
................
  r87106 | raymond.hettinger | 2010-12-07 03:04:56 +0100 (Tue, 07 Dec 2010) | 1 line
  
  Add entry for new pdb features
................
  r87107 | benjamin.peterson | 2010-12-07 04:46:27 +0100 (Tue, 07 Dec 2010) | 1 line
  
  return views from dict proxy items/values/keys #10630
................
  r87108 | benjamin.peterson | 2010-12-07 04:47:37 +0100 (Tue, 07 Dec 2010) | 1 line
  
  add news note
................
  r87109 | benjamin.peterson | 2010-12-07 05:04:02 +0100 (Tue, 07 Dec 2010) | 1 line
  
  use the more direct API
................
  r87110 | raymond.hettinger | 2010-12-07 07:45:30 +0100 (Tue, 07 Dec 2010) | 1 line
  
  Add example for the entry for argparse
................
  r87112 | raymond.hettinger | 2010-12-07 09:52:41 +0100 (Tue, 07 Dec 2010) | 1 line
  
  More cleanups and examples.
................
  r87113 | raymond.hettinger | 2010-12-07 10:24:30 +0100 (Tue, 07 Dec 2010) | 2 lines
  
  Spelling.
................
  r87114 | raymond.hettinger | 2010-12-07 10:37:11 +0100 (Tue, 07 Dec 2010) | 1 line
  
  Clean-ups and examples.
................
  r87115 | raymond.hettinger | 2010-12-07 10:44:21 +0100 (Tue, 07 Dec 2010) | 1 line
  
  Make the example a little more interesting and useful.
................
  r87116 | raymond.hettinger | 2010-12-07 10:55:02 +0100 (Tue, 07 Dec 2010) | 2 lines
  
  Martin's name with Unicode.
................
  r87117 | hirokazu.yamamoto | 2010-12-07 11:24:37 +0100 (Tue, 07 Dec 2010) | 2 lines
  
  Issue #10637: Called CloseHandle twice in os.stat/os.lstat (Windows)
................
  r87118 | ronald.oussoren | 2010-12-07 15:41:05 +0100 (Tue, 07 Dec 2010) | 14 lines
  
  Two small changes to adjust framework builds to the new stable ABI
  
  Both the Makefile and the script that is used on OSX to create the binary
  installer refer to the directory containing the Makefile using the name
  'config'. This name was changed with the new ABI (with default build flags
  it is now named config-3.2m).  This patch ensures that both files use the
  correct name.
  
  The build-installer.py script contains one other change: it now tests for the
  Tcl/Tk framework version by looking at the 'Current' symlink in the framework
  instead of runnning a script. This makes it possible to verify the version
  that is in the SDK that's used during the build instead of the version that
  is installed on the system.
................
  r87119 | ronald.oussoren | 2010-12-07 16:28:10 +0100 (Tue, 07 Dec 2010) | 2 lines
  
  Fix for issue #10107: Without this patch IDLE on OSX doesn't warn about unsaved files when quitting.
................
  r87124 | raymond.hettinger | 2010-12-08 02:13:53 +0100 (Wed, 08 Dec 2010) | 1 line
  
  Update whatsnew.  Salt the random number seed.
................
  r87125 | raymond.hettinger | 2010-12-08 07:42:41 +0100 (Wed, 08 Dec 2010) | 2 lines
  
  Add example for concurrent.futures.
................
  r87126 | raymond.hettinger | 2010-12-08 07:48:33 +0100 (Wed, 08 Dec 2010) | 1 line
  
  Clean-ups.
................
  r87127 | raymond.hettinger | 2010-12-08 07:50:02 +0100 (Wed, 08 Dec 2010) | 1 line
  
  Nits.
................
  r87128 | senthil.kumaran | 2010-12-08 09:04:49 +0100 (Wed, 08 Dec 2010) | 3 lines
  
  Fix Issue8194  - Fix incompatible API change in the parse_respones for xmlrpclib.
................
  r87129 | raymond.hettinger | 2010-12-08 11:18:21 +0100 (Wed, 08 Dec 2010) | 1 line
  
  range() example
................
  r87130 | raymond.hettinger | 2010-12-08 12:19:45 +0100 (Wed, 08 Dec 2010) | 1 line
  
  Example of argparge with subparsers.
................
  r87131 | raymond.hettinger | 2010-12-08 12:33:19 +0100 (Wed, 08 Dec 2010) | 2 lines
  
  Entry for inspect.getattr_static().
................
  r87132 | hirokazu.yamamoto | 2010-12-08 15:47:07 +0100 (Wed, 08 Dec 2010) | 3 lines
  
  Mention NASM which is needed to build openssl-1.0.0a original source.
  (PC/VC6/readme.txt)
................
  r87133 | alexander.belopolsky | 2010-12-08 22:21:56 +0100 (Wed, 08 Dec 2010) | 1 line
  
  Added a datetime new features entry
................
  r87134 | alexander.belopolsky | 2010-12-08 22:38:46 +0100 (Wed, 08 Dec 2010) | 1 line
  
  Edited the Unicode 6.0.0 entry to add unicode.org links and trim the summary.
................
  r87135 | victor.stinner | 2010-12-08 23:25:45 +0100 (Wed, 08 Dec 2010) | 4 lines
  
  Issue #10546: UTF-16-LE and UTF-16-BE *do* support non-BMP characters
  
  Fix the doc and add tests.
................
  r87136 | r.david.murray | 2010-12-08 23:53:00 +0100 (Wed, 08 Dec 2010) | 6 lines
  
  Have script_helper._assert_python strip refcount strings from stderr.
  
  This makes the output of the function and those that depend on it
  independent of whether or not they are being run under a debug
  build.
................
  r87137 | alexander.belopolsky | 2010-12-09 00:31:48 +0100 (Thu, 09 Dec 2010) | 1 line
  
  Issue #6697: Fixed instances of _PyUnicode_AsString() result not checked for NULL
................
  r87140 | hirokazu.yamamoto | 2010-12-09 11:49:00 +0100 (Thu, 09 Dec 2010) | 2 lines
  
  Should call Py_INCREF for Py_None (Modules/_ssl.c: PySSL_cipher)
................
  r87141 | hirokazu.yamamoto | 2010-12-09 12:13:30 +0100 (Thu, 09 Dec 2010) | 2 lines
  
  Fixed typo in comment.
................
  r87145 | raymond.hettinger | 2010-12-09 17:41:54 +0100 (Thu, 09 Dec 2010) | 2 lines
  
  Entries for datetime, callable, and collections.Counter.
................
  r87146 | georg.brandl | 2010-12-09 19:08:43 +0100 (Thu, 09 Dec 2010) | 1 line
  
  Fix "seperate".
................
  r87147 | georg.brandl | 2010-12-09 19:10:27 +0100 (Thu, 09 Dec 2010) | 1 line
  
  #10661: give QName a nicer repr.
................
  r87148 | georg.brandl | 2010-12-09 19:26:02 +0100 (Thu, 09 Dec 2010) | 1 line
  
  Guard against rogue tuples.
................
  r87149 | raymond.hettinger | 2010-12-10 00:43:34 +0100 (Fri, 10 Dec 2010) | 1 line
  
  Doh! Example pasted twice, but only once in the right place.
................
  r87150 | raymond.hettinger | 2010-12-10 02:09:01 +0100 (Fri, 10 Dec 2010) | 1 line
  
  Overview of email module and recategorize various entries.
................
  r87151 | raymond.hettinger | 2010-12-10 02:19:15 +0100 (Fri, 10 Dec 2010) | 1 line
  
  Reclassify some entries and remove a couple of minor ones.
................
  r87152 | ezio.melotti | 2010-12-10 03:32:05 +0100 (Fri, 10 Dec 2010) | 1 line
  
  #10273: Remove a "Matches" that I missed in r86910. Thanks to RDM for noticing it.
................
  r87153 | vinay.sajip | 2010-12-10 09:17:05 +0100 (Fri, 10 Dec 2010) | 1 line
  
  Minor documentation tweak.
................
  r87154 | vinay.sajip | 2010-12-10 09:19:38 +0100 (Fri, 10 Dec 2010) | 1 line
  
  test.support: Added TestHandler and Matcher classes for better support of assertions about logging.
................
  r87155 | vinay.sajip | 2010-12-10 10:11:23 +0100 (Fri, 10 Dec 2010) | 1 line
  
  Fied typo
................
  r87156 | georg.brandl | 2010-12-10 11:01:44 +0100 (Fri, 10 Dec 2010) | 1 line
  
  #10668: fix wrong call of __init__.
................
  r87157 | vinay.sajip | 2010-12-10 12:42:57 +0100 (Fri, 10 Dec 2010) | 1 line
  
  logging: added handler of last resort.
................
  r87158 | raymond.hettinger | 2010-12-10 18:45:13 +0100 (Fri, 10 Dec 2010) | 1 line
  
  Move nntp entry back to changed modules section and add entry for non-ascii import directories.
................
  r87159 | alexander.belopolsky | 2010-12-10 19:11:24 +0100 (Fri, 10 Dec 2010) | 1 line
  
  Updated UCD version and unicode.org links to Unicode 6.0.0
................
  r87160 | alexander.belopolsky | 2010-12-10 19:14:16 +0100 (Fri, 10 Dec 2010) | 1 line
  
  Reverted accidental commit (from r87159)
................
  r87161 | georg.brandl | 2010-12-10 20:22:11 +0100 (Fri, 10 Dec 2010) | 1 line
  
  Fix typo.
................
  r87171 | martin.v.loewis | 2010-12-11 19:17:22 +0100 (Sat, 11 Dec 2010) | 2 lines
  
  Adjust PySlice_GetIndices documentation to signature change.
................
  r87172 | georg.brandl | 2010-12-11 20:10:30 +0100 (Sat, 11 Dec 2010) | 1 line
  
  Avoid AttributeError(_closed) when a TemporaryDirectory is deallocated whose mkdtemp call failed.
................
  r87173 | martin.v.loewis | 2010-12-11 20:22:04 +0100 (Sat, 11 Dec 2010) | 2 lines
  
  Add versionchanged for parameter type changes.
................
  r87174 | barry.warsaw | 2010-12-11 22:32:01 +0100 (Sat, 11 Dec 2010) | 4 lines
  
  Create the hardlink between python-3.2m and python-3.2 in altbininstall target
  instead of bininstall target so it shows up when you do 'make altinstall'.
  Closes issue 10677.
................
  r87175 | georg.brandl | 2010-12-11 23:19:34 +0100 (Sat, 11 Dec 2010) | 1 line
  
  Fix markup.
................
  r87176 | benjamin.peterson | 2010-12-12 02:33:04 +0100 (Sun, 12 Dec 2010) | 1 line
  
  remove (un)transform methods
................
  r87177 | benjamin.peterson | 2010-12-12 02:46:43 +0100 (Sun, 12 Dec 2010) | 1 line
  
  having three copies of the same test is surely a bit excessive
................
  r87179 | vinay.sajip | 2010-12-12 14:20:55 +0100 (Sun, 12 Dec 2010) | 1 line
  
  Logging documentation update.
................
  r87180 | vinay.sajip | 2010-12-12 14:25:29 +0100 (Sun, 12 Dec 2010) | 1 line
  
  Logging documentation - further update.
................
  r87181 | vinay.sajip | 2010-12-12 14:49:39 +0100 (Sun, 12 Dec 2010) | 1 line
  
  Logging documentation - further update.
................
  r87182 | nick.coghlan | 2010-12-12 16:24:21 +0100 (Sun, 12 Dec 2010) | 2 lines
  
  Issue #10188 (partial resolution): tidy up some behaviour in the new tempfile.TemporaryDirectory context manager
................
  r87183 | vinay.sajip | 2010-12-12 18:37:27 +0100 (Sun, 12 Dec 2010) | 1 line
  
  Logging documentation - further update.
................
  r87184 | antoine.pitrou | 2010-12-12 19:09:53 +0100 (Sun, 12 Dec 2010) | 3 lines
  
  SET_LINENO was removed in 2.3
................
  r87185 | antoine.pitrou | 2010-12-12 19:12:40 +0100 (Sun, 12 Dec 2010) | 3 lines
  
  Remove reference to stuff which is already obsolete in 2.x.
................
  r87186 | antoine.pitrou | 2010-12-12 19:14:34 +0100 (Sun, 12 Dec 2010) | 3 lines
  
  Obsolete aliases needn't be documented
................
  r87188 | antoine.pitrou | 2010-12-12 19:25:25 +0100 (Sun, 12 Dec 2010) | 3 lines
  
  Make this a warning and fix indentation
................
  r87189 | antoine.pitrou | 2010-12-12 20:59:47 +0100 (Sun, 12 Dec 2010) | 3 lines
  
  Better explain the buffer interface (hopefully)
................
  r87190 | antoine.pitrou | 2010-12-12 21:01:43 +0100 (Sun, 12 Dec 2010) | 3 lines
  
  Add link to the buffer protocol description from the memory description.
................
  r87191 | r.david.murray | 2010-12-12 21:06:19 +0100 (Sun, 12 Dec 2010) | 6 lines
  
  #243654: only create a new MIME boundary if we don't already have one.
  
  The rearranged code should do exactly what the old code did, but
  the new code avoids a potentially costly re computation in the case
  where a boundary already exists.
................
  r87192 | antoine.pitrou | 2010-12-12 21:09:18 +0100 (Sun, 12 Dec 2010) | 3 lines
  
  Remove redundant sentence, and fix markup
................
  r87193 | antoine.pitrou | 2010-12-12 21:13:31 +0100 (Sun, 12 Dec 2010) | 3 lines
  
  Fix heading level
................
  r87194 | antoine.pitrou | 2010-12-12 21:17:29 +0100 (Sun, 12 Dec 2010) | 3 lines
  
  Consistent ordering of availability statements
................
  r87197 | antoine.pitrou | 2010-12-12 21:34:49 +0100 (Sun, 12 Dec 2010) | 3 lines
  
  Homogenize the "optional OS services" menu
................
  r87198 | antoine.pitrou | 2010-12-12 21:57:12 +0100 (Sun, 12 Dec 2010) | 3 lines
  
  Improve readability of the socket docs
................
  r87201 | vinay.sajip | 2010-12-12 23:30:17 +0100 (Sun, 12 Dec 2010) | 1 line
  
  Logging documentation - further update.
................
  r87202 | vinay.sajip | 2010-12-12 23:45:35 +0100 (Sun, 12 Dec 2010) | 1 line
  
  Logging documentation - further update.
................
  r87203 | vinay.sajip | 2010-12-12 23:47:13 +0100 (Sun, 12 Dec 2010) | 1 line
  
  Logging documentation - further update.
................
  r87204 | nick.coghlan | 2010-12-13 04:02:43 +0100 (Mon, 13 Dec 2010) | 1 line
  
  Actually finish the tests for r87182
................
  r87205 | kristjan.jonsson | 2010-12-13 04:32:10 +0100 (Mon, 13 Dec 2010) | 8 lines
  
  issue 10683
  When the solution is converted to Visual Studio 2010, the command line to invoke make_buildinfo changes from:
  $(SolutionDir)make_buildinfo.exe" Debug "$(IntDir)\"
  to
  $(SolutionDir)make_buildinfo.exe" Debug "$(IntDir)"
  If the final backslash is omitted, the backslash in IntDir will escape the quote, thus passing the quote in as part of the path name.
  
  This solution is a hack-fix to that problem by skipping any trailing quote from the path name.  It works as long as we don't need any additional arguments to make_buildinfo.exe.  This will help all those sould that are going to run this project through the visual studio autoconverter and get the same error.
................
  r87206 | gregory.p.smith | 2010-12-13 07:45:02 +0100 (Mon, 13 Dec 2010) | 5 lines
  
  Get rid of the close_fds DeprecationWarning.  Changes the default on a per
  platform basis.  It remains False on Windows and changes to True on all
  other platforms (POSIX).  Based on python-dev discussion and
  http://bugs.python.org/issue7213.
................
  r87207 | gregory.p.smith | 2010-12-13 08:59:39 +0100 (Mon, 13 Dec 2010) | 4 lines
  
  issue7213: Open the pipes used by subprocesses with the FD_CLOEXEC flag from
  the C code, using pipe2() when available.  Adds unittests for close_fds and
  cloexec behaviors.
................
  r87208 | gregory.p.smith | 2010-12-13 09:00:52 +0100 (Mon, 13 Dec 2010) | 2 lines
  
  regenerate configure based on r87207.
................
  r87209 | gregory.p.smith | 2010-12-13 09:07:14 +0100 (Mon, 13 Dec 2010) | 2 lines
  
  Mention the subprocess.Popen close_fds default change.  Fixup *s to -s.
................
  r87210 | vinay.sajip | 2010-12-13 09:54:02 +0100 (Mon, 13 Dec 2010) | 1 line
  
  Logging documentatio update.
................
  r87212 | nick.coghlan | 2010-12-13 17:32:51 +0100 (Mon, 13 Dec 2010) | 1 line
  
  Captured IO streams with embedded backslashes are always such a fun combination...
................
  r87213 | barry.warsaw | 2010-12-13 19:04:23 +0100 (Mon, 13 Dec 2010) | 6 lines
  
  Issue 10687.  When --without-pymalloc is given, $VERSION is the same as
  $LDVERSION, which screws up the sym/hard-links.  This avoids those games when
  $VERSION == $LDVERSION.
  
  Also, include a drive-by fix for an obvious syntax error.
................
  r87214 | vinay.sajip | 2010-12-13 19:43:57 +0100 (Mon, 13 Dec 2010) | 1 line
  
  Logging documentation update.
................
  r87215 | vinay.sajip | 2010-12-13 19:49:08 +0100 (Mon, 13 Dec 2010) | 1 line
  
  Logging documentation update.
................
  r87216 | r.david.murray | 2010-12-13 23:50:30 +0100 (Mon, 13 Dec 2010) | 2 lines
  
  #10698: fix typo in example.
................
  r87217 | r.david.murray | 2010-12-14 00:51:19 +0100 (Tue, 14 Dec 2010) | 5 lines
  
  #1078919: make add_header automatically do RFC2231 encoding when needed.
  
  Also document the use of three-tuples if control of the charset
  and language is desired.
................
  r87221 | r.david.murray | 2010-12-14 01:55:46 +0100 (Tue, 14 Dec 2010) | 4 lines
  
  #10699: fix docstring for tzset: it does not take a parameter
  
  Thanks to Garrett Cooper for the fix.
................
  r87222 | r.david.murray | 2010-12-14 02:22:50 +0100 (Tue, 14 Dec 2010) | 2 lines
  
  Use skipIf instead of a return when attribute doesn't exist.
................
  r87225 | r.david.murray | 2010-12-14 02:38:16 +0100 (Tue, 14 Dec 2010) | 2 lines
  
  9162: fix license in multiprocessing files
................
  r87228 | r.david.murray | 2010-12-14 03:25:43 +0100 (Tue, 14 Dec 2010) | 2 lines
  
  Turn on regrtest -W (rerun immediately) option for Windows, too.
................
  r87229 | gregory.p.smith | 2010-12-14 14:43:30 +0100 (Tue, 14 Dec 2010) | 7 lines
  
  Issue #6559: fix the subprocess.Popen pass_fds implementation. Add a unittest.
  Issue #7213: Change the close_fds default on Windows to better match the new
  default on POSIX.  True when possible (False if stdin/stdout/stderr are
  supplied).
  
  Update the documentation to reflect all of the above.
................
  r87230 | r.david.murray | 2010-12-14 15:16:20 +0100 (Tue, 14 Dec 2010) | 7 lines
  
  #10695: use %s not %d so that a string 'port' does not cause a debug traceback
  
  Passing the port as a string value works fine in regular mode, but
  if you turned debug on it would throw an error trying to print the
  port number, which is surprising and confusing.
................
  r87233 | gregory.p.smith | 2010-12-14 15:38:00 +0100 (Tue, 14 Dec 2010) | 4 lines
  
  Issue #1731717: Fixed the problem where subprocess.wait() could cause an
  OSError exception when The OS had been told to ignore SIGCLD in our process
  or otherwise not wait for exiting child processes.
................
  r87236 | gregory.p.smith | 2010-12-14 16:23:02 +0100 (Tue, 14 Dec 2010) | 2 lines
  
  Fix "BytesWarning: str() on a bytes instance"
................
  r87238 | r.david.murray | 2010-12-14 17:20:53 +0100 (Tue, 14 Dec 2010) | 7 lines
  
  #775964: skip YP/NIS entries instead of failing the test
  
  Also includes doc updates mentioning that these entries may not
  be retrievable via getgrnam and getgrgid.
  
  Patch by Bobby Impollonia.
................
  r87241 | gregory.p.smith | 2010-12-14 19:18:49 +0100 (Tue, 14 Dec 2010) | 2 lines
  
  SIGCHLD is a more portable name than SIGCLD.  (OSX has no SIGCLD)
................
  r87245 | vinay.sajip | 2010-12-14 20:40:21 +0100 (Tue, 14 Dec 2010) | 1 line
  
  Logging documentation update.
................
  r87246 | raymond.hettinger | 2010-12-14 22:12:03 +0100 (Tue, 14 Dec 2010) | 1 line
  
  Nits
................
  r87247 | antoine.pitrou | 2010-12-14 23:06:10 +0100 (Tue, 14 Dec 2010) | 3 lines
  
  Freshen README contents
................
  r87248 | r.david.murray | 2010-12-14 23:32:50 +0100 (Tue, 14 Dec 2010) | 2 lines
  
  More comprehensive compileall cli tests, and fixes.
................
  r87251 | r.david.murray | 2010-12-15 00:06:25 +0100 (Wed, 15 Dec 2010) | 4 lines
  
  #4236: avoid possible Fatal Error when import is called from __del__
  
  Patch by Simon Cross, crasher test code by Martin von L??wis.
................
  r87256 | r.david.murray | 2010-12-15 03:19:14 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  #10705: document what the values of debuglevel are and mean.
................
  r87258 | andrew.kuchling | 2010-12-15 03:37:01 +0100 (Wed, 15 Dec 2010) | 1 line
  
  Typo fix
................
  r87260 | senthil.kumaran | 2010-12-15 05:02:45 +0100 (Wed, 15 Dec 2010) | 6 lines
  
  TIMEOUT value change in URLTimeout Test. test.support.transient_internet has a
  socket timeout of 30 when it checks for resource.  Explicit overrding (like
  setting the 10) wont exhibit consistent behavior when tests are outside context
  manager. So, settting it 30.
................
  r87261 | antoine.pitrou | 2010-12-15 16:33:18 +0100 (Wed, 15 Dec 2010) | 4 lines
  
  Issue #10706: Remove outdated script runtests.sh.  Either `make test`
  or `python -m test` should be used instead.
................
  r87262 | antoine.pitrou | 2010-12-15 16:42:59 +0100 (Wed, 15 Dec 2010) | 3 lines
  
  Remove outdated compatibility file.
................
  r87263 | antoine.pitrou | 2010-12-15 16:47:34 +0100 (Wed, 15 Dec 2010) | 3 lines
  
  Encourage --with-pydebug rather than individual setting of debug options.
................
  r87264 | antoine.pitrou | 2010-12-15 16:48:20 +0100 (Wed, 15 Dec 2010) | 3 lines
  
  I don't think we need to ship the comp.lang.python RFD these days.
................
  r87265 | raymond.hettinger | 2010-12-15 17:30:37 +0100 (Wed, 15 Dec 2010) | 1 line
  
  Issue 10667: Fast path for collections.Counter
................
  r87266 | raymond.hettinger | 2010-12-15 18:54:13 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Add entries for the random module and the collections module.
................
  r87267 | raymond.hettinger | 2010-12-15 19:20:19 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Adopt Antoine's suggestion to improve readability with module subsections.
................
  r87268 | raymond.hettinger | 2010-12-15 19:31:57 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Minor regroupings.
................
  r87269 | raymond.hettinger | 2010-12-15 20:00:38 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Move email section in with other modules.  Fix markup.
................
  r87270 | antoine.pitrou | 2010-12-15 20:07:26 +0100 (Wed, 15 Dec 2010) | 3 lines
  
  Move the urllib-inherited API to a distinguished section
................
  r87271 | eric.araujo | 2010-12-15 20:09:58 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Improve trace documentation (#9264).  Patch by Eli Bendersky.
................
  r87272 | raymond.hettinger | 2010-12-15 20:20:01 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Add intro to the changed modules section.
................
  r87273 | eric.araujo | 2010-12-15 20:30:15 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Use nested method directives, rewrap long lines, fix whitespace.
................
  r87274 | raymond.hettinger | 2010-12-15 20:33:49 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Elaborate on the calculation used in the random module.
................
  r87275 | alexander.belopolsky | 2010-12-15 20:47:37 +0100 (Wed, 15 Dec 2010) | 1 line
  
  Use sentence case in section titles consistently
................
  r87276 | terry.reedy | 2010-12-15 21:18:10 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Issue 10534, difflib: tweak doc; test new SequenceMatcher instance attributes; avoid unneeded lists of SM.b2j keys and items in .__chain_b. Do not backport.
................
  r87277 | eric.araujo | 2010-12-15 21:26:30 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Fix wrong name in docstring and doc (#10693).  Original patch by Eli Bendersky.
................
  r87280 | eric.araujo | 2010-12-15 22:07:22 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Fix build_ext with VS 8.0.  Patch by Hirokazu Yamamoto (#9558).
................
  r87283 | eric.araujo | 2010-12-15 23:06:35 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Add disclaimer about MinGW compat in distutils docs (#6007).  Patch by Chris Lambacher.
................
  r87284 | raymond.hettinger | 2010-12-15 23:07:15 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Add entries for structseq, ContextDecorator, and various C-API changes.
................
  r87288 | raymond.hettinger | 2010-12-15 23:35:03 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Entry for decimal and fractions.
................
  r87289 | eric.araujo | 2010-12-15 23:37:27 +0100 (Wed, 15 Dec 2010) | 2 lines
  
  Mark up one missed None in pkgutil.rst (#8851)
................
  r87292 | antoine.pitrou | 2010-12-15 23:59:16 +0100 (Wed, 15 Dec 2010) | 4 lines
  
  Issue #8844: Regular and recursive lock acquisitions can now be interrupted
  by signals on platforms using pthreads.  Patch by Reid Kleckner.
................
  r87293 | antoine.pitrou | 2010-12-16 00:38:50 +0100 (Thu, 16 Dec 2010) | 3 lines
  
  Make test_threadsignals more lax, and add notes
................
  r87294 | eric.araujo | 2010-12-16 01:07:01 +0100 (Thu, 16 Dec 2010) | 2 lines
  
  No need to generate a link for something that???s just above.
................
  r87295 | raymond.hettinger | 2010-12-16 01:21:08 +0100 (Thu, 16 Dec 2010) | 2 lines
  
  Entries for ElementTree, collectionsm, functools and ZipFile.
................
  r87296 | eric.araujo | 2010-12-16 01:23:30 +0100 (Thu, 16 Dec 2010) | 2 lines
  
  Advertise ???python -m??? instead of direct filename.
................
  r87297 | raymond.hettinger | 2010-12-16 01:30:53 +0100 (Thu, 16 Dec 2010) | 1 line
  
  Nits
................
  r87298 | raymond.hettinger | 2010-12-16 01:53:05 +0100 (Thu, 16 Dec 2010) | 2 lines
  
  Thank you ispell.
................
  r87299 | lukasz.langa | 2010-12-16 02:16:22 +0100 (Thu, 16 Dec 2010) | 4 lines
  
  Broken ConfigParser removed, SafeConfigParser renamed to ConfigParser.
  Life is beatiful once again.
................
  r87300 | eric.araujo | 2010-12-16 02:40:26 +0100 (Thu, 16 Dec 2010) | 2 lines
  
  Advertise ???python -m test??? over test.regrtest (r87296 followup)
................
  r87301 | lukasz.langa | 2010-12-16 02:42:36 +0100 (Thu, 16 Dec 2010) | 3 lines
  
  Acknowledged renaming of SafeConfigParser to ConfigParser.
................
  r87302 | eric.araujo | 2010-12-16 03:10:11 +0100 (Thu, 16 Dec 2010) | 2 lines
  
  Add versionadded directive missing from r78983.
................
  r87303 | raymond.hettinger | 2010-12-16 03:24:12 +0100 (Thu, 16 Dec 2010) | 2 lines
  
  Improve the ContextDecorator example.
................
  r87304 | eric.araujo | 2010-12-16 04:13:05 +0100 (Thu, 16 Dec 2010) | 2 lines
  
  Fix one versionchanged
................
  r87306 | brian.curtin | 2010-12-16 04:24:49 +0100 (Thu, 16 Dec 2010) | 2 lines
  
  EasyDialogs was removed in 3.x. fallback_getpass will always be the answer here.
................
  r87312 | eric.araujo | 2010-12-16 07:28:48 +0100 (Thu, 16 Dec 2010) | 2 lines
  
  Add missing docs and directives related to PEP 3147 and byte-compilation
................
  r87315 | raymond.hettinger | 2010-12-16 11:06:11 +0100 (Thu, 16 Dec 2010) | 1 line
  
  Add todo for WSGI
................
  r87316 | antoine.pitrou | 2010-12-16 14:33:56 +0100 (Thu, 16 Dec 2010) | 3 lines
  
  Credit Florent for porting
................
  r87317 | antoine.pitrou | 2010-12-16 17:48:36 +0100 (Thu, 16 Dec 2010) | 4 lines
  
  Issue #10714: Limit length of incoming request in http.server to 65536 bytes
  for security reasons.  Initial patch by Ross Lagerwall.
................
  r87323 | antoine.pitrou | 2010-12-16 19:25:24 +0100 (Thu, 16 Dec 2010) | 3 lines
  
  Issue #10710: `Misc/setuid-prog.c` is removed from the source tree.
................
  r87324 | r.david.murray | 2010-12-16 20:08:51 +0100 (Thu, 16 Dec 2010) | 9 lines
  
  #10719: restore messages generated on invalid compileall args
  
  Before the introduction of filename arguments to compileall it gave semi useful
  messages about not being able to 'list' names that weren't valid directories.
  This fix restores that behavior.  In addition to the test for this case, the
  patch also adds a test for the default behavior of compileall when no arguments
  are provided, and fixes a bug in one of the previously added tests.
................
  r87327 | gregory.p.smith | 2010-12-16 20:23:05 +0100 (Thu, 16 Dec 2010) | 2 lines
  
  assert that the regex given to assertRegex is non-empty.
................
  r87328 | lukasz.langa | 2010-12-17 02:32:29 +0100 (Fri, 17 Dec 2010) | 5 lines
  
  configparser API cleanup: default values now sensible, slightly incompatible.
  Backwards compatible alternative values possible as documented.
  Done by ??ukasz Langa, approved by Raymond and Fred.
................
  r87329 | senthil.kumaran | 2010-12-17 05:48:45 +0100 (Fri, 17 Dec 2010) | 3 lines
  
  Fix Issue9721 - urljoin behavior when the relative url starts with ';'
................
  r87337 | r.david.murray | 2010-12-17 17:11:40 +0100 (Fri, 17 Dec 2010) | 2 lines
  
  #10559: provide instructions for accessing sys.argv when first mentioned.
................
  r87338 | r.david.murray | 2010-12-17 17:29:07 +0100 (Fri, 17 Dec 2010) | 2 lines
  
  #10454: clarify the compileall docs and help messages.
................
  r87339 | daniel.stutzbach | 2010-12-17 17:31:32 +0100 (Fri, 17 Dec 2010) | 1 line
  
  Issue 8753: Added documentation for Py_ReprEntr and Py_ReprLeave.
................
  r87340 | antoine.pitrou | 2010-12-17 18:35:56 +0100 (Fri, 17 Dec 2010) | 4 lines
  
  Issue #10711: Remove HTTP 0.9 support from http.client.  The `strict`
  parameter to HTTPConnection and friends is deprecated.
................
  r87341 | antoine.pitrou | 2010-12-17 18:42:16 +0100 (Fri, 17 Dec 2010) | 4 lines
  
  Issue #4188: Avoid creating dummy thread objects when logging operations
  from the threading module (with the internal verbose flag activated).
................
  r87344 | raymond.hettinger | 2010-12-17 21:19:50 +0100 (Fri, 17 Dec 2010) | 1 line
  
  Expand the LBYL glossary entry.
................
  r87345 | martin.v.loewis | 2010-12-17 21:43:27 +0100 (Fri, 17 Dec 2010) | 1 line
  
  Upgrade Tcl/Tk to 8.5.9.
................
  r87346 | daniel.stutzbach | 2010-12-17 21:53:03 +0100 (Fri, 17 Dec 2010) | 1 line
  
  Issue2690: Update docs to reflect the change made by issue2690.
................
  r87348 | martin.v.loewis | 2010-12-17 22:04:09 +0100 (Fri, 17 Dec 2010) | 1 line
  
  Upgrade to sqlite3 3.7.4.
................
  r87350 | lukasz.langa | 2010-12-17 22:56:32 +0100 (Fri, 17 Dec 2010) | 3 lines
  
  100% test coverage, better mapping protocol compatibility, some minor bugfixes
................
  r87351 | lukasz.langa | 2010-12-17 22:57:32 +0100 (Fri, 17 Dec 2010) | 3 lines
  
  configparser hype coming up!
................
  r87352 | lukasz.langa | 2010-12-17 23:05:46 +0100 (Fri, 17 Dec 2010) | 3 lines
  
  fix for an embarrassing autoformatting SNAFU. Thanks for your alertness, Antoine.
................
  r87353 | victor.stinner | 2010-12-17 23:24:30 +0100 (Fri, 17 Dec 2010) | 1 line
  
  update .gitignore using .hgignore
................
  r87354 | daniel.stutzbach | 2010-12-17 23:28:07 +0100 (Fri, 17 Dec 2010) | 1 line
  
  Fix typo
................
  r87355 | raymond.hettinger | 2010-12-18 00:31:30 +0100 (Sat, 18 Dec 2010) | 1 line
  
  Add link to a sample solution to a common problem.
................
  r87356 | r.david.murray | 2010-12-18 04:48:32 +0100 (Sat, 18 Dec 2010) | 11 lines
  
  #9907: call rl_initialize early when using editline on OSX
  
  editline rl_initialize apparently discards any mappings done before it
  is called, which makes tab revert to file completion instead of inserting
  a tab.  So now on OSX we call rl_initialize first if we are using
  readline, and then re-read the users .editrc (if any) afterward so they
  can still override our defaults.
  
  Patch by Ned Deily, modified by Ronald Oussoren.
................
  r87359 | raymond.hettinger | 2010-12-18 10:41:32 +0100 (Sat, 18 Dec 2010) | 1 line
  
  Enhance argparse example to show aliases.
................
  r87360 | raymond.hettinger | 2010-12-18 11:48:26 +0100 (Sat, 18 Dec 2010) | 2 lines
  
  Minor wordsmithing and markup fix-ups.
................
  r87361 | raymond.hettinger | 2010-12-18 11:57:50 +0100 (Sat, 18 Dec 2010) | 2 lines
  
  Minor markup and wording fixups.
................
  r87362 | steven.bethard | 2010-12-18 12:19:23 +0100 (Sat, 18 Dec 2010) | 1 line
  
  Add subparser aliases for argparse. Resolves issue 9324. Approved by Georg for beta2 on the tracker.
................
  r87363 | raymond.hettinger | 2010-12-18 12:20:52 +0100 (Sat, 18 Dec 2010) | 2 lines
  
  Nits.
................
  r87364 | georg.brandl | 2010-12-18 12:53:25 +0100 (Sat, 18 Dec 2010) | 1 line
  
  Add attribution.
................
  r87365 | georg.brandl | 2010-12-18 12:58:12 +0100 (Sat, 18 Dec 2010) | 1 line
  
  Typo fix.
................
  r87366 | georg.brandl | 2010-12-18 13:01:15 +0100 (Sat, 18 Dec 2010) | 1 line
  
  Use kbd role.
................
  r87367 | antoine.pitrou | 2010-12-18 13:33:06 +0100 (Sat, 18 Dec 2010) | 3 lines
  
  Make this a note again.
................
  r87368 | ezio.melotti | 2010-12-18 15:59:43 +0100 (Sat, 18 Dec 2010) | 1 line
  
  #5587: add a repr to dict_proxy objects.  Patch by David Stanek and Daniel Urban.
................
  r87371 | georg.brandl | 2010-12-18 17:21:58 +0100 (Sat, 18 Dec 2010) | 1 line
  
  Fix typo.
................
  r87372 | r.david.murray | 2010-12-18 17:39:06 +0100 (Sat, 18 Dec 2010) | 2 lines
  
  #10728: the default for printing help is sys.stdout, not stderr.
................
  r87373 | senthil.kumaran | 2010-12-18 17:55:23 +0100 (Sat, 18 Dec 2010) | 3 lines
  
  Fix Issue6791 - Limit the HTTP header readline with _MAXLENGTH. Patch by Antoine Pitrou
................
  r87374 | r.david.murray | 2010-12-18 18:19:10 +0100 (Sat, 18 Dec 2010) | 8 lines
  
  #10404: Use ctl-button-1 for context menus on OSX Idle.
  
  This provides access to the context menus where they previously could
  not be accessed due to the way OSX Tk binds buttons.  It also
  improves platform consistency.
  
  Patch by Ned Deily.
................
  r87377 | ezio.melotti | 2010-12-18 18:31:58 +0100 (Sat, 18 Dec 2010) | 1 line
  
  Use lowercase true/false in assertTrue/assertFalse messages.
................
  r87378 | georg.brandl | 2010-12-18 18:51:28 +0100 (Sat, 18 Dec 2010) | 1 line
  
  #10723: add missing builtin exceptions.
................
  r87381 | antoine.pitrou | 2010-12-18 18:59:18 +0100 (Sat, 18 Dec 2010) | 3 lines
  
  NEWS entry for r87373	
................
  r87384 | r.david.murray | 2010-12-18 19:25:38 +0100 (Sat, 18 Dec 2010) | 12 lines
  
  #9286: Fix the rfc822 parser to preserve whitespace in address local part.
  
  Such addresses are not RFC compliant except under the 'obsolete syntax'
  rules, but before this fix the whitespace was dropped from the input,
  concatenating the pieces.  That breaks one of the principles of the
  email package, that of preserving the input as much as possible.
  It also denies the application program the opportunity to apply its
  own heuristics to interpretation of such non-compliant addresses.
  
  It is possible users of the email package were depending on the local
  part always being a single token, so this fix will not be backported.
................
  r87389 | ezio.melotti | 2010-12-18 21:00:04 +0100 (Sat, 18 Dec 2010) | 1 line
  
  #10573: use actual/expected consistently in unittest methods. The order of the args of assertCountEqual is also changed.
................
  r87390 | michael.foord | 2010-12-19 04:19:47 +0100 (Sun, 19 Dec 2010) | 1 line
  
  Issue 10611. Issue 9857. Improve the way exception handling, including test skipping, is done inside TestCase.run
................
  r87391 | michael.foord | 2010-12-19 04:59:10 +0100 (Sun, 19 Dec 2010) | 1 line
  
  Fix minor issue in implementation of issue 10470.
................
  r87392 | michael.foord | 2010-12-19 05:07:28 +0100 (Sun, 19 Dec 2010) | 1 line
  
  Improvement to fix for issue 9926 to allow TestResult to be reused.
................
  r87393 | vinay.sajip | 2010-12-19 07:02:31 +0100 (Sun, 19 Dec 2010) | 1 line
  
  Logging documentation update.
................
  r87394 | georg.brandl | 2010-12-19 11:10:32 +0100 (Sun, 19 Dec 2010) | 1 line
  
  #6075: make idle work with both Carbon AquaTk and Cocoa AquaTk. Patch by Kevin Walzer and Ned Deily.
................
  r87395 | georg.brandl | 2010-12-19 11:17:46 +0100 (Sun, 19 Dec 2010) | 1 line
  
  Temporarily skip test failing with newer ttk.
................
  r87396 | georg.brandl | 2010-12-19 11:25:28 +0100 (Sun, 19 Dec 2010) | 1 line
  
  Update pydoc topics.
................
  r87397 | georg.brandl | 2010-12-19 11:28:46 +0100 (Sun, 19 Dec 2010) | 1 line
  
  Fix markup error and update suspicious file.
................
  r87398 | georg.brandl | 2010-12-19 11:30:28 +0100 (Sun, 19 Dec 2010) | 1 line
  
  Bump to 3.2b2.
................
  r87399 | senthil.kumaran | 2010-12-19 11:49:52 +0100 (Sun, 19 Dec 2010) | 3 lines
  
  Issue3243 - Support iterable bodies in httplib. Patch contributions by Xuanji Li and Chris AtLee.
................
  r87400 | georg.brandl | 2010-12-19 13:33:52 +0100 (Sun, 19 Dec 2010) | 1 line
  
  #3243 follow-up: remove debugging print and fix docs; data is a bytes object.
................
  r87402 | vinay.sajip | 2010-12-19 13:56:57 +0100 (Sun, 19 Dec 2010) | 1 line
  
  Logging documentation reorganised.
................
  r87403 | vinay.sajip | 2010-12-19 14:41:26 +0100 (Sun, 19 Dec 2010) | 1 line
  
  Logging documentation updates.
................
  r87408 | r.david.murray | 2010-12-20 19:08:59 +0100 (Mon, 20 Dec 2010) | 8 lines
  
  Make test_compileall more robust by using -S to keep sys.path minimized.
  
  Arfrever Taifersar Arahesis reported that test_compileall failed during Gentoo
  install because it was tyring to write .pyc files to a read-only system
  directory during test_no_args_compiles_path.  Having subprocess call python
  with -S should eliminate the system directories from the path.
................
  r87411 | r.david.murray | 2010-12-20 20:04:51 +0100 (Mon, 20 Dec 2010) | 2 lines
  
  Revert incorrect patch made at the wrong time.
................
  r87415 | r.david.murray | 2010-12-21 19:07:59 +0100 (Tue, 21 Dec 2010) | 4 lines
  
  Fix the change made for issue 1243654.
  
  Surprisingly, it turns out there was no test that exercised this code path.
................
  r87418 | r.david.murray | 2010-12-21 19:24:33 +0100 (Tue, 21 Dec 2010) | 10 lines
  
  Make test_compileall more robust by using -S to keep sys.path minimized.
  
  Try this again, hopefully the right way this time.
  
  Arfrever Taifersar Arahesis reported that test_compileall failed during Gentoo
  install because it was tyring to write .pyc files to a read-only system
  directory during test_no_args_compiles_path.  Having the tests call python
  with -S should eliminate the system directories from the path.
................
  r87421 | antoine.pitrou | 2010-12-21 19:49:01 +0100 (Tue, 21 Dec 2010) | 4 lines
  
  Suggest sys.maxsize as a reliable way to know whether the interpreter is 64-bit.
  (part of #10735)
................
  r87424 | raymond.hettinger | 2010-12-21 20:24:26 +0100 (Tue, 21 Dec 2010) | 1 line
  
  Deprecate assertDictContainsSubset()
................
  r87425 | raymond.hettinger | 2010-12-21 21:09:55 +0100 (Tue, 21 Dec 2010) | 2 lines
  
  Reference the release schedule
................
  r87426 | raymond.hettinger | 2010-12-21 21:52:12 +0100 (Tue, 21 Dec 2010) | 2 lines
  
  Document the alternate format for :ref:.
................
  r87427 | antoine.pitrou | 2010-12-21 22:20:59 +0100 (Tue, 21 Dec 2010) | 3 lines
  
  Issue #10750: The `raw` attribute of buffered IO objects is now read-only.
................
  r87430 | r.david.murray | 2010-12-21 22:53:37 +0100 (Tue, 21 Dec 2010) | 9 lines
  
  #4871: check that zipfile password is bytes, and give useful error message.
  
  Previously passing a string in as the password would fail either with
  an assertion error or a TypeError with a confusing error message.
  Note that a string can't be accepted since zipfile has no way to
  guess what encoding should be used to turn it into bytes.
  
  Patch by Victor Stinner.
................
  r87433 | alexander.belopolsky | 2010-12-22 02:37:36 +0100 (Wed, 22 Dec 2010) | 3 lines
  
  Both PEP 3131 and the current implementation use NFKC normalization
  for identifiers.  Fixed the documentation to agree.
................
  r87435 | alexander.belopolsky | 2010-12-22 03:35:20 +0100 (Wed, 22 Dec 2010) | 1 line
  
  Removed unneeded #include
................
  r87436 | gregory.p.smith | 2010-12-22 06:22:17 +0100 (Wed, 22 Dec 2010) | 2 lines
  
  fix a compiler warning about err_msg potentially being used uninitialized.
................
  r87437 | raymond.hettinger | 2010-12-22 10:11:54 +0100 (Wed, 22 Dec 2010) | 2 lines
  
  Add todo
................
  r87438 | michael.foord | 2010-12-22 11:39:04 +0100 (Wed, 22 Dec 2010) | 1 line
  
  Minor typo corrections in whatsnew
................
  r87439 | vinay.sajip | 2010-12-22 16:04:15 +0100 (Wed, 22 Dec 2010) | 1 line
  
  Logging documentation updates.
................
  r87440 | michael.foord | 2010-12-22 19:28:51 +0100 (Wed, 22 Dec 2010) | 1 line
  
  Another trivial typo correction in whatsnew
................
  r87441 | antoine.pitrou | 2010-12-22 23:19:15 +0100 (Wed, 22 Dec 2010) | 3 lines
  
  Fix ResourceWarning in test_normalization
................
  r87442 | alexander.belopolsky | 2010-12-23 03:27:37 +0100 (Thu, 23 Dec 2010) | 1 line
  
  Issue #10254: Fixed a crash and a regression introduced by the implementation of PRI 29.
................
  r87443 | alexander.belopolsky | 2010-12-23 03:58:25 +0100 (Thu, 23 Dec 2010) | 1 line
  
  Issue #10587: Document the meaning of str methods.
................
  r87445 | eric.araujo | 2010-12-23 19:41:33 +0100 (Thu, 23 Dec 2010) | 2 lines
  
  Fix small inaccuracy: there is no index function
................
  r87446 | eric.araujo | 2010-12-23 19:44:31 +0100 (Thu, 23 Dec 2010) | 2 lines
  
  Nits: use a real boolean, make one docstring more similar to the other ones
................
  r87447 | eric.araujo | 2010-12-23 20:13:05 +0100 (Thu, 23 Dec 2010) | 2 lines
  
  Fix typo in superclass method name
................
  r87448 | r.david.murray | 2010-12-23 20:44:49 +0100 (Thu, 23 Dec 2010) | 4 lines
  
  #4496: remove misleading comment and note that self.handlers is obsolete.
  
  self.handlers is still used in one urllib2 test, but not by the code iteslf.
................
  r87451 | r.david.murray | 2010-12-23 21:35:46 +0100 (Thu, 23 Dec 2010) | 4 lines
  
  #1155362: allow hh:mm:ss-uuuu like we allow hh:mm:ss+uuuu in parsedate_tz
  
  Original patch by Thomas Herve.
................
  r87454 | raymond.hettinger | 2010-12-23 22:54:02 +0100 (Thu, 23 Dec 2010) | 4 lines
  
  Fix buglet.  If the input was an iterator, the fallback would occur after
  part of the iterator had been consumed.   Also, fix argument names which
  did not match the docs and were a bit misleading.
................
  r87455 | benjamin.peterson | 2010-12-23 23:17:42 +0100 (Thu, 23 Dec 2010) | 1 line
  
  fix docstring
................
  r87458 | benjamin.peterson | 2010-12-23 23:49:38 +0100 (Thu, 23 Dec 2010) | 1 line
  
  use native tenary condition
................
  r87459 | benjamin.peterson | 2010-12-23 23:53:42 +0100 (Thu, 23 Dec 2010) | 1 line
  
  kill some function imports
................
  r87460 | terry.reedy | 2010-12-24 00:10:28 +0100 (Fri, 24 Dec 2010) | 3 lines
  
  Issue 10730: mimetypes module - add .svgz to mimetypes.suffix_map and .svg to types_map.
  Addition OKed by GB on IRC (R. David Murray). No backport.
................
  r87461 | eric.araujo | 2010-12-24 00:18:41 +0100 (Fri, 24 Dec 2010) | 2 lines
  
  Fix syntax typo
................
  r87462 | benjamin.peterson | 2010-12-24 00:45:39 +0100 (Fri, 24 Dec 2010) | 1 line
  
  update comment
................
  r87463 | alexander.belopolsky | 2010-12-24 01:24:11 +0100 (Fri, 24 Dec 2010) | 1 line
  
  Issue #9063: Corrected the tzinfo example.
................
  r87466 | raymond.hettinger | 2010-12-24 01:48:47 +0100 (Fri, 24 Dec 2010) | 1 line
  
  Add test for r87454.
................
  r87467 | raymond.hettinger | 2010-12-24 01:52:54 +0100 (Fri, 24 Dec 2010) | 1 line
  
  Fix docs and comment for r87454.
................
  r87468 | raymond.hettinger | 2010-12-24 01:58:34 +0100 (Fri, 24 Dec 2010) | 2 lines
  
  Fix docstring.
................
  r87469 | senthil.kumaran | 2010-12-24 05:03:59 +0100 (Fri, 24 Dec 2010) | 4 lines
  
  Fix some mistakes- Issue3243 (r87399)  Correcting the operator precendence
  problem with Content-Length header and uncommenting the test.
................
  r87470 | alexander.belopolsky | 2010-12-24 05:22:40 +0100 (Fri, 24 Dec 2010) | 1 line
  
  Added an XXX note to describe timedelta/timedelta feature.
................
  r87471 | raymond.hettinger | 2010-12-24 11:02:22 +0100 (Fri, 24 Dec 2010) | 20 lines
  
  Improve diff for assertCountEqual() to actually show the differing counts.
  
  New output looks like this: 
  
  Traceback (most recent call last):
    File "test.py", line 5, in test_ce
      self.assertCountEqual('abracadabra xx', 'simsalabim xx')
  AssertionError: Element counts were not equal:
  Expected 5, got 2:  'a'
  Expected 2, got 1:  'b'
  Expected 0, got 2:  'i'
  Expected 0, got 2:  'm'
  Expected 0, got 1:  'l'
  Expected 0, got 2:  's'
  Expected 1, got 0:  'c'
  Expected 1, got 0:  'd'
  Expected 2, got 0:  'r'
................
  r87472 | raymond.hettinger | 2010-12-24 11:04:00 +0100 (Fri, 24 Dec 2010) | 1 line
  
  Add news entry for 87471.
................
  r87473 | raymond.hettinger | 2010-12-24 11:30:06 +0100 (Fri, 24 Dec 2010) | 1 line
  
  Add direct tests for the util functions.
................
  r87474 | raymond.hettinger | 2010-12-24 12:20:30 +0100 (Fri, 24 Dec 2010) | 1 line
  
  Put diff output in useful order (when the elements were first seen).
................
  r87475 | raymond.hettinger | 2010-12-24 12:24:00 +0100 (Fri, 24 Dec 2010) | 1 line
  
  Keep helper functions private.
................
  r87476 | vinay.sajip | 2010-12-24 13:03:48 +0100 (Fri, 24 Dec 2010) | 1 line
  
  Logging documentation updates.
................
  r87477 | raymond.hettinger | 2010-12-24 22:51:48 +0100 (Fri, 24 Dec 2010) | 1 line
  
  Adopt symmetric names for arguments (actual/expected --> first/second).
................
  r87478 | terry.reedy | 2010-12-24 22:59:03 +0100 (Fri, 24 Dec 2010) | 2 lines
  
  Match current tracker name, though I do not know if still active.
................
  r87479 | r.david.murray | 2010-12-24 23:36:49 +0100 (Fri, 24 Dec 2010) | 8 lines
  
  #1693546: don't add quotes around RFC 2231 encoded values.
  
  The RFC is bit hard to understand on this point, but the examples
  clearly show that parameter values that are encoded according
  to its charset/language rules don't have surrounding quotes, and
  the ABNF does not allow for quotes.  So when we produce such
  encoded values, we no longer add quotes.
................
  r87482 | brian.quinlan | 2010-12-25 00:10:41 +0100 (Sat, 25 Dec 2010) | 1 line
  
  Better reporting of test failures on Windows.
................
  r87483 | brian.quinlan | 2010-12-25 01:18:27 +0100 (Sat, 25 Dec 2010) | 1 line
  
  Assign closed handles to None to make errors more obvious if they are used.
................
  r87485 | victor.stinner | 2010-12-25 23:40:32 +0100 (Sat, 25 Dec 2010) | 5 lines
  
  Issue #10763: subprocess.communicate() closes stdout and stderr if both are
  pipes (bug specific to Windows).
  
  Improve also the unit test: write a portable unit test.
................
  r87486 | eric.araujo | 2010-12-26 03:18:49 +0100 (Sun, 26 Dec 2010) | 2 lines
  
  Fix typo spotted by Rodrigo Bernardo Pimentel (#9891)
................
  r87489 | eric.araujo | 2010-12-26 03:38:05 +0100 (Sun, 26 Dec 2010) | 2 lines
  
  Remove unexistent parameter (#3216)
................
  r87492 | terry.reedy | 2010-12-26 04:48:35 +0100 (Sun, 26 Dec 2010) | 1 line
  
  revert 87478
................
  r87493 | eric.araujo | 2010-12-26 18:53:27 +0100 (Sun, 26 Dec 2010) | 2 lines
  
  Fix typo (#10770)
................
  r87496 | vinay.sajip | 2010-12-26 19:47:51 +0100 (Sun, 26 Dec 2010) | 1 line
  
  Improved logging cookbook for logging with multiprocessing.
................
  r87497 | r.david.murray | 2010-12-26 20:54:29 +0100 (Sun, 26 Dec 2010) | 10 lines
  
  #5258/#10642: print fn, line, traceback and continue when .pth file is broken
  
  If a .pth file contained an error, it could cause a traceback in site.py,
  terminating its processing.  In 2.7 and 3.2, the interpreter will then not
  start.  Previously, a message would print saying to use -v to get the
  traceback.  In either case, the traceback generated for a failed .pth file did
  not include the .pth filename, making it difficult to debug the problem.  Now
  site.py reports not only the .pth filename but also the line number causing the
  error, and just skips the remainder of the file.
................
  r87498 | vinay.sajip | 2010-12-26 22:22:33 +0100 (Sun, 26 Dec 2010) | 1 line
  
  Added logging documentation cross-references.
................
  r87501 | r.david.murray | 2010-12-27 01:03:13 +0100 (Mon, 27 Dec 2010) | 2 lines
  
  Escape file path before searching for it in output via regex
................
  r87504 | victor.stinner | 2010-12-27 02:49:26 +0100 (Mon, 27 Dec 2010) | 1 line
  
  Issue #9738: Document encodings of error and warning functions
................
  r87505 | victor.stinner | 2010-12-27 02:49:29 +0100 (Mon, 27 Dec 2010) | 1 line
  
  Issue #9738: document encodings of unicode functions
................
  r87506 | victor.stinner | 2010-12-27 02:49:31 +0100 (Mon, 27 Dec 2010) | 1 line
  
  Issue #9738: Document encodings of AST, compiler, parser and PyRun functions
................
  r87507 | victor.stinner | 2010-12-27 03:39:20 +0100 (Mon, 27 Dec 2010) | 1 line
  
  Issue #9738: Ooops, fix typos in my previous commit (r87506)
................
  r87508 | r.david.murray | 2010-12-27 05:31:48 +0100 (Mon, 27 Dec 2010) | 5 lines
  
  Skip test that does not raise an error on Windows.
  
  I'm assuming that the putative path from the malformed
  pth file is simply not found and therefore ignored.
................
  r87512 | vinay.sajip | 2010-12-27 12:18:52 +0100 (Mon, 27 Dec 2010) | 1 line
  
  Issue #10774: test_logging now removes temp files created during tests.
................
  r87513 | vinay.sajip | 2010-12-27 15:31:52 +0100 (Mon, 27 Dec 2010) | 1 line
  
  Issue #10626: test_logging now preserves logger disabled states.
................
  r87514 | vinay.sajip | 2010-12-27 19:34:25 +0100 (Mon, 27 Dec 2010) | 1 line
  
  Issue #10626: test_logging now preserves logger disabled states.
................
  r87516 | r.david.murray | 2010-12-27 21:09:32 +0100 (Mon, 27 Dec 2010) | 5 lines
  
  #7056: runtest and runtest_inner don't use testdir, so drop it from their sigs
  
  I've only tested regular runs and -j runs.  If I've broken anything
  else I'm sure I'll hear about it sooner or later.
................
  r87517 | victor.stinner | 2010-12-27 21:10:36 +0100 (Mon, 27 Dec 2010) | 3 lines
  
  Issue #10779: PyErr_WarnExplicit() decodes the filename from the filesystem
  encoding instead of UTF-8.
................
  r87518 | victor.stinner | 2010-12-27 21:12:13 +0100 (Mon, 27 Dec 2010) | 3 lines
  
  Issue #10778: decoding_fgets() decodes the filename from the filesystem
  encoding instead of UTF-8.
................
  r87519 | victor.stinner | 2010-12-28 01:28:21 +0100 (Tue, 28 Dec 2010) | 3 lines
  
  Issue #10780: PyErr_SetFromWindowsErrWithFilename() and
  PyErr_SetExcFromWindowsErrWithFilename() decode the filename from the
  filesystem encoding instead of UTF-8.
................
  r87520 | victor.stinner | 2010-12-28 01:59:02 +0100 (Tue, 28 Dec 2010) | 3 lines
  
  Issue #8966: Remove the documentation of ctypes.set_conversion_mode()
  
  Function removed by r83195.
................
  r87521 | victor.stinner | 2010-12-28 01:59:03 +0100 (Tue, 28 Dec 2010) | 3 lines
  
  Issue #10780: Remove commas at the end of the argument list
  
  Forbidden in C, stupid language!
................
  r87522 | georg.brandl | 2010-12-28 10:16:12 +0100 (Tue, 28 Dec 2010) | 1 line
  
  Replace sys.maxint mention by sys.maxsize.
................
  r87523 | georg.brandl | 2010-12-28 10:18:24 +0100 (Tue, 28 Dec 2010) | 1 line
  
  Remove confusing paragraph -- this is relevant only to advanced users anyway and does not belong into the tutorial.
................
  r87524 | georg.brandl | 2010-12-28 10:29:19 +0100 (Tue, 28 Dec 2010) | 1 line
  
  Fix advice: call PyType_Ready to fill in ob_type of custom types.
................
  r87525 | georg.brandl | 2010-12-28 10:51:43 +0100 (Tue, 28 Dec 2010) | 1 line
  
  #10679: install idle, pydoc, 2to3 scripts with X.Y suffix for make altinstall; create symlinks for make install.
................
  r87526 | georg.brandl | 2010-12-28 11:38:33 +0100 (Tue, 28 Dec 2010) | 1 line
  
  #10777: fix iteration over dict keys while mutating the dict.
................
  r87527 | georg.brandl | 2010-12-28 11:56:20 +0100 (Tue, 28 Dec 2010) | 1 line
  
  #10768: fix ScrolledText widget construction, and make the example work from the interactive shell.
................
  r87528 | georg.brandl | 2010-12-28 12:02:12 +0100 (Tue, 28 Dec 2010) | 1 line
  
  Add news entry and clarify another.
................
  r87529 | victor.stinner | 2010-12-28 12:02:46 +0100 (Tue, 28 Dec 2010) | 2 lines
  
  Issue #9738: Fix typo, ASCII-encoding string => ASCII-encoded string
................
  r87530 | georg.brandl | 2010-12-28 12:06:07 +0100 (Tue, 28 Dec 2010) | 1 line
  
  #10767: update README in crashers; not all may have a bug entry and/or be fixed.
................
  r87531 | georg.brandl | 2010-12-28 12:08:17 +0100 (Tue, 28 Dec 2010) | 1 line
  
  #10742: document readonly attribute of memoryviews.
................
  r87532 | georg.brandl | 2010-12-28 12:15:49 +0100 (Tue, 28 Dec 2010) | 1 line
  
  #10781: clarify that *encoding* is not a parameter for Node objects in general.
................
  r87533 | georg.brandl | 2010-12-28 12:38:12 +0100 (Tue, 28 Dec 2010) | 1 line
  
  Remove history; adapt a bit more to reST, since this will once be part of the dev guide.
................
  r87534 | georg.brandl | 2010-12-28 12:48:53 +0100 (Tue, 28 Dec 2010) | 1 line
  
  Rewrap.
................
  r87535 | georg.brandl | 2010-12-28 12:49:41 +0100 (Tue, 28 Dec 2010) | 1 line
  
  #10739: document that on Windows, socket.makefile() does not make a file that has a true file descriptor usable where such a thing is expected.
................
  r87536 | georg.brandl | 2010-12-28 12:53:25 +0100 (Tue, 28 Dec 2010) | 1 line
  
  #10609: fix non-working dbm example.
................
  r87537 | victor.stinner | 2010-12-28 14:26:42 +0100 (Tue, 28 Dec 2010) | 6 lines
  
  Issue #10783: struct.pack() doesn't encode implicitly unicode to UTF-8
  
   * Replace "bytes" by "bytes object" in struct error messages
   * Document the API change in What's new in Python 3.2
   * Fix test_wave
   * Remove also ugly implicit conversions in test_struct
................
  r87538 | victor.stinner | 2010-12-28 14:33:43 +0100 (Tue, 28 Dec 2010) | 1 line
  
  Issue #10783: Fix test_sys, pack('c', ' ') => pack('c', b' ')
................
  r87539 | brian.curtin | 2010-12-28 15:31:47 +0100 (Tue, 28 Dec 2010) | 3 lines
  
  Fix #9333. The symlink function is always available now, raising OSError
  when the user doesn't hold the symbolic link privilege rather than hiding it.
................
  r87542 | senthil.kumaran | 2010-12-28 16:55:16 +0100 (Tue, 28 Dec 2010) | 3 lines
  
  Fix Issue10759 - html.parser.unescape() fails on HTML entities with incorrect syntax
................
  r87547 | brian.curtin | 2010-12-28 18:08:22 +0100 (Tue, 28 Dec 2010) | 3 lines
  
  Minor doc update for #9333. Took out the phrasing about os.symlink not
  existing and mentioned the OSError possibility.
................
  r87548 | brian.curtin | 2010-12-28 18:12:43 +0100 (Tue, 28 Dec 2010) | 3 lines
  
  This file was obsolted by a number of adjustments to the os.symlink tests
  on Windows, and is no longer needed by any tests or Lib/test/support.py
................
  r87549 | georg.brandl | 2010-12-28 19:30:18 +0100 (Tue, 28 Dec 2010) | 1 line
  
  Add sys.flags.quiet attribute for the new -q option, as noted missing by Eric in #1772833.
................
  r87550 | r.david.murray | 2010-12-28 19:54:13 +0100 (Tue, 28 Dec 2010) | 8 lines
  
  #9824: encode , and ; in cookie values so that browsers don't split on them
  
  There is a small chance of backward incompatibility here, but only for
  non-SimpleCookie applications reading SimpleCookie generated cookies.  Even
  then, any such ap is likely to be handling escaped values already, and it would
  take a fairly perverse implementation of unescaping to fail to unescape these
  newly escaped chars, so the risk seems minimal.
................
  r87553 | terry.reedy | 2010-12-28 20:30:19 +0100 (Tue, 28 Dec 2010) | 2 lines
  
  Issue 10738: Fix webbrowser.Opera.raise_opts value.
................
  r87556 | brian.quinlan | 2010-12-28 22:14:34 +0100 (Tue, 28 Dec 2010) | 1 line
  
  Does not install a logging handler. Fixes issue 10626.
................
  r87557 | victor.stinner | 2010-12-29 00:05:20 +0100 (Wed, 29 Dec 2010) | 1 line
  
  Compile pgenmain.c and printgrammar.c with PGEN defined
................
  r87558 | victor.stinner | 2010-12-29 00:14:17 +0100 (Wed, 29 Dec 2010) | 1 line
  
  Don't ignore pgen error (on "make Parser/pgen.stamp")
................
  r87559 | victor.stinner | 2010-12-29 00:35:10 +0100 (Wed, 29 Dec 2010) | 1 line
  
  Issue #10783: rephrase the changelog (NEWS, What's new)
................
  r87560 | victor.stinner | 2010-12-29 00:39:51 +0100 (Wed, 29 Dec 2010) | 1 line
  
  Rephrase PyUnicode_CompareWithASCIIString() documentation
................
  r87561 | brian.curtin | 2010-12-29 03:04:28 +0100 (Wed, 29 Dec 2010) | 2 lines
  
  Fix #9333 on Windows XP, where os.symlink is not a possibility.
................
  r87562 | brian.curtin | 2010-12-29 03:41:07 +0100 (Wed, 29 Dec 2010) | 2 lines
  
  Close stdout, clear ResourceWarning
................
  r87563 | victor.stinner | 2010-12-29 03:44:42 +0100 (Wed, 29 Dec 2010) | 1 line
  
  Issue #10783: rephrase the changelog (new try)
................
  r87564 | senthil.kumaran | 2010-12-29 07:25:42 +0100 (Wed, 29 Dec 2010) | 3 lines
  
  Fix Issue 10753 - Don't quote ;=, in the PATH_INFO envvar.
................
  r87567 | r.david.murray | 2010-12-29 17:57:24 +0100 (Wed, 29 Dec 2010) | 2 lines
  
  Fix a comment typo and update another comment to match Python3 reality                                                                                                                                                                                                                 
................
  r87569 | terry.reedy | 2010-12-29 20:02:07 +0100 (Wed, 29 Dec 2010) | 2 lines
  
  Minor clarification
................
  r87571 | r.david.murray | 2010-12-29 20:06:48 +0100 (Wed, 29 Dec 2010) | 2 lines
  
  Fix same typo in docs.
................
  r87573 | senthil.kumaran | 2010-12-30 08:07:58 +0100 (Thu, 30 Dec 2010) | 3 lines
  
  Fix Issue10793 - hashlib documentation issue on return type of digest
................
  r87575 | martin.v.loewis | 2010-12-30 09:36:37 +0100 (Thu, 30 Dec 2010) | 2 lines
  
  Issue #10542: Document that identifiers use XID_Start XID_Continue*.
................
  r87577 | martin.v.loewis | 2010-12-30 15:55:47 +0100 (Thu, 30 Dec 2010) | 2 lines
  
  Build and install libpython3.so.
................
  r87579 | georg.brandl | 2010-12-30 18:22:33 +0100 (Thu, 30 Dec 2010) | 1 line
  
  Remove some of the old demos.  (Put a few somewhere else.)
................
  r87580 | georg.brandl | 2010-12-30 18:32:22 +0100 (Thu, 30 Dec 2010) | 1 line
  
  Clean up tools: remove "world" and "framer", move single SSL script to scripts/.
................
  r87581 | georg.brandl | 2010-12-30 18:36:17 +0100 (Thu, 30 Dec 2010) | 1 line
  
  Fix NameErrors.
................
  r87582 | michael.foord | 2010-12-30 20:36:29 +0100 (Thu, 30 Dec 2010) | 1 line
  
  Issue 10786: unittest.TextTestRunner default stream no longer bound at import time
................
  r87583 | georg.brandl | 2010-12-30 22:33:07 +0100 (Thu, 30 Dec 2010) | 1 line
  
  More cleanup: Move some demos into a dedicated Tools/demo dir, move 2to3 demo to Tools, and remove all the other Demo content.
................
  r87584 | georg.brandl | 2010-12-30 22:33:49 +0100 (Thu, 30 Dec 2010) | 1 line
  
  Remove the actual Demo dir.
................
  r87585 | georg.brandl | 2010-12-30 23:11:50 +0100 (Thu, 30 Dec 2010) | 1 line
  
  Harmonize docstrings.  Move redemo from Tools/scripts to Tools/demo.  Add a README file to Tools/demo.
................
  r87586 | georg.brandl | 2010-12-30 23:12:40 +0100 (Thu, 30 Dec 2010) | 1 line
  
  Remove mentions of the Demo directory.
................
  r87587 | georg.brandl | 2010-12-30 23:31:10 +0100 (Thu, 30 Dec 2010) | 1 line
  
  Add the missing __main__.py in the turtledemo package.  It seems to have been lost during some mass rename action (r86095).
................
  r87588 | georg.brandl | 2010-12-30 23:32:49 +0100 (Thu, 30 Dec 2010) | 1 line
  
  Update README, remove empty directory.
................
  r87589 | vinay.sajip | 2010-12-31 00:26:50 +0100 (Fri, 31 Dec 2010) | 1 line
  
  Issue #10788: Changed test_logging setUp logic to provide more information.
................
  r87590 | r.david.murray | 2010-12-31 20:21:14 +0100 (Fri, 31 Dec 2010) | 4 lines
  
  #9361: add some tests for calendar.leapdays
  
  Patch by John Chandler.
................
  r87593 | georg.brandl | 2011-01-01 00:00:03 +0100 (Sat, 01 Jan 2011) | 1 line
  
  Happy New Year!  (CET edition)
................
  r87594 | raymond.hettinger | 2011-01-01 00:16:17 +0100 (Sat, 01 Jan 2011) | 1 line
  
  Fix OrderedDict.setdefault() to work for subclasses that define __missing__().
................
  r87595 | raymond.hettinger | 2011-01-01 00:23:06 +0100 (Sat, 01 Jan 2011) | 2 lines
  
  Typo.
................
  r87598 | terry.reedy | 2011-01-01 03:25:36 +0100 (Sat, 01 Jan 2011) | 2 lines
  
  Issue 6285: catch missing IDLE help file.
................
  r87601 | terry.reedy | 2011-01-01 03:54:11 +0100 (Sat, 01 Jan 2011) | 2 lines
  
  Issue 6285: add NEWS entry for 3.2.
................
  r87603 | georg.brandl | 2011-01-01 11:07:30 +0100 (Sat, 01 Jan 2011) | 1 line
  
  Fix issue references.
................
  r87604 | georg.brandl | 2011-01-01 11:09:32 +0100 (Sat, 01 Jan 2011) | 1 line
  
  #10801: In zipfile, support different encodings for the header and the filenames.  Patch by MvL, test by Eli Bendersky.
................
  r87606 | georg.brandl | 2011-01-01 11:42:31 +0100 (Sat, 01 Jan 2011) | 1 line
  
  #10801: do not actually extract, just open() the files in the test zipfile.
................
  r87607 | benjamin.peterson | 2011-01-01 15:28:31 +0100 (Sat, 01 Jan 2011) | 1 line
  
  update copyright to 2011
................
  r87610 | gregory.p.smith | 2011-01-01 22:18:46 +0100 (Sat, 01 Jan 2011) | 2 lines
  
  post release bump
................
  r87611 | raymond.hettinger | 2011-01-01 23:38:00 +0100 (Sat, 01 Jan 2011) | 1 line
  
  Make it easier to extend OrderedDict without breaking it.
................
  r87612 | raymond.hettinger | 2011-01-02 00:51:55 +0100 (Sun, 02 Jan 2011) | 1 line
  
  Fix OrderedDic.pop() to work for subclasses that define  __missing__().
................
  r87615 | raymond.hettinger | 2011-01-02 09:03:33 +0100 (Sun, 02 Jan 2011) | 4 lines
  
  Fix doctest to not rely on order of dictionary entries.
  Use super() instead of direct references to the dict superclass.
................


Added:
   python/branches/py3k-cdecimal/Doc/howto/logging-cookbook.rst
      - copied unchanged from r87615, /python/branches/py3k/Doc/howto/logging-cookbook.rst
   python/branches/py3k-cdecimal/Doc/howto/logging.rst
      - copied unchanged from r87615, /python/branches/py3k/Doc/howto/logging.rst
   python/branches/py3k-cdecimal/Doc/library/logging.config.rst
      - copied unchanged from r87615, /python/branches/py3k/Doc/library/logging.config.rst
   python/branches/py3k-cdecimal/Doc/library/logging.handlers.rst
      - copied unchanged from r87615, /python/branches/py3k/Doc/library/logging.handlers.rst
   python/branches/py3k-cdecimal/Include/typeslots.h
      - copied unchanged from r87615, /python/branches/py3k/Include/typeslots.h
   python/branches/py3k-cdecimal/Lib/encodings/base64_codec.py
      - copied unchanged from r87615, /python/branches/py3k/Lib/encodings/base64_codec.py
   python/branches/py3k-cdecimal/Lib/encodings/bz2_codec.py
      - copied unchanged from r87615, /python/branches/py3k/Lib/encodings/bz2_codec.py
   python/branches/py3k-cdecimal/Lib/encodings/hex_codec.py
      - copied unchanged from r87615, /python/branches/py3k/Lib/encodings/hex_codec.py
   python/branches/py3k-cdecimal/Lib/encodings/quopri_codec.py
      - copied unchanged from r87615, /python/branches/py3k/Lib/encodings/quopri_codec.py
   python/branches/py3k-cdecimal/Lib/encodings/rot_13.py
      - copied unchanged from r87615, /python/branches/py3k/Lib/encodings/rot_13.py
   python/branches/py3k-cdecimal/Lib/encodings/uu_codec.py
      - copied unchanged from r87615, /python/branches/py3k/Lib/encodings/uu_codec.py
   python/branches/py3k-cdecimal/Lib/encodings/zlib_codec.py
      - copied unchanged from r87615, /python/branches/py3k/Lib/encodings/zlib_codec.py
   python/branches/py3k-cdecimal/Lib/pydoc_data/_pydoc.css
      - copied unchanged from r87615, /python/branches/py3k/Lib/pydoc_data/_pydoc.css
   python/branches/py3k-cdecimal/Lib/test/__main__.py
      - copied unchanged from r87615, /python/branches/py3k/Lib/test/__main__.py
   python/branches/py3k-cdecimal/Lib/test/json_tests/   (props changed)
      - copied from r87615, /python/branches/py3k/Lib/test/json_tests/
   python/branches/py3k-cdecimal/Lib/test/subprocessdata/
      - copied from r87615, /python/branches/py3k/Lib/test/subprocessdata/
   python/branches/py3k-cdecimal/Lib/test/zip_cp437_header.zip
      - copied unchanged from r87615, /python/branches/py3k/Lib/test/zip_cp437_header.zip
   python/branches/py3k-cdecimal/Lib/turtledemo/__main__.py
      - copied unchanged from r87615, /python/branches/py3k/Lib/turtledemo/__main__.py
   python/branches/py3k-cdecimal/Lib/unittest/test/_test_warnings.py
      - copied unchanged from r87615, /python/branches/py3k/Lib/unittest/test/_test_warnings.py
   python/branches/py3k-cdecimal/Modules/xxlimited.c
      - copied unchanged from r87615, /python/branches/py3k/Modules/xxlimited.c
   python/branches/py3k-cdecimal/Objects/typeslots.inc
      - copied unchanged from r87615, /python/branches/py3k/Objects/typeslots.inc
   python/branches/py3k-cdecimal/Objects/typeslots.py
      - copied unchanged from r87615, /python/branches/py3k/Objects/typeslots.py
   python/branches/py3k-cdecimal/PC/python3.def
      - copied unchanged from r87615, /python/branches/py3k/PC/python3.def
   python/branches/py3k-cdecimal/PC/python3.mak
      - copied unchanged from r87615, /python/branches/py3k/PC/python3.mak
   python/branches/py3k-cdecimal/PC/python32gen.py
      - copied unchanged from r87615, /python/branches/py3k/PC/python32gen.py
   python/branches/py3k-cdecimal/PC/python32stub.def
      - copied unchanged from r87615, /python/branches/py3k/PC/python32stub.def
   python/branches/py3k-cdecimal/PC/python3dll.c
      - copied unchanged from r87615, /python/branches/py3k/PC/python3dll.c
   python/branches/py3k-cdecimal/PCbuild/python3dll.vcproj
      - copied unchanged from r87615, /python/branches/py3k/PCbuild/python3dll.vcproj
   python/branches/py3k-cdecimal/PCbuild/xxlimited.vcproj
      - copied unchanged from r87615, /python/branches/py3k/PCbuild/xxlimited.vcproj
   python/branches/py3k-cdecimal/Tools/demo/
      - copied from r87615, /python/branches/py3k/Tools/demo/
   python/branches/py3k-cdecimal/Tools/parser/
      - copied from r87615, /python/branches/py3k/Tools/parser/
   python/branches/py3k-cdecimal/Tools/scripts/abitype.py
      - copied unchanged from r87615, /python/branches/py3k/Tools/scripts/abitype.py
   python/branches/py3k-cdecimal/Tools/scripts/find-uname.py
      - copied unchanged from r87615, /python/branches/py3k/Tools/scripts/find-uname.py
   python/branches/py3k-cdecimal/Tools/scripts/get-remote-certificate.py
      - copied unchanged from r87615, /python/branches/py3k/Tools/scripts/get-remote-certificate.py
   python/branches/py3k-cdecimal/Tools/test2to3/   (props changed)
      - copied from r87615, /python/branches/py3k/Tools/test2to3/
Removed:
   python/branches/py3k-cdecimal/Demo/
   python/branches/py3k-cdecimal/Lib/json/tests/
   python/branches/py3k-cdecimal/Lib/test/symlink_support.py
   python/branches/py3k-cdecimal/Misc/RFD
   python/branches/py3k-cdecimal/Misc/pymemcompat.h
   python/branches/py3k-cdecimal/Misc/setuid-prog.c
   python/branches/py3k-cdecimal/Tools/framer/
   python/branches/py3k-cdecimal/Tools/scripts/redemo.py
   python/branches/py3k-cdecimal/Tools/ssl/
   python/branches/py3k-cdecimal/Tools/world/
   python/branches/py3k-cdecimal/runtests.sh
Modified:
   python/branches/py3k-cdecimal/   (props changed)
   python/branches/py3k-cdecimal/.gitignore
   python/branches/py3k-cdecimal/Doc/ACKS.txt
   python/branches/py3k-cdecimal/Doc/README.txt
   python/branches/py3k-cdecimal/Doc/c-api/buffer.rst
   python/branches/py3k-cdecimal/Doc/c-api/codec.rst
   python/branches/py3k-cdecimal/Doc/c-api/exceptions.rst
   python/branches/py3k-cdecimal/Doc/c-api/import.rst
   python/branches/py3k-cdecimal/Doc/c-api/init.rst
   python/branches/py3k-cdecimal/Doc/c-api/intro.rst
   python/branches/py3k-cdecimal/Doc/c-api/list.rst
   python/branches/py3k-cdecimal/Doc/c-api/slice.rst
   python/branches/py3k-cdecimal/Doc/c-api/typeobj.rst
   python/branches/py3k-cdecimal/Doc/c-api/unicode.rst
   python/branches/py3k-cdecimal/Doc/c-api/veryhigh.rst
   python/branches/py3k-cdecimal/Doc/copyright.rst
   python/branches/py3k-cdecimal/Doc/distutils/apiref.rst
   python/branches/py3k-cdecimal/Doc/documenting/markup.rst
   python/branches/py3k-cdecimal/Doc/extending/embedding.rst
   python/branches/py3k-cdecimal/Doc/extending/extending.rst
   python/branches/py3k-cdecimal/Doc/extending/windows.rst
   python/branches/py3k-cdecimal/Doc/faq/extending.rst
   python/branches/py3k-cdecimal/Doc/glossary.rst
   python/branches/py3k-cdecimal/Doc/howto/index.rst
   python/branches/py3k-cdecimal/Doc/includes/tzinfo-examples.py
   python/branches/py3k-cdecimal/Doc/install/index.rst
   python/branches/py3k-cdecimal/Doc/library/_thread.rst
   python/branches/py3k-cdecimal/Doc/library/allos.rst
   python/branches/py3k-cdecimal/Doc/library/argparse.rst
   python/branches/py3k-cdecimal/Doc/library/array.rst
   python/branches/py3k-cdecimal/Doc/library/bdb.rst
   python/branches/py3k-cdecimal/Doc/library/builtins.rst
   python/branches/py3k-cdecimal/Doc/library/codecs.rst
   python/branches/py3k-cdecimal/Doc/library/collections.rst
   python/branches/py3k-cdecimal/Doc/library/compileall.rst
   python/branches/py3k-cdecimal/Doc/library/concurrent.futures.rst
   python/branches/py3k-cdecimal/Doc/library/configparser.rst
   python/branches/py3k-cdecimal/Doc/library/ctypes.rst
   python/branches/py3k-cdecimal/Doc/library/curses.rst
   python/branches/py3k-cdecimal/Doc/library/dbm.rst
   python/branches/py3k-cdecimal/Doc/library/difflib.rst
   python/branches/py3k-cdecimal/Doc/library/dis.rst
   python/branches/py3k-cdecimal/Doc/library/doctest.rst
   python/branches/py3k-cdecimal/Doc/library/email.header.rst
   python/branches/py3k-cdecimal/Doc/library/email.message.rst
   python/branches/py3k-cdecimal/Doc/library/email.util.rst
   python/branches/py3k-cdecimal/Doc/library/exceptions.rst
   python/branches/py3k-cdecimal/Doc/library/fileformats.rst
   python/branches/py3k-cdecimal/Doc/library/functions.rst
   python/branches/py3k-cdecimal/Doc/library/functools.rst
   python/branches/py3k-cdecimal/Doc/library/grp.rst
   python/branches/py3k-cdecimal/Doc/library/hashlib.rst
   python/branches/py3k-cdecimal/Doc/library/heapq.rst
   python/branches/py3k-cdecimal/Doc/library/html.parser.rst
   python/branches/py3k-cdecimal/Doc/library/http.client.rst
   python/branches/py3k-cdecimal/Doc/library/imp.rst
   python/branches/py3k-cdecimal/Doc/library/inspect.rst
   python/branches/py3k-cdecimal/Doc/library/io.rst
   python/branches/py3k-cdecimal/Doc/library/itertools.rst
   python/branches/py3k-cdecimal/Doc/library/logging.rst
   python/branches/py3k-cdecimal/Doc/library/msilib.rst
   python/branches/py3k-cdecimal/Doc/library/multiprocessing.rst
   python/branches/py3k-cdecimal/Doc/library/os.path.rst
   python/branches/py3k-cdecimal/Doc/library/os.rst
   python/branches/py3k-cdecimal/Doc/library/parser.rst
   python/branches/py3k-cdecimal/Doc/library/pdb.rst
   python/branches/py3k-cdecimal/Doc/library/pickle.rst
   python/branches/py3k-cdecimal/Doc/library/pkgutil.rst
   python/branches/py3k-cdecimal/Doc/library/platform.rst
   python/branches/py3k-cdecimal/Doc/library/pty.rst
   python/branches/py3k-cdecimal/Doc/library/py_compile.rst
   python/branches/py3k-cdecimal/Doc/library/pydoc.rst
   python/branches/py3k-cdecimal/Doc/library/random.rst
   python/branches/py3k-cdecimal/Doc/library/re.rst
   python/branches/py3k-cdecimal/Doc/library/runpy.rst
   python/branches/py3k-cdecimal/Doc/library/shelve.rst
   python/branches/py3k-cdecimal/Doc/library/socket.rst
   python/branches/py3k-cdecimal/Doc/library/someos.rst
   python/branches/py3k-cdecimal/Doc/library/sqlite3.rst
   python/branches/py3k-cdecimal/Doc/library/stdtypes.rst
   python/branches/py3k-cdecimal/Doc/library/string.rst
   python/branches/py3k-cdecimal/Doc/library/struct.rst
   python/branches/py3k-cdecimal/Doc/library/subprocess.rst
   python/branches/py3k-cdecimal/Doc/library/sys.rst
   python/branches/py3k-cdecimal/Doc/library/test.rst
   python/branches/py3k-cdecimal/Doc/library/textwrap.rst
   python/branches/py3k-cdecimal/Doc/library/threading.rst
   python/branches/py3k-cdecimal/Doc/library/tkinter.rst
   python/branches/py3k-cdecimal/Doc/library/tkinter.tix.rst
   python/branches/py3k-cdecimal/Doc/library/trace.rst
   python/branches/py3k-cdecimal/Doc/library/turtle.rst
   python/branches/py3k-cdecimal/Doc/library/unicodedata.rst
   python/branches/py3k-cdecimal/Doc/library/unittest.rst
   python/branches/py3k-cdecimal/Doc/library/urllib.parse.rst
   python/branches/py3k-cdecimal/Doc/library/urllib.request.rst
   python/branches/py3k-cdecimal/Doc/library/warnings.rst
   python/branches/py3k-cdecimal/Doc/library/xml.dom.minidom.rst
   python/branches/py3k-cdecimal/Doc/library/zipfile.rst
   python/branches/py3k-cdecimal/Doc/license.rst
   python/branches/py3k-cdecimal/Doc/reference/datamodel.rst
   python/branches/py3k-cdecimal/Doc/reference/expressions.rst
   python/branches/py3k-cdecimal/Doc/reference/lexical_analysis.rst
   python/branches/py3k-cdecimal/Doc/tools/sphinxext/static/basic.css
   python/branches/py3k-cdecimal/Doc/tools/sphinxext/susp-ignored.csv
   python/branches/py3k-cdecimal/Doc/tutorial/interpreter.rst
   python/branches/py3k-cdecimal/Doc/tutorial/stdlib.rst
   python/branches/py3k-cdecimal/Doc/using/cmdline.rst
   python/branches/py3k-cdecimal/Doc/whatsnew/2.7.rst
   python/branches/py3k-cdecimal/Doc/whatsnew/3.2.rst
   python/branches/py3k-cdecimal/Include/Python.h
   python/branches/py3k-cdecimal/Include/abstract.h
   python/branches/py3k-cdecimal/Include/ast.h
   python/branches/py3k-cdecimal/Include/bytearrayobject.h
   python/branches/py3k-cdecimal/Include/bytes_methods.h
   python/branches/py3k-cdecimal/Include/bytesobject.h
   python/branches/py3k-cdecimal/Include/cellobject.h
   python/branches/py3k-cdecimal/Include/ceval.h
   python/branches/py3k-cdecimal/Include/classobject.h
   python/branches/py3k-cdecimal/Include/code.h
   python/branches/py3k-cdecimal/Include/codecs.h
   python/branches/py3k-cdecimal/Include/compile.h
   python/branches/py3k-cdecimal/Include/complexobject.h
   python/branches/py3k-cdecimal/Include/datetime.h
   python/branches/py3k-cdecimal/Include/descrobject.h
   python/branches/py3k-cdecimal/Include/dictobject.h
   python/branches/py3k-cdecimal/Include/dtoa.h
   python/branches/py3k-cdecimal/Include/eval.h
   python/branches/py3k-cdecimal/Include/fileobject.h
   python/branches/py3k-cdecimal/Include/floatobject.h
   python/branches/py3k-cdecimal/Include/frameobject.h
   python/branches/py3k-cdecimal/Include/funcobject.h
   python/branches/py3k-cdecimal/Include/genobject.h
   python/branches/py3k-cdecimal/Include/import.h
   python/branches/py3k-cdecimal/Include/listobject.h
   python/branches/py3k-cdecimal/Include/longintrepr.h
   python/branches/py3k-cdecimal/Include/longobject.h
   python/branches/py3k-cdecimal/Include/marshal.h
   python/branches/py3k-cdecimal/Include/memoryobject.h
   python/branches/py3k-cdecimal/Include/methodobject.h
   python/branches/py3k-cdecimal/Include/modsupport.h
   python/branches/py3k-cdecimal/Include/moduleobject.h
   python/branches/py3k-cdecimal/Include/object.h
   python/branches/py3k-cdecimal/Include/objimpl.h
   python/branches/py3k-cdecimal/Include/parsetok.h
   python/branches/py3k-cdecimal/Include/patchlevel.h
   python/branches/py3k-cdecimal/Include/pyarena.h
   python/branches/py3k-cdecimal/Include/pyatomic.h
   python/branches/py3k-cdecimal/Include/pyctype.h
   python/branches/py3k-cdecimal/Include/pydebug.h
   python/branches/py3k-cdecimal/Include/pyerrors.h
   python/branches/py3k-cdecimal/Include/pygetopt.h
   python/branches/py3k-cdecimal/Include/pymath.h
   python/branches/py3k-cdecimal/Include/pystate.h
   python/branches/py3k-cdecimal/Include/pystrtod.h
   python/branches/py3k-cdecimal/Include/pythonrun.h
   python/branches/py3k-cdecimal/Include/pythread.h
   python/branches/py3k-cdecimal/Include/pytime.h
   python/branches/py3k-cdecimal/Include/setobject.h
   python/branches/py3k-cdecimal/Include/sliceobject.h
   python/branches/py3k-cdecimal/Include/structseq.h
   python/branches/py3k-cdecimal/Include/symtable.h
   python/branches/py3k-cdecimal/Include/sysmodule.h
   python/branches/py3k-cdecimal/Include/timefuncs.h
   python/branches/py3k-cdecimal/Include/token.h
   python/branches/py3k-cdecimal/Include/traceback.h
   python/branches/py3k-cdecimal/Include/tupleobject.h
   python/branches/py3k-cdecimal/Include/ucnhash.h
   python/branches/py3k-cdecimal/Include/unicodeobject.h
   python/branches/py3k-cdecimal/Include/warnings.h
   python/branches/py3k-cdecimal/Include/weakrefobject.h
   python/branches/py3k-cdecimal/LICENSE
   python/branches/py3k-cdecimal/Lib/_abcoll.py
   python/branches/py3k-cdecimal/Lib/_pyio.py
   python/branches/py3k-cdecimal/Lib/_weakrefset.py
   python/branches/py3k-cdecimal/Lib/argparse.py
   python/branches/py3k-cdecimal/Lib/bdb.py
   python/branches/py3k-cdecimal/Lib/codecs.py
   python/branches/py3k-cdecimal/Lib/collections.py
   python/branches/py3k-cdecimal/Lib/compileall.py
   python/branches/py3k-cdecimal/Lib/concurrent/futures/_base.py
   python/branches/py3k-cdecimal/Lib/concurrent/futures/process.py
   python/branches/py3k-cdecimal/Lib/configparser.py
   python/branches/py3k-cdecimal/Lib/dbm/dumb.py
   python/branches/py3k-cdecimal/Lib/decimal.py
   python/branches/py3k-cdecimal/Lib/difflib.py
   python/branches/py3k-cdecimal/Lib/distutils/__init__.py
   python/branches/py3k-cdecimal/Lib/distutils/archive_util.py
   python/branches/py3k-cdecimal/Lib/distutils/command/build_ext.py
   python/branches/py3k-cdecimal/Lib/distutils/command/install.py
   python/branches/py3k-cdecimal/Lib/distutils/sysconfig.py
   python/branches/py3k-cdecimal/Lib/doctest.py
   python/branches/py3k-cdecimal/Lib/email/_parseaddr.py
   python/branches/py3k-cdecimal/Lib/email/generator.py
   python/branches/py3k-cdecimal/Lib/email/header.py
   python/branches/py3k-cdecimal/Lib/email/message.py
   python/branches/py3k-cdecimal/Lib/email/test/test_email.py
   python/branches/py3k-cdecimal/Lib/email/utils.py
   python/branches/py3k-cdecimal/Lib/encodings/aliases.py
   python/branches/py3k-cdecimal/Lib/functools.py
   python/branches/py3k-cdecimal/Lib/getpass.py
   python/branches/py3k-cdecimal/Lib/gettext.py
   python/branches/py3k-cdecimal/Lib/html/parser.py
   python/branches/py3k-cdecimal/Lib/http/client.py
   python/branches/py3k-cdecimal/Lib/http/cookies.py
   python/branches/py3k-cdecimal/Lib/http/server.py
   python/branches/py3k-cdecimal/Lib/idlelib/Bindings.py
   python/branches/py3k-cdecimal/Lib/idlelib/EditorWindow.py
   python/branches/py3k-cdecimal/Lib/idlelib/FileList.py
   python/branches/py3k-cdecimal/Lib/idlelib/IOBinding.py
   python/branches/py3k-cdecimal/Lib/idlelib/idlever.py
   python/branches/py3k-cdecimal/Lib/idlelib/macosxSupport.py
   python/branches/py3k-cdecimal/Lib/inspect.py
   python/branches/py3k-cdecimal/Lib/lib2to3/   (props changed)
   python/branches/py3k-cdecimal/Lib/lib2to3/fixes/fix_urllib.py
   python/branches/py3k-cdecimal/Lib/lib2to3/main.py
   python/branches/py3k-cdecimal/Lib/lib2to3/refactor.py
   python/branches/py3k-cdecimal/Lib/lib2to3/tests/test_refactor.py
   python/branches/py3k-cdecimal/Lib/lib2to3/tests/test_util.py
   python/branches/py3k-cdecimal/Lib/logging/__init__.py
   python/branches/py3k-cdecimal/Lib/mimetypes.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/__init__.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/connection.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/dummy/__init__.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/dummy/connection.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/forking.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/heap.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/managers.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/pool.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/process.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/queues.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/reduction.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/sharedctypes.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/synchronize.py
   python/branches/py3k-cdecimal/Lib/multiprocessing/util.py
   python/branches/py3k-cdecimal/Lib/netrc.py
   python/branches/py3k-cdecimal/Lib/numbers.py
   python/branches/py3k-cdecimal/Lib/os.py
   python/branches/py3k-cdecimal/Lib/pdb.py
   python/branches/py3k-cdecimal/Lib/py_compile.py
   python/branches/py3k-cdecimal/Lib/pydoc.py
   python/branches/py3k-cdecimal/Lib/pydoc_data/topics.py
   python/branches/py3k-cdecimal/Lib/random.py
   python/branches/py3k-cdecimal/Lib/shelve.py
   python/branches/py3k-cdecimal/Lib/shutil.py
   python/branches/py3k-cdecimal/Lib/site.py
   python/branches/py3k-cdecimal/Lib/smtpd.py
   python/branches/py3k-cdecimal/Lib/subprocess.py
   python/branches/py3k-cdecimal/Lib/sysconfig.py
   python/branches/py3k-cdecimal/Lib/tabnanny.py
   python/branches/py3k-cdecimal/Lib/telnetlib.py
   python/branches/py3k-cdecimal/Lib/tempfile.py
   python/branches/py3k-cdecimal/Lib/test/crashers/README
   python/branches/py3k-cdecimal/Lib/test/datetimetester.py
   python/branches/py3k-cdecimal/Lib/test/pystone.py
   python/branches/py3k-cdecimal/Lib/test/regrtest.py
   python/branches/py3k-cdecimal/Lib/test/script_helper.py
   python/branches/py3k-cdecimal/Lib/test/support.py
   python/branches/py3k-cdecimal/Lib/test/test_abc.py
   python/branches/py3k-cdecimal/Lib/test/test_argparse.py
   python/branches/py3k-cdecimal/Lib/test/test_array.py
   python/branches/py3k-cdecimal/Lib/test/test_asyncore.py
   python/branches/py3k-cdecimal/Lib/test/test_bool.py
   python/branches/py3k-cdecimal/Lib/test/test_builtin.py
   python/branches/py3k-cdecimal/Lib/test/test_calendar.py
   python/branches/py3k-cdecimal/Lib/test/test_cfgparser.py
   python/branches/py3k-cdecimal/Lib/test/test_cgi.py
   python/branches/py3k-cdecimal/Lib/test/test_cmath.py
   python/branches/py3k-cdecimal/Lib/test/test_cmd_line.py
   python/branches/py3k-cdecimal/Lib/test/test_codecs.py
   python/branches/py3k-cdecimal/Lib/test/test_collections.py
   python/branches/py3k-cdecimal/Lib/test/test_compileall.py
   python/branches/py3k-cdecimal/Lib/test/test_complex.py
   python/branches/py3k-cdecimal/Lib/test/test_concurrent_futures.py
   python/branches/py3k-cdecimal/Lib/test/test_contextlib.py
   python/branches/py3k-cdecimal/Lib/test/test_csv.py
   python/branches/py3k-cdecimal/Lib/test/test_dbm_gnu.py
   python/branches/py3k-cdecimal/Lib/test/test_decimal.py
   python/branches/py3k-cdecimal/Lib/test/test_descr.py
   python/branches/py3k-cdecimal/Lib/test/test_difflib.py
   python/branches/py3k-cdecimal/Lib/test/test_dis.py
   python/branches/py3k-cdecimal/Lib/test/test_float.py
   python/branches/py3k-cdecimal/Lib/test/test_fork1.py
   python/branches/py3k-cdecimal/Lib/test/test_fractions.py
   python/branches/py3k-cdecimal/Lib/test/test_functools.py
   python/branches/py3k-cdecimal/Lib/test/test_grp.py
   python/branches/py3k-cdecimal/Lib/test/test_htmlparser.py
   python/branches/py3k-cdecimal/Lib/test/test_http_cookies.py
   python/branches/py3k-cdecimal/Lib/test/test_httplib.py
   python/branches/py3k-cdecimal/Lib/test/test_httpservers.py
   python/branches/py3k-cdecimal/Lib/test/test_import.py
   python/branches/py3k-cdecimal/Lib/test/test_inspect.py
   python/branches/py3k-cdecimal/Lib/test/test_int.py
   python/branches/py3k-cdecimal/Lib/test/test_io.py
   python/branches/py3k-cdecimal/Lib/test/test_itertools.py
   python/branches/py3k-cdecimal/Lib/test/test_json.py
   python/branches/py3k-cdecimal/Lib/test/test_listcomps.py
   python/branches/py3k-cdecimal/Lib/test/test_logging.py
   python/branches/py3k-cdecimal/Lib/test/test_long.py
   python/branches/py3k-cdecimal/Lib/test/test_math.py
   python/branches/py3k-cdecimal/Lib/test/test_memoryview.py
   python/branches/py3k-cdecimal/Lib/test/test_multiprocessing.py
   python/branches/py3k-cdecimal/Lib/test/test_netrc.py
   python/branches/py3k-cdecimal/Lib/test/test_normalization.py
   python/branches/py3k-cdecimal/Lib/test/test_ntpath.py
   python/branches/py3k-cdecimal/Lib/test/test_os.py
   python/branches/py3k-cdecimal/Lib/test/test_pdb.py
   python/branches/py3k-cdecimal/Lib/test/test_posixpath.py
   python/branches/py3k-cdecimal/Lib/test/test_pydoc.py
   python/branches/py3k-cdecimal/Lib/test/test_pyexpat.py
   python/branches/py3k-cdecimal/Lib/test/test_random.py
   python/branches/py3k-cdecimal/Lib/test/test_range.py
   python/branches/py3k-cdecimal/Lib/test/test_runpy.py
   python/branches/py3k-cdecimal/Lib/test/test_shelve.py
   python/branches/py3k-cdecimal/Lib/test/test_shutil.py
   python/branches/py3k-cdecimal/Lib/test/test_site.py
   python/branches/py3k-cdecimal/Lib/test/test_smtpd.py
   python/branches/py3k-cdecimal/Lib/test/test_smtplib.py
   python/branches/py3k-cdecimal/Lib/test/test_socket.py
   python/branches/py3k-cdecimal/Lib/test/test_ssl.py
   python/branches/py3k-cdecimal/Lib/test/test_struct.py
   python/branches/py3k-cdecimal/Lib/test/test_subprocess.py
   python/branches/py3k-cdecimal/Lib/test/test_sys.py
   python/branches/py3k-cdecimal/Lib/test/test_syslog.py
   python/branches/py3k-cdecimal/Lib/test/test_telnetlib.py
   python/branches/py3k-cdecimal/Lib/test/test_tempfile.py
   python/branches/py3k-cdecimal/Lib/test/test_threadsignals.py
   python/branches/py3k-cdecimal/Lib/test/test_time.py
   python/branches/py3k-cdecimal/Lib/test/test_trace.py
   python/branches/py3k-cdecimal/Lib/test/test_tuple.py
   python/branches/py3k-cdecimal/Lib/test/test_types.py
   python/branches/py3k-cdecimal/Lib/test/test_unicode.py
   python/branches/py3k-cdecimal/Lib/test/test_unicodedata.py
   python/branches/py3k-cdecimal/Lib/test/test_unittest.py
   python/branches/py3k-cdecimal/Lib/test/test_urllib.py
   python/branches/py3k-cdecimal/Lib/test/test_urllib2.py
   python/branches/py3k-cdecimal/Lib/test/test_urllibnet.py
   python/branches/py3k-cdecimal/Lib/test/test_urlparse.py
   python/branches/py3k-cdecimal/Lib/test/test_weakset.py
   python/branches/py3k-cdecimal/Lib/test/test_winsound.py
   python/branches/py3k-cdecimal/Lib/test/test_wsgiref.py
   python/branches/py3k-cdecimal/Lib/test/test_xml_etree.py
   python/branches/py3k-cdecimal/Lib/test/test_xml_etree_c.py
   python/branches/py3k-cdecimal/Lib/test/test_xmlrpc.py
   python/branches/py3k-cdecimal/Lib/test/test_zipfile.py
   python/branches/py3k-cdecimal/Lib/test/test_zipimport_support.py
   python/branches/py3k-cdecimal/Lib/test/test_zlib.py
   python/branches/py3k-cdecimal/Lib/test/win_console_handler.py
   python/branches/py3k-cdecimal/Lib/threading.py
   python/branches/py3k-cdecimal/Lib/tkinter/__init__.py
   python/branches/py3k-cdecimal/Lib/tkinter/scrolledtext.py
   python/branches/py3k-cdecimal/Lib/tkinter/test/test_ttk/test_widgets.py
   python/branches/py3k-cdecimal/Lib/tkinter/tix.py
   python/branches/py3k-cdecimal/Lib/turtle.py
   python/branches/py3k-cdecimal/Lib/turtledemo/about_turtledemo.txt
   python/branches/py3k-cdecimal/Lib/turtledemo/demohelp.txt
   python/branches/py3k-cdecimal/Lib/unittest/case.py
   python/branches/py3k-cdecimal/Lib/unittest/main.py
   python/branches/py3k-cdecimal/Lib/unittest/runner.py
   python/branches/py3k-cdecimal/Lib/unittest/suite.py
   python/branches/py3k-cdecimal/Lib/unittest/test/test_assertions.py
   python/branches/py3k-cdecimal/Lib/unittest/test/test_break.py
   python/branches/py3k-cdecimal/Lib/unittest/test/test_case.py
   python/branches/py3k-cdecimal/Lib/unittest/test/test_discovery.py
   python/branches/py3k-cdecimal/Lib/unittest/test/test_functiontestcase.py
   python/branches/py3k-cdecimal/Lib/unittest/test/test_loader.py
   python/branches/py3k-cdecimal/Lib/unittest/test/test_program.py
   python/branches/py3k-cdecimal/Lib/unittest/test/test_runner.py
   python/branches/py3k-cdecimal/Lib/unittest/test/test_setups.py
   python/branches/py3k-cdecimal/Lib/unittest/test/test_suite.py
   python/branches/py3k-cdecimal/Lib/unittest/util.py
   python/branches/py3k-cdecimal/Lib/urllib/parse.py
   python/branches/py3k-cdecimal/Lib/urllib/request.py
   python/branches/py3k-cdecimal/Lib/wave.py
   python/branches/py3k-cdecimal/Lib/weakref.py
   python/branches/py3k-cdecimal/Lib/webbrowser.py
   python/branches/py3k-cdecimal/Lib/wsgiref/util.py
   python/branches/py3k-cdecimal/Lib/xml/etree/ElementTree.py
   python/branches/py3k-cdecimal/Lib/xmlrpc/client.py
   python/branches/py3k-cdecimal/Lib/zipfile.py
   python/branches/py3k-cdecimal/Mac/BuildScript/build-installer.py
   python/branches/py3k-cdecimal/Mac/Makefile.in
   python/branches/py3k-cdecimal/Mac/README
   python/branches/py3k-cdecimal/Makefile.pre.in
   python/branches/py3k-cdecimal/Misc/ACKS
   python/branches/py3k-cdecimal/Misc/NEWS
   python/branches/py3k-cdecimal/Misc/README
   python/branches/py3k-cdecimal/Misc/RPM/python-3.2.spec
   python/branches/py3k-cdecimal/Misc/SpecialBuilds.txt
   python/branches/py3k-cdecimal/Misc/python-wing4.wpr
   python/branches/py3k-cdecimal/Misc/python.man
   python/branches/py3k-cdecimal/Misc/python.pc.in
   python/branches/py3k-cdecimal/Modules/_collectionsmodule.c
   python/branches/py3k-cdecimal/Modules/_ctypes/_ctypes.c
   python/branches/py3k-cdecimal/Modules/_ctypes/cfield.c
   python/branches/py3k-cdecimal/Modules/_datetimemodule.c
   python/branches/py3k-cdecimal/Modules/_elementtree.c
   python/branches/py3k-cdecimal/Modules/_functoolsmodule.c
   python/branches/py3k-cdecimal/Modules/_gdbmmodule.c
   python/branches/py3k-cdecimal/Modules/_io/bufferedio.c
   python/branches/py3k-cdecimal/Modules/_lsprof.c
   python/branches/py3k-cdecimal/Modules/_posixsubprocess.c
   python/branches/py3k-cdecimal/Modules/_ssl.c
   python/branches/py3k-cdecimal/Modules/_struct.c
   python/branches/py3k-cdecimal/Modules/_testcapimodule.c
   python/branches/py3k-cdecimal/Modules/_threadmodule.c
   python/branches/py3k-cdecimal/Modules/arraymodule.c
   python/branches/py3k-cdecimal/Modules/getpath.c
   python/branches/py3k-cdecimal/Modules/grpmodule.c
   python/branches/py3k-cdecimal/Modules/itertoolsmodule.c
   python/branches/py3k-cdecimal/Modules/main.c
   python/branches/py3k-cdecimal/Modules/mmapmodule.c
   python/branches/py3k-cdecimal/Modules/parsermodule.c
   python/branches/py3k-cdecimal/Modules/posixmodule.c
   python/branches/py3k-cdecimal/Modules/pwdmodule.c
   python/branches/py3k-cdecimal/Modules/pyexpat.c
   python/branches/py3k-cdecimal/Modules/readline.c
   python/branches/py3k-cdecimal/Modules/resource.c
   python/branches/py3k-cdecimal/Modules/signalmodule.c
   python/branches/py3k-cdecimal/Modules/socketmodule.c
   python/branches/py3k-cdecimal/Modules/socketmodule.h
   python/branches/py3k-cdecimal/Modules/spwdmodule.c
   python/branches/py3k-cdecimal/Modules/symtablemodule.c
   python/branches/py3k-cdecimal/Modules/syslogmodule.c
   python/branches/py3k-cdecimal/Modules/timemodule.c
   python/branches/py3k-cdecimal/Modules/unicodedata.c
   python/branches/py3k-cdecimal/Objects/bytearrayobject.c
   python/branches/py3k-cdecimal/Objects/bytesobject.c
   python/branches/py3k-cdecimal/Objects/complexobject.c
   python/branches/py3k-cdecimal/Objects/descrobject.c
   python/branches/py3k-cdecimal/Objects/floatobject.c
   python/branches/py3k-cdecimal/Objects/funcobject.c
   python/branches/py3k-cdecimal/Objects/genobject.c
   python/branches/py3k-cdecimal/Objects/listobject.c
   python/branches/py3k-cdecimal/Objects/longobject.c
   python/branches/py3k-cdecimal/Objects/memoryobject.c
   python/branches/py3k-cdecimal/Objects/moduleobject.c
   python/branches/py3k-cdecimal/Objects/object.c
   python/branches/py3k-cdecimal/Objects/obmalloc.c
   python/branches/py3k-cdecimal/Objects/rangeobject.c
   python/branches/py3k-cdecimal/Objects/setobject.c
   python/branches/py3k-cdecimal/Objects/sliceobject.c
   python/branches/py3k-cdecimal/Objects/stringlib/formatter.h
   python/branches/py3k-cdecimal/Objects/structseq.c
   python/branches/py3k-cdecimal/Objects/tupleobject.c
   python/branches/py3k-cdecimal/Objects/typeobject.c
   python/branches/py3k-cdecimal/Objects/unicodectype.c
   python/branches/py3k-cdecimal/Objects/unicodeobject.c
   python/branches/py3k-cdecimal/PC/VC6/readme.txt
   python/branches/py3k-cdecimal/PC/getpathp.c
   python/branches/py3k-cdecimal/PC/pyconfig.h
   python/branches/py3k-cdecimal/PC/python_nt.rc
   python/branches/py3k-cdecimal/PCbuild/build_tkinter.py
   python/branches/py3k-cdecimal/PCbuild/make_buildinfo.c
   python/branches/py3k-cdecimal/PCbuild/pcbuild.sln
   python/branches/py3k-cdecimal/PCbuild/pyproject.vsprops
   python/branches/py3k-cdecimal/PCbuild/pythoncore.vcproj
   python/branches/py3k-cdecimal/PCbuild/readme.txt
   python/branches/py3k-cdecimal/Parser/pgenmain.c
   python/branches/py3k-cdecimal/Parser/printgrammar.c
   python/branches/py3k-cdecimal/Parser/tokenizer.c
   python/branches/py3k-cdecimal/Python/_warnings.c
   python/branches/py3k-cdecimal/Python/ast.c
   python/branches/py3k-cdecimal/Python/bltinmodule.c
   python/branches/py3k-cdecimal/Python/ceval.c
   python/branches/py3k-cdecimal/Python/compile.c
   python/branches/py3k-cdecimal/Python/dynload_shlib.c
   python/branches/py3k-cdecimal/Python/dynload_win.c
   python/branches/py3k-cdecimal/Python/errors.c
   python/branches/py3k-cdecimal/Python/future.c
   python/branches/py3k-cdecimal/Python/getcopyright.c
   python/branches/py3k-cdecimal/Python/import.c
   python/branches/py3k-cdecimal/Python/peephole.c
   python/branches/py3k-cdecimal/Python/pyarena.c
   python/branches/py3k-cdecimal/Python/pythonrun.c
   python/branches/py3k-cdecimal/Python/sysmodule.c
   python/branches/py3k-cdecimal/Python/thread_nt.h
   python/branches/py3k-cdecimal/Python/thread_pthread.h
   python/branches/py3k-cdecimal/Python/traceback.c
   python/branches/py3k-cdecimal/README
   python/branches/py3k-cdecimal/Tools/README
   python/branches/py3k-cdecimal/Tools/buildbot/external-amd64.bat
   python/branches/py3k-cdecimal/Tools/buildbot/external-common.bat
   python/branches/py3k-cdecimal/Tools/buildbot/external.bat
   python/branches/py3k-cdecimal/Tools/buildbot/test.bat
   python/branches/py3k-cdecimal/Tools/msi/msi.py
   python/branches/py3k-cdecimal/Tools/scripts/README
   python/branches/py3k-cdecimal/Tools/scripts/untabify.py
   python/branches/py3k-cdecimal/Tools/unicode/gencodec.py
   python/branches/py3k-cdecimal/configure
   python/branches/py3k-cdecimal/configure.in
   python/branches/py3k-cdecimal/pyconfig.h.in
   python/branches/py3k-cdecimal/setup.py

Modified: python/branches/py3k-cdecimal/.gitignore
==============================================================================
--- python/branches/py3k-cdecimal/.gitignore	(original)
+++ python/branches/py3k-cdecimal/.gitignore	Sun Jan  2 13:18:37 2011
@@ -1,8 +1,17 @@
+*.cover
+*.o
+*.orig
+*.pyc
+*.pyd
+*.pyo
+*.rej
+*~
 Doc/build/
 Doc/tools/docutils/
 Doc/tools/jinja2/
 Doc/tools/pygments/
 Doc/tools/sphinx/
+Lib/lib2to3/*.pickle
 Makefile
 Makefile.pre
 Misc/python.pc
@@ -10,17 +19,26 @@
 Modules/Setup.config
 Modules/Setup.local
 Modules/config.c
+Modules/ld_so_aix
+PCbuild/*.bsc
+PCbuild/*.dll
+PCbuild/*.exe
+PCbuild/*.exp
+PCbuild/*.lib
+PCbuild/*.ncb
+PCbuild/*.o
+PCbuild/*.pdb
+PCbuild/Win32-temp-*
 Parser/pgen
 Parser/pgen.stamp
+__pycache__
+autom4te.cache
 build/
 config.log
 config.status
-libpython3.2.a
+libpython*.a
 pybuilddir.txt
 pyconfig.h
 python
 python-gdb.py
 tags
-Lib/lib2to3/Grammar3.2.0.alpha.2.pickle
-Lib/lib2to3/PatternGrammar3.2.0.alpha.2.pickle
-autom4te.cache

Modified: python/branches/py3k-cdecimal/Doc/ACKS.txt
==============================================================================
--- python/branches/py3k-cdecimal/Doc/ACKS.txt	(original)
+++ python/branches/py3k-cdecimal/Doc/ACKS.txt	Sun Jan  2 13:18:37 2011
@@ -111,6 +111,7 @@
    * Andrew M. Kuchling
    * Dave Kuhlman
    * Erno Kuusela
+   * Ross Lagerwall
    * Thomas Lamb
    * Detlef Lannert
    * Piers Lauder

Modified: python/branches/py3k-cdecimal/Doc/README.txt
==============================================================================
--- python/branches/py3k-cdecimal/Doc/README.txt	(original)
+++ python/branches/py3k-cdecimal/Doc/README.txt	Sun Jan  2 13:18:37 2011
@@ -132,7 +132,7 @@
 as long as you don't change or remove the copyright notice:
 
 ----------------------------------------------------------------------
-Copyright (c) 2000-2010 Python Software Foundation.
+Copyright (c) 2000-2011 Python Software Foundation.
 All rights reserved.
 
 Copyright (c) 2000 BeOpen.com.

Modified: python/branches/py3k-cdecimal/Doc/c-api/buffer.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/c-api/buffer.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/c-api/buffer.rst	Sun Jan  2 13:18:37 2011
@@ -12,16 +12,32 @@
 .. index::
    single: buffer interface
 
-Python objects implemented in C can export a "buffer interface."  These
-functions can be used by an object to expose its data in a raw, byte-oriented
-format. Clients of the object can use the buffer interface to access the
-object data directly, without needing to copy it first.
-
-Examples of objects that support the buffer interface are :class:`bytes`,
-:class:`bytearray` and :class:`array.array`. The bytes and bytearray objects
-exposes their bytes contents in the buffer interface's byte-oriented form.
-An :class:`array.array` can also expose its contents, but it should be noted
-that array elements may be multi-byte values.
+Certain objects available in Python wrap access to an underlying memory
+array or *buffer*.  Such objects include the built-in :class:`bytes` and
+:class:`bytearray`, and some extension types like :class:`array.array`.
+Third-party libraries may define their own types for special purposes, such
+as image processing or numeric analysis.
+
+While each of these types have their own semantics, they share the common
+characteristic of being backed by a possibly large memory buffer.  It is
+then desireable, in some situations, to access that buffer directly and
+without intermediate copying.
+
+Python provides such a facility at the C level in the form of the *buffer
+protocol*.  This protocol has two sides:
+
+.. index:: single: PyBufferProcs
+
+- on the producer side, a type can export a "buffer interface" which allows
+  objects of that type to expose information about their underlying buffer.
+  This interface is described in the section :ref:`buffer-structs`;
+
+- on the consumer side, several means are available to obtain a pointer to
+  the raw underlying data of an object (for example a method parameter).
+
+Simple objects such as :class:`bytes` and :class:`bytearray` expose their
+underlying buffer in byte-oriented form.  Other forms are possible; for example,
+the elements exposed by a :class:`array.array` can be multi-byte values.
 
 An example consumer of the buffer interface is the :meth:`~io.BufferedIOBase.write`
 method of file objects: any object that can export a series of bytes through
@@ -44,12 +60,6 @@
 resource leaks.
 
 
-.. index:: single: PyBufferProcs
-
-How the buffer interface is exposed by a type object is described in the
-section :ref:`buffer-structs`, under the description for :c:type:`PyBufferProcs`.
-
-
 The buffer structure
 ====================
 

Modified: python/branches/py3k-cdecimal/Doc/c-api/codec.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/c-api/codec.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/c-api/codec.rst	Sun Jan  2 13:18:37 2011
@@ -80,15 +80,13 @@
    The callback gets a single argument, an instance of
    :exc:`UnicodeEncodeError`, :exc:`UnicodeDecodeError` or
    :exc:`UnicodeTranslateError` that holds information about the problematic
-   sequence of characters or bytes and their offset in the original string.  The
+   sequence of characters or bytes and their offset in the original string (see
+   :ref:`unicodeexceptions` for functions to extract this information).  The
    callback must either raise the given exception, or return a two-item tuple
    containing the replacement for the problematic sequence, and an integer
    giving the offset in the original string at which encoding/decoding should be
    resumed.
 
-   .. XXX once they are documented, link to PyUnicode*Error access functions
-      to show how to get at the exception properties
-
    Return ``0`` on success, ``-1`` on error.
 
 .. c:function:: PyObject* PyCodec_LookupError(const char *name)

Modified: python/branches/py3k-cdecimal/Doc/c-api/exceptions.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/c-api/exceptions.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/c-api/exceptions.rst	Sun Jan  2 13:18:37 2011
@@ -145,79 +145,11 @@
 
 .. c:function:: PyObject* PyErr_Format(PyObject *exception, const char *format, ...)
 
-   This function sets the error indicator and returns *NULL*. *exception* should be
-   a Python exception (class, not an instance). *format* should be an ASCII-encoded string,
-   containing format codes, similar to :c:func:`printf`. The ``width.precision``
-   before a format code is parsed, but the width part is ignored.
-
-   .. % This should be exactly the same as the table in PyString_FromFormat.
-   .. % One should just refer to the other.
-   .. % The descriptions for %zd and %zu are wrong, but the truth is complicated
-   .. % because not all compilers support the %z width modifier -- we fake it
-   .. % when necessary via interpolating PY_FORMAT_SIZE_T.
-   .. % Similar comments apply to the %ll width modifier and
-   .. % PY_FORMAT_LONG_LONG.
-
-   +-------------------+---------------+--------------------------------+
-   | Format Characters | Type          | Comment                        |
-   +===================+===============+================================+
-   | :attr:`%%`        | *n/a*         | The literal % character.       |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%c`        | int           | A single character,            |
-   |                   |               | represented as an C int.       |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%d`        | int           | Exactly equivalent to          |
-   |                   |               | ``printf("%d")``.              |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%u`        | unsigned int  | Exactly equivalent to          |
-   |                   |               | ``printf("%u")``.              |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%ld`       | long          | Exactly equivalent to          |
-   |                   |               | ``printf("%ld")``.             |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%lu`       | unsigned long | Exactly equivalent to          |
-   |                   |               | ``printf("%lu")``.             |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%lld`      | long long     | Exactly equivalent to          |
-   |                   |               | ``printf("%lld")``.            |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%llu`      | unsigned      | Exactly equivalent to          |
-   |                   | long long     | ``printf("%llu")``.            |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%zd`       | Py_ssize_t    | Exactly equivalent to          |
-   |                   |               | ``printf("%zd")``.             |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%zu`       | size_t        | Exactly equivalent to          |
-   |                   |               | ``printf("%zu")``.             |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%i`        | int           | Exactly equivalent to          |
-   |                   |               | ``printf("%i")``.              |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%x`        | int           | Exactly equivalent to          |
-   |                   |               | ``printf("%x")``.              |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%s`        | char\*        | A null-terminated C character  |
-   |                   |               | array.                         |
-   +-------------------+---------------+--------------------------------+
-   | :attr:`%p`        | void\*        | The hex representation of a C  |
-   |                   |               | pointer. Mostly equivalent to  |
-   |                   |               | ``printf("%p")`` except that   |
-   |                   |               | it is guaranteed to start with |
-   |                   |               | the literal ``0x`` regardless  |
-   |                   |               | of what the platform's         |
-   |                   |               | ``printf`` yields.             |
-   +-------------------+---------------+--------------------------------+
-
-   An unrecognized format character causes all the rest of the format string to be
-   copied as-is to the result string, and any extra arguments discarded.
-
-   .. note::
-
-      The `"%lld"` and `"%llu"` format specifiers are only available
-      when :const:`HAVE_LONG_LONG` is defined.
-
-   .. versionchanged:: 3.2
-      Support for `"%lld"` and `"%llu"` added.
+   This function sets the error indicator and returns *NULL*.  *exception*
+   should be a Python exception class.  The *format* and subsequent
+   parameters help format the error message; they have the same meaning and
+   values as in :c:func:`PyUnicode_FromFormat`. *format* is an ASCII-encoded
+   string.
 
 
 .. c:function:: void PyErr_SetNone(PyObject *type)
@@ -287,7 +219,9 @@
 
    Similar to :c:func:`PyErr_SetFromWindowsErr`, with the additional behavior that
    if *filename* is not *NULL*, it is passed to the constructor of
-   :exc:`WindowsError` as a third parameter. Availability: Windows.
+   :exc:`WindowsError` as a third parameter.  *filename* is decoded from the
+   filesystem encoding (:func:`sys.getfilesystemencoding`).  Availability:
+   Windows.
 
 
 .. c:function:: PyObject* PyErr_SetExcFromWindowsErrWithFilename(PyObject *type, int ierr, char *filename)
@@ -301,7 +235,8 @@
    Set file, line, and offset information for the current exception.  If the
    current exception is not a :exc:`SyntaxError`, then it sets additional
    attributes, which make the exception printing subsystem think the exception
-   is a :exc:`SyntaxError`.
+   is a :exc:`SyntaxError`. *filename* is decoded from the filesystem encoding
+   (:func:`sys.getfilesystemencoding`).
 
 .. versionadded:: 3.2
 
@@ -323,7 +258,7 @@
 .. c:function:: int PyErr_WarnEx(PyObject *category, char *message, int stack_level)
 
    Issue a warning message.  The *category* argument is a warning category (see
-   below) or *NULL*; the *message* argument is a message string.  *stack_level* is a
+   below) or *NULL*; the *message* argument is an UTF-8 encoded string.  *stack_level* is a
    positive number giving a number of stack frames; the warning will be issued from
    the  currently executing line of code in that stack frame.  A *stack_level* of 1
    is the function calling :c:func:`PyErr_WarnEx`, 2 is  the function above that,
@@ -363,13 +298,16 @@
    is a straightforward wrapper around the Python function
    :func:`warnings.warn_explicit`, see there for more information.  The *module*
    and *registry* arguments may be set to *NULL* to get the default effect
-   described there.
+   described there. *message* and *module* are UTF-8 encoded strings,
+   *filename* is decoded from the filesystem encoding
+   (:func:`sys.getfilesystemencoding`).
 
 
 .. c:function:: int PyErr_WarnFormat(PyObject *category, Py_ssize_t stack_level, const char *format, ...)
 
    Function similar to :c:func:`PyErr_WarnEx`, but use
-   :c:func:`PyUnicode_FromFormatV` to format the warning message.
+   :c:func:`PyUnicode_FromFormat` to format the warning message.  *format* is
+   an ASCII-encoded string.
 
    .. versionadded:: 3.2
 
@@ -496,6 +434,85 @@
    This steals a reference to *ctx*.
 
 
+.. _unicodeexceptions:
+
+Unicode Exception Objects
+=========================
+
+The following functions are used to create and modify Unicode exceptions from C.
+
+.. c:function:: PyObject* PyUnicodeDecodeError_Create(const char *encoding, const char *object, Py_ssize_t length, Py_ssize_t start, Py_ssize_t end, const char *reason)
+
+   Create a :class:`UnicodeDecodeError` object with the attributes *encoding*,
+   *object*, *length*, *start*, *end* and *reason*. *encoding* and *reason* are
+   UTF-8 encoded strings.
+
+.. c:function:: PyObject* PyUnicodeEncodeError_Create(const char *encoding, const Py_UNICODE *object, Py_ssize_t length, Py_ssize_t start, Py_ssize_t end, const char *reason)
+
+   Create a :class:`UnicodeEncodeError` object with the attributes *encoding*,
+   *object*, *length*, *start*, *end* and *reason*. *encoding* and *reason* are
+   UTF-8 encoded strings.
+
+.. c:function:: PyObject* PyUnicodeTranslateError_Create(const Py_UNICODE *object, Py_ssize_t length, Py_ssize_t start, Py_ssize_t end, const char *reason)
+
+   Create a :class:`UnicodeTranslateError` object with the attributes *object*,
+   *length*, *start*, *end* and *reason*. *reason* is an UTF-8 encoded string.
+
+.. c:function:: PyObject* PyUnicodeDecodeError_GetEncoding(PyObject *exc)
+                PyObject* PyUnicodeEncodeError_GetEncoding(PyObject *exc)
+
+   Return the *encoding* attribute of the given exception object.
+
+.. c:function:: PyObject* PyUnicodeDecodeError_GetObject(PyObject *exc)
+                PyObject* PyUnicodeEncodeError_GetObject(PyObject *exc)
+                PyObject* PyUnicodeTranslateError_GetObject(PyObject *exc)
+
+   Return the *object* attribute of the given exception object.
+
+.. c:function:: int PyUnicodeDecodeError_GetStart(PyObject *exc, Py_ssize_t *start)
+                int PyUnicodeEncodeError_GetStart(PyObject *exc, Py_ssize_t *start)
+                int PyUnicodeTranslateError_GetStart(PyObject *exc, Py_ssize_t *start)
+
+   Get the *start* attribute of the given exception object and place it into
+   *\*start*.  *start* must not be *NULL*.  Return ``0`` on success, ``-1`` on
+   failure.
+
+.. c:function:: int PyUnicodeDecodeError_SetStart(PyObject *exc, Py_ssize_t start)
+                int PyUnicodeEncodeError_SetStart(PyObject *exc, Py_ssize_t start)
+                int PyUnicodeTranslateError_SetStart(PyObject *exc, Py_ssize_t start)
+
+   Set the *start* attribute of the given exception object to *start*.  Return
+   ``0`` on success, ``-1`` on failure.
+
+.. c:function:: int PyUnicodeDecodeError_GetEnd(PyObject *exc, Py_ssize_t *end)
+                int PyUnicodeEncodeError_GetEnd(PyObject *exc, Py_ssize_t *end)
+                int PyUnicodeTranslateError_GetEnd(PyObject *exc, Py_ssize_t *end)
+
+   Get the *end* attribute of the given exception object and place it into
+   *\*end*.  *end* must not be *NULL*.  Return ``0`` on success, ``-1`` on
+   failure.
+
+.. c:function:: int PyUnicodeDecodeError_SetEnd(PyObject *exc, Py_ssize_t end)
+                int PyUnicodeEncodeError_SetEnd(PyObject *exc, Py_ssize_t end)
+                int PyUnicodeTranslateError_SetEnd(PyObject *exc, Py_ssize_t end)
+
+   Set the *end* attribute of the given exception object to *end*.  Return ``0``
+   on success, ``-1`` on failure.
+
+.. c:function:: PyObject* PyUnicodeDecodeError_GetReason(PyObject *exc)
+                PyObject* PyUnicodeEncodeError_GetReason(PyObject *exc)
+                PyObject* PyUnicodeTranslateError_GetReason(PyObject *exc)
+
+   Return the *reason* attribute of the given exception object.
+
+.. c:function:: int PyUnicodeDecodeError_SetReason(PyObject *exc, const char *reason)
+                int PyUnicodeEncodeError_SetReason(PyObject *exc, const char *reason)
+                int PyUnicodeTranslateError_SetReason(PyObject *exc, const char *reason)
+
+   Set the *reason* attribute of the given exception object to *reason*.  Return
+   ``0`` on success, ``-1`` on failure.
+
+
 Recursion Control
 =================
 
@@ -525,6 +542,35 @@
    Ends a :c:func:`Py_EnterRecursiveCall`.  Must be called once for each
    *successful* invocation of :c:func:`Py_EnterRecursiveCall`.
 
+Properly implementing :attr:`tp_repr` for container types requires
+special recursion handling.  In addition to protecting the stack,
+:attr:`tp_repr` also needs to track objects to prevent cycles.  The
+following two functions facilitate this functionality.  Effectively,
+these are the C equivalent to :func:`reprlib.recursive_repr`.
+
+.. c:function:: int Py_ReprEnter(PyObject *object)
+
+   Called at the beginning of the :attr:`tp_repr` implementation to
+   detect cycles.
+
+   If the object has already been processed, the function returns a
+   positive integer.  In that case the :attr:`tp_repr` implementation
+   should return a string object indicating a cycle.  As examples,
+   :class:`dict` objects return ``{...}`` and :class:`list` objects
+   return ``[...]``.
+
+   The function will return a negative integer if the recursion limit
+   is reached.  In that case the :attr:`tp_repr` implementation should
+   typically return ``NULL``.
+
+   Otherwise, the function returns zero and the :attr:`tp_repr`
+   implementation can continue normally.
+
+.. c:function:: void Py_ReprLeave(PyObject *object)
+
+   Ends a :c:func:`Py_ReprEnter`.  Must be called once for each
+   invocation of :c:func:`Py_ReprEnter` that returns zero.
+
 
 .. _standardexceptions:
 

Modified: python/branches/py3k-cdecimal/Doc/c-api/import.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/c-api/import.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/c-api/import.rst	Sun Jan  2 13:18:37 2011
@@ -142,6 +142,7 @@
    attribute of the module object is set to *cpathname* if it is
    non-``NULL``.  Of the three functions, this is the preferred one to use.
 
+   .. versionadded:: 3.2
 
 .. c:function:: long PyImport_GetMagicNumber()
 
@@ -155,6 +156,8 @@
    Return the magic tag string for :pep:`3147` format Python bytecode file
    names.
 
+   .. versionadded:: 3.2
+
 .. c:function:: PyObject* PyImport_GetModuleDict()
 
    Return the dictionary used for the module administration (a.k.a.

Modified: python/branches/py3k-cdecimal/Doc/c-api/init.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/c-api/init.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/c-api/init.rst	Sun Jan  2 13:18:37 2011
@@ -412,8 +412,9 @@
 .. c:function:: void Py_SetPythonHome(wchar_t *home)
 
    Set the default "home" directory, that is, the location of the standard
-   Python libraries.  The libraries are searched in
-   :file:`{home}/lib/python{version}` and :file:`{home}/lib/python{version}`.
+   Python libraries.  See :envvar:`PYTHONHOME` for the meaning of the
+   argument string.
+
    The argument should point to a zero-terminated character string in static
    storage whose contents will not change for the duration of the program's
    execution.  No code in the Python interpreter will change the contents of

Modified: python/branches/py3k-cdecimal/Doc/c-api/intro.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/c-api/intro.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/c-api/intro.rst	Sun Jan  2 13:18:37 2011
@@ -41,8 +41,8 @@
    #include "Python.h"
 
 This implies inclusion of the following standard headers: ````,
-````, ````, ````, and ```` (if
-available).
+````, ````, ````, ```` and ````
+(if available).
 
 .. note::
 

Modified: python/branches/py3k-cdecimal/Doc/c-api/list.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/c-api/list.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/c-api/list.rst	Sun Jan  2 13:18:37 2011
@@ -37,7 +37,7 @@
 
    .. note::
 
-      If *length* is greater than zero, the returned list object's items are
+      If *len* is greater than zero, the returned list object's items are
       set to ``NULL``.  Thus you cannot use abstract API functions such as
       :c:func:`PySequence_SetItem`  or expose the object to Python code before
       setting all items to a real object with :c:func:`PyList_SetItem`.
@@ -58,9 +58,9 @@
 
 .. c:function:: PyObject* PyList_GetItem(PyObject *list, Py_ssize_t index)
 
-   Return the object at position *pos* in the list pointed to by *p*.  The
+   Return the object at position *index* in the list pointed to by *list*.  The
    position must be positive, indexing from the end of the list is not
-   supported.  If *pos* is out of bounds, return *NULL* and set an
+   supported.  If *index* is out of bounds, return *NULL* and set an
    :exc:`IndexError` exception.
 
 

Modified: python/branches/py3k-cdecimal/Doc/c-api/slice.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/c-api/slice.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/c-api/slice.rst	Sun Jan  2 13:18:37 2011
@@ -26,7 +26,7 @@
    the new object could not be allocated.
 
 
-.. c:function:: int PySlice_GetIndices(PySliceObject *slice, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
+.. c:function:: int PySlice_GetIndices(PyObject *slice, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
 
    Retrieve the start, stop and step indices from the slice object *slice*,
    assuming a sequence of length *length*. Treats indices greater than
@@ -38,8 +38,12 @@
 
    You probably do not want to use this function.
 
+   .. versionchanged:: 3.2
+      The parameter type for the *slice* parameter was ``PySliceObject*``
+      before.
 
-.. c:function:: int PySlice_GetIndicesEx(PySliceObject *slice, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength)
+
+.. c:function:: int PySlice_GetIndicesEx(PyObject *slice, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength)
 
    Usable replacement for :c:func:`PySlice_GetIndices`.  Retrieve the start,
    stop, and step indices from the slice object *slice* assuming a sequence of
@@ -49,3 +53,6 @@
 
    Returns 0 on success and -1 on error with exception set.
 
+   .. versionchanged:: 3.2
+      The parameter type for the *slice* parameter was ``PySliceObject*``
+      before.

Modified: python/branches/py3k-cdecimal/Doc/c-api/typeobj.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/c-api/typeobj.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/c-api/typeobj.rst	Sun Jan  2 13:18:37 2011
@@ -705,7 +705,9 @@
    This field is not inherited by subtypes (computed attributes are inherited
    through a different mechanism).
 
-   Docs for PyGetSetDef (XXX belong elsewhere)::
+   .. XXX belongs elsewhere
+
+   Docs for PyGetSetDef::
 
       typedef PyObject *(*getter)(PyObject *, void *);
       typedef int (*setter)(PyObject *, PyObject *, void *);
@@ -752,7 +754,7 @@
 
       PyObject * tp_descr_get(PyObject *self, PyObject *obj, PyObject *type);
 
-   XXX explain.
+   .. XXX explain.
 
    This field is inherited by subtypes.
 
@@ -767,7 +769,7 @@
 
    This field is inherited by subtypes.
 
-   XXX explain.
+   .. XXX explain.
 
 
 .. c:member:: long PyTypeObject.tp_dictoffset
@@ -1193,7 +1195,7 @@
 .. sectionauthor:: Benjamin Peterson
 
 
-The buffer interface exports a model where an object can expose its internal
+The :ref:`buffer interface ` exports a model where an object can expose its internal
 data.
 
 If an object does not export the buffer interface, then its :attr:`tp_as_buffer`

Modified: python/branches/py3k-cdecimal/Doc/c-api/unicode.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/c-api/unicode.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/c-api/unicode.rst	Sun Jan  2 13:18:37 2011
@@ -328,6 +328,13 @@
    Identical to :c:func:`PyUnicode_FromFormat` except that it takes exactly two
    arguments.
 
+.. c:function:: PyObject* PyUnicode_TransformDecimalToASCII(Py_UNICODE *s, Py_ssize_t size)
+
+   Create a Unicode object by replacing all decimal digits in
+   :c:type:`Py_UNICODE` buffer of the given size by ASCII digits 0--9
+   according to their decimal value.  Return *NULL* if an exception
+   occurs.
+
 
 .. c:function:: Py_UNICODE* PyUnicode_AsUnicode(PyObject *unicode)
 
@@ -1056,7 +1063,9 @@
 .. c:function:: int PyUnicode_CompareWithASCIIString(PyObject *uni, char *string)
 
    Compare a unicode object, *uni*, with *string* and return -1, 0, 1 for less
-   than, equal, and greater than, respectively.
+   than, equal, and greater than, respectively. It is best to pass only
+   ASCII-encoded strings, but the function interprets the input string as
+   ISO-8859-1 if it contains non-ASCII characters".
 
 
 .. c:function:: int PyUnicode_RichCompare(PyObject *left,  PyObject *right,  int op)

Modified: python/branches/py3k-cdecimal/Doc/c-api/veryhigh.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/c-api/veryhigh.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/c-api/veryhigh.rst	Sun Jan  2 13:18:37 2011
@@ -66,8 +66,9 @@
    If *fp* refers to a file associated with an interactive device (console or
    terminal input or Unix pseudo-terminal), return the value of
    :c:func:`PyRun_InteractiveLoop`, otherwise return the result of
-   :c:func:`PyRun_SimpleFile`.  If *filename* is *NULL*, this function uses
-   ``"???"`` as the filename.
+   :c:func:`PyRun_SimpleFile`.  *filename* is decoded from the filesystem
+   encoding (:func:`sys.getfilesystemencoding`).  If *filename* is *NULL*, this
+   function uses ``"???"`` as the filename.
 
 
 .. c:function:: int PyRun_SimpleString(const char *command)
@@ -110,9 +111,10 @@
 .. c:function:: int PyRun_SimpleFileExFlags(FILE *fp, const char *filename, int closeit, PyCompilerFlags *flags)
 
    Similar to :c:func:`PyRun_SimpleStringFlags`, but the Python source code is read
-   from *fp* instead of an in-memory string. *filename* should be the name of the
-   file.  If *closeit* is true, the file is closed before PyRun_SimpleFileExFlags
-   returns.
+   from *fp* instead of an in-memory string. *filename* should be the name of
+   the file, it is decoded from the filesystem encoding
+   (:func:`sys.getfilesystemencoding`).  If *closeit* is true, the file is
+   closed before PyRun_SimpleFileExFlags returns.
 
 
 .. c:function:: int PyRun_InteractiveOne(FILE *fp, const char *filename)
@@ -125,7 +127,10 @@
 
    Read and execute a single statement from a file associated with an
    interactive device according to the *flags* argument.  The user will be
-   prompted using ``sys.ps1`` and ``sys.ps2``.  Returns ``0`` when the input was
+   prompted using ``sys.ps1`` and ``sys.ps2``.  *filename* is decoded from the
+   filesystem encoding (:func:`sys.getfilesystemencoding`).
+
+   Returns ``0`` when the input was
    executed successfully, ``-1`` if there was an exception, or an error code
    from the :file:`errcode.h` include file distributed as part of Python if
    there was a parse error.  (Note that :file:`errcode.h` is not included by
@@ -142,7 +147,8 @@
 
    Read and execute statements from a file associated with an interactive device
    until EOF is reached.  The user will be prompted using ``sys.ps1`` and
-   ``sys.ps2``.  Returns ``0`` at EOF.
+   ``sys.ps2``.  *filename* is decoded from the filesystem encoding
+   (:func:`sys.getfilesystemencoding`).  Returns ``0`` at EOF.
 
 
 .. c:function:: struct _node* PyParser_SimpleParseString(const char *str, int start)
@@ -164,7 +170,8 @@
    Parse Python source code from *str* using the start token *start* according to
    the *flags* argument.  The result can be used to create a code object which can
    be evaluated efficiently. This is useful if a code fragment must be evaluated
-   many times.
+   many times. *filename* is decoded from the filesystem encoding
+   (:func:`sys.getfilesystemencoding`).
 
 
 .. c:function:: struct _node* PyParser_SimpleParseFile(FILE *fp, const char *filename, int start)
@@ -217,7 +224,8 @@
 .. c:function:: PyObject* PyRun_FileExFlags(FILE *fp, const char *filename, int start, PyObject *globals, PyObject *locals, int closeit, PyCompilerFlags *flags)
 
    Similar to :c:func:`PyRun_StringFlags`, but the Python source code is read from
-   *fp* instead of an in-memory string. *filename* should be the name of the file.
+   *fp* instead of an in-memory string. *filename* should be the name of the file,
+   it is decoded from the filesystem encoding (:func:`sys.getfilesystemencoding`).
    If *closeit* is true, the file is closed before :c:func:`PyRun_FileExFlags`
    returns.
 
@@ -230,23 +238,38 @@
 
 .. c:function:: PyObject* Py_CompileStringFlags(const char *str, const char *filename, int start, PyCompilerFlags *flags)
 
+   This is a simplified interface to :c:func:`Py_CompileStringExFlags` below, with
+   *optimize* set to ``-1``.
+
+
+.. c:function:: PyObject* Py_CompileStringExFlags(const char *str, const char *filename, int start, PyCompilerFlags *flags, int optimize)
+
    Parse and compile the Python source code in *str*, returning the resulting code
    object.  The start token is given by *start*; this can be used to constrain the
    code which can be compiled and should be :const:`Py_eval_input`,
    :const:`Py_file_input`, or :const:`Py_single_input`.  The filename specified by
    *filename* is used to construct the code object and may appear in tracebacks or
-   :exc:`SyntaxError` exception messages.  This returns *NULL* if the code cannot
-   be parsed or compiled.
+   :exc:`SyntaxError` exception messages, it is decoded from the filesystem
+   encoding (:func:`sys.getfilesystemencoding`).  This returns *NULL* if the
+   code cannot be parsed or compiled.
+
+   The integer *optimize* specifies the optimization level of the compiler; a
+   value of ``-1`` selects the optimization level of the interpreter as given by
+   :option:`-O` options.  Explicit levels are ``0`` (no optimization;
+   ``__debug__`` is true), ``1`` (asserts are removed, ``__debug__`` is false)
+   or ``2`` (docstrings are removed too).
+
+   .. versionadded:: 3.2
 
 
-.. c:function:: PyObject* PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
+.. c:function:: PyObject* PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals)
 
    This is a simplified interface to :c:func:`PyEval_EvalCodeEx`, with just
    the code object, and the dictionaries of global and local variables.
    The other arguments are set to *NULL*.
 
 
-.. c:function:: PyObject* PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, PyObject **args, int argcount, PyObject **kws, int kwcount, PyObject **defs, int defcount, PyObject *closure)
+.. c:function:: PyObject* PyEval_EvalCodeEx(PyObject *co, PyObject *globals, PyObject *locals, PyObject **args, int argcount, PyObject **kws, int kwcount, PyObject **defs, int defcount, PyObject *closure)
 
    Evaluate a precompiled code object, given a particular environment for its
    evaluation.  This environment consists of dictionaries of global and local

Modified: python/branches/py3k-cdecimal/Doc/copyright.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/copyright.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/copyright.rst	Sun Jan  2 13:18:37 2011
@@ -4,7 +4,7 @@
 
 Python and this documentation is:
 
-Copyright ?? 2001-2010 Python Software Foundation. All rights reserved.
+Copyright ?? 2001-2011 Python Software Foundation. All rights reserved.
 
 Copyright ?? 2000 BeOpen.com. All rights reserved.
 

Modified: python/branches/py3k-cdecimal/Doc/distutils/apiref.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/distutils/apiref.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/distutils/apiref.rst	Sun Jan  2 13:18:37 2011
@@ -888,7 +888,7 @@
 .. function:: make_zipfile(base_name, base_dir[, verbose=0, dry_run=0])
 
    Create a zip file from all files in and under *base_dir*.  The output zip file
-   will be named *base_dir* + :file:`.zip`.  Uses either the  :mod:`zipfile` Python
+   will be named *base_name* + :file:`.zip`.  Uses either the  :mod:`zipfile` Python
    module (if available) or the InfoZIP :file:`zip`  utility (if installed and
    found on the default search path).  If neither  tool is available, raises
    :exc:`DistutilsExecError`.   Returns the name of the output zip file.

Modified: python/branches/py3k-cdecimal/Doc/documenting/markup.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/documenting/markup.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/documenting/markup.rst	Sun Jan  2 13:18:37 2011
@@ -610,6 +610,8 @@
 
 The ``:ref:`` invocation is replaced with the section title.
 
+Alternatively, you can reference any label (not just section titles)
+if you provide the link text ``:ref:`link text````.
 
 Paragraph-level markup
 ----------------------

Modified: python/branches/py3k-cdecimal/Doc/extending/embedding.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/extending/embedding.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/extending/embedding.rst	Sun Jan  2 13:18:37 2011
@@ -35,9 +35,6 @@
 to :c:func:`PyRun_SimpleFile`.  You can also call the lower-level operations
 described in the previous chapters to construct and use Python objects.
 
-A simple demo of embedding Python can be found in the directory
-:file:`Demo/embed/` of the source distribution.
-
 
 .. seealso::
 
@@ -209,7 +206,7 @@
    {
        if(!PyArg_ParseTuple(args, ":numargs"))
            return NULL;
-       return Py_BuildValue("i", numargs);
+       return PyLong_FromLong(numargs);
    }
 
    static PyMethodDef EmbMethods[] = {

Modified: python/branches/py3k-cdecimal/Doc/extending/extending.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/extending/extending.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/extending/extending.rst	Sun Jan  2 13:18:37 2011
@@ -81,7 +81,7 @@
        if (!PyArg_ParseTuple(args, "s", &command))
            return NULL;
        sts = system(command);
-       return Py_BuildValue("i", sts);
+       return PyLong_FromLong(sts);
    }
 
 There is a straightforward translation from the argument list in Python (for
@@ -274,12 +274,9 @@
    sts = system(command);
 
 Our :func:`spam.system` function must return the value of :c:data:`sts` as a
-Python object.  This is done using the function :c:func:`Py_BuildValue`, which is
-something like the inverse of :c:func:`PyArg_ParseTuple`: it takes a format
-string and an arbitrary number of C values, and returns a new Python object.
-More info on :c:func:`Py_BuildValue` is given later. ::
+Python object.  This is done using the function :c:func:`PyLong_FromLong`. ::
 
-   return Py_BuildValue("i", sts);
+   return PyLong_FromLong(sts);
 
 In this case, it will return an integer object.  (Yes, even integers are objects
 on the heap in Python!)
@@ -1195,7 +1192,7 @@
        if (!PyArg_ParseTuple(args, "s", &command))
            return NULL;
        sts = PySpam_System(command);
-       return Py_BuildValue("i", sts);
+       return PyLong_FromLong(sts);
    }
 
 In the beginning of the module, right after the line ::

Modified: python/branches/py3k-cdecimal/Doc/extending/windows.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/extending/windows.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/extending/windows.rst	Sun Jan  2 13:18:37 2011
@@ -110,7 +110,7 @@
    Now your options are:
 
 #. Copy :file:`example.sln` and :file:`example.vcproj`, rename them to
-      :file:`spam.\*`, and edit them by hand, or
+   :file:`spam.\*`, and edit them by hand, or
 
 #. Create a brand new project; instructions are below.
 
@@ -179,8 +179,8 @@
 
 and add the following to the module initialization function::
 
-   MyObject_Type.ob_type = &PyType_Type;
-
+   if (PyType_Ready(&MyObject_Type) < 0)
+        return NULL;
 
 
 .. _dynamic-linking:

Modified: python/branches/py3k-cdecimal/Doc/faq/extending.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/faq/extending.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/faq/extending.rst	Sun Jan  2 13:18:37 2011
@@ -379,7 +379,7 @@
            if (ps1  == prompt ||                  /* ">>> " or */
                '\n' == code[i + j - 1])           /* "... " and double '\n' */
            {                                               /* so execute it */
-             dum = PyEval_EvalCode ((PyCodeObject *)src, glb, loc);
+             dum = PyEval_EvalCode (src, glb, loc);
              Py_XDECREF (dum);
              Py_XDECREF (src);
              free (code);

Modified: python/branches/py3k-cdecimal/Doc/glossary.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/glossary.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/glossary.rst	Sun Jan  2 13:18:37 2011
@@ -27,7 +27,7 @@
       :ref:`2to3-reference`.
 
    abstract base class
-      Abstract Base Classes (abbreviated ABCs) complement :term:`duck-typing` by
+      :ref:`abstract-base-classes` complement :term:`duck-typing` by
       providing a way to define interfaces when other techniques like
       :func:`hasattr` would be clumsy. Python comes with many built-in ABCs for
       data structures (in the :mod:`collections` module), numbers (in the
@@ -181,22 +181,22 @@
       not expressions.
 
    extension module
-      A module written in C or C++, using Python's C API to interact with the core and
-      with user code.
+      A module written in C or C++, using Python's C API to interact with the
+      core and with user code.
 
    file object
       An object exposing a file-oriented API (with methods such as
-      :meth:`read()` or :meth:`write()`) to an underlying resource.
-      Depending on the way it was created, a file object can mediate access
-      to a real on-disk file or to another other type of storage or
-      communication device (for example standard input/output, in-memory
-      buffers, sockets, pipes, etc.).  File objects are also called
-      :dfn:`file-like objects` or :dfn:`streams`.
-
-      There are actually three categories of file objects: raw binary
-      files, buffered binary files and text files.  Their interfaces are
-      defined in the :mod:`io` module.  The canonical way to create a
-      file object is by using the :func:`open` function.
+      :meth:`read()` or :meth:`write()`) to an underlying resource.  Depending
+      on the way it was created, a file object can mediate access to a real
+      on-disk file or to another other type of storage or communication device
+      (for example standard input/output, in-memory buffers, sockets, pipes,
+      etc.).  File objects are also called :dfn:`file-like objects` or
+      :dfn:`streams`.
+
+      There are actually three categories of file objects: raw binary files,
+      buffered binary files and text files.  Their interfaces are defined in the
+      :mod:`io` module.  The canonical way to create a file object is by using
+      the :func:`open` function.
 
    file-like object
       A synonym for :term:`file object`.
@@ -392,6 +392,12 @@
       the :term:`EAFP` approach and is characterized by the presence of many
       :keyword:`if` statements.
 
+      In a multi-threaded environment, the LBYL approach can risk introducing a
+      race condition between "the looking" and "the leaping".  For example, the
+      code, ``if key in mapping: return mapping[key]`` can fail if another
+      thread removes *key* from *mapping* after the test, but before the lookup.
+      This issue can be solved with locks or by using the EAFP approach.
+
    list
       A built-in Python :term:`sequence`.  Despite its name it is more akin
       to an array in other languages than to a linked list since access to

Modified: python/branches/py3k-cdecimal/Doc/howto/index.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/howto/index.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/howto/index.rst	Sun Jan  2 13:18:37 2011
@@ -19,6 +19,8 @@
    descriptor.rst
    doanddont.rst
    functional.rst
+   logging.rst
+   logging-cookbook.rst
    regex.rst
    sockets.rst
    sorting.rst

Modified: python/branches/py3k-cdecimal/Doc/includes/tzinfo-examples.py
==============================================================================
--- python/branches/py3k-cdecimal/Doc/includes/tzinfo-examples.py	(original)
+++ python/branches/py3k-cdecimal/Doc/includes/tzinfo-examples.py	Sun Jan  2 13:18:37 2011
@@ -71,7 +71,7 @@
     def _isdst(self, dt):
         tt = (dt.year, dt.month, dt.day,
               dt.hour, dt.minute, dt.second,
-              dt.weekday(), 0, -1)
+              dt.weekday(), 0, 0)
         stamp = _time.mktime(tt)
         tt = _time.localtime(stamp)
         return tt.tm_isdst > 0

Modified: python/branches/py3k-cdecimal/Doc/install/index.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/install/index.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/install/index.rst	Sun Jan  2 13:18:37 2011
@@ -929,15 +929,34 @@
 GNU C / Cygwin / MinGW
 ^^^^^^^^^^^^^^^^^^^^^^
 
-These instructions only apply if you're using a version of Python prior  to
-2.4.1 with a MinGW prior to 3.0.0 (with binutils-2.13.90-20030111-1).
-
 This section describes the necessary steps to use Distutils with the GNU C/C++
 compilers in their Cygwin and MinGW distributions. [#]_ For a Python interpreter
 that was built with Cygwin, everything should work without any of these
 following steps.
 
-These compilers require some special libraries. This task is more complex than
+Not all extensions can be built with MinGW or Cygwin, but many can.  Extensions
+most likely to not work are those that use C++ or depend on Microsoft Visual C
+extensions.
+
+To let Distutils compile your extension with Cygwin you have to type::
+
+   python setup.py build --compiler=cygwin
+
+and for Cygwin in no-cygwin mode [#]_ or for MinGW type::
+
+   python setup.py build --compiler=mingw32
+
+If you want to use any of these options/compilers as default, you should
+consider writing it in your personal or system-wide configuration file for
+Distutils (see section :ref:`inst-config-files`.)
+
+Older Versions of Python and MinGW
+""""""""""""""""""""""""""""""""""
+The following instructions only apply if you're using a version of Python
+inferior to 2.4.1 with a MinGW inferior to 3.0.0 (with
+binutils-2.13.90-20030111-1).
+
+These compilers require some special libraries.  This task is more complex than
 for Borland's C++, because there is no program to convert the library.  First
 you have to create a list of symbols which the Python DLL exports. (You can find
 a good program for this task at
@@ -967,18 +986,6 @@
 them too. The converted files have to reside in the same directories as the
 normal libraries do.
 
-To let Distutils compile your extension with Cygwin you now have to type ::
-
-   python setup.py build --compiler=cygwin
-
-and for Cygwin in no-cygwin mode [#]_ or for MinGW type::
-
-   python setup.py build --compiler=mingw32
-
-If you want to use any of these options/compilers as default, you should
-consider to write it in your personal or system-wide configuration file for
-Distutils (see section :ref:`inst-config-files`.)
-
 
 .. seealso::
 

Modified: python/branches/py3k-cdecimal/Doc/library/_thread.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/_thread.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/_thread.rst	Sun Jan  2 13:18:37 2011
@@ -137,6 +137,10 @@
    .. versionchanged:: 3.2
       The *timeout* parameter is new.
 
+   .. versionchanged:: 3.2
+      Lock acquires can now be interrupted by signals on POSIX.
+
+
 .. method:: lock.release()
 
    Releases the lock.  The lock must have been acquired earlier, but not

Modified: python/branches/py3k-cdecimal/Doc/library/allos.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/allos.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/allos.rst	Sun Jan  2 13:18:37 2011
@@ -19,6 +19,8 @@
    optparse.rst
    getopt.rst
    logging.rst
+   logging.config.rst
+   logging.handlers.rst
    getpass.rst
    curses.rst
    curses.ascii.rst

Modified: python/branches/py3k-cdecimal/Doc/library/argparse.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/argparse.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/argparse.rst	Sun Jan  2 13:18:37 2011
@@ -1428,6 +1428,16 @@
 
        {foo,bar}   additional help
 
+   Furthermore, ``add_parser`` supports an additional ``aliases`` argument,
+   which allows multiple strings to refer to the same subparser. This example,
+   like ``svn``, aliases ``co`` as a shorthand for ``checkout``::
+
+     >>> parser = argparse.ArgumentParser()
+     >>> subparsers = parser.add_subparsers()
+     >>> checkout = subparsers.add_parser('checkout', aliases=['co'])
+     >>> checkout.add_argument('foo')
+     >>> parser.parse_args(['co', 'bar'])
+     Namespace(foo='bar')
 
    One particularly effective way of handling sub-commands is to combine the use
    of the :meth:`add_subparsers` method with calls to :meth:`set_defaults` so
@@ -1466,7 +1476,7 @@
      >>> args.func(args)
      ((XYZYX))
 
-   This way, you can let :meth:`parse_args` does the job of calling the
+   This way, you can let :meth:`parse_args` do the job of calling the
    appropriate function after argument parsing is complete.  Associating
    functions with actions like this is typically the easiest way to handle the
    different actions for each of your subparsers.  However, if it is necessary
@@ -1648,14 +1658,14 @@
 .. method:: ArgumentParser.print_usage(file=None)
 
    Print a brief description of how the :class:`ArgumentParser` should be
-   invoked on the command line.  If *file* is ``None``, :data:`sys.stderr` is
+   invoked on the command line.  If *file* is ``None``, :data:`sys.stdout` is
    assumed.
 
 .. method:: ArgumentParser.print_help(file=None)
 
    Print a help message, including the program usage and information about the
    arguments registered with the :class:`ArgumentParser`.  If *file* is
-   ``None``, :data:`sys.stderr` is assumed.
+   ``None``, :data:`sys.stdout` is assumed.
 
 There are also variants of these methods that simply return a string instead of
 printing it:
@@ -1729,6 +1739,7 @@
    This method prints a usage message including the *message* to the
    standard output and terminates the program with a status code of 2.
 
+.. _upgrading-optparse-code:
 
 Upgrading optparse code
 -----------------------

Modified: python/branches/py3k-cdecimal/Doc/library/array.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/array.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/array.rst	Sun Jan  2 13:18:37 2011
@@ -65,10 +65,6 @@
    passed to the :meth:`extend` method.
 
 
-.. data:: ArrayType
-
-   Obsolete alias for :class:`array`.
-
 .. data:: typecodes
 
    A string with all available type codes.

Modified: python/branches/py3k-cdecimal/Doc/library/bdb.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/bdb.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/bdb.rst	Sun Jan  2 13:18:37 2011
@@ -359,12 +359,10 @@
 .. function:: effective(file, line, frame)
 
    Determine if there is an effective (active) breakpoint at this line of code.
-   Return breakpoint number or 0 if none.
-
-   Called only if we know there is a breakpoint at this location.  Returns the
-   breakpoint that was triggered and a flag that indicates if it is ok to delete
-   a temporary breakpoint.
+   Return a tuple of the breakpoint and a boolean that indicates if it is ok
+   to delete a temporary breakpoint.  Return ``(None, None)`` if there is no
+   matching breakpoint.
 
 .. function:: set_trace()
 
-   Starts debugging with a :class:`Bdb` instance from caller's frame.
+   Start debugging with a :class:`Bdb` instance from caller's frame.

Modified: python/branches/py3k-cdecimal/Doc/library/builtins.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/builtins.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/builtins.rst	Sun Jan  2 13:18:37 2011
@@ -32,9 +32,8 @@
 
        # ...
 
-As an implementation detail, most modules have the name ``__builtins__`` (note
-the ``'s'``) made available as part of their globals.  The value of
-``__builtins__`` is normally either this module or the value of this modules's
-:attr:`__dict__` attribute.  Since this is an implementation detail, it may not
-be used by alternate implementations of Python.
-
+As an implementation detail, most modules have the name ``__builtins__`` made
+available as part of their globals.  The value of ``__builtins__`` is normally
+either this module or the value of this modules's :attr:`__dict__` attribute.
+Since this is an implementation detail, it may not be used by alternate
+implementations of Python.

Modified: python/branches/py3k-cdecimal/Doc/library/codecs.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/codecs.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/codecs.rst	Sun Jan  2 13:18:37 2011
@@ -1114,9 +1114,9 @@
 +-----------------+--------------------------------+--------------------------------+
 | utf_16          | U16, utf16                     | all languages                  |
 +-----------------+--------------------------------+--------------------------------+
-| utf_16_be       | UTF-16BE                       | all languages (BMP only)       |
+| utf_16_be       | UTF-16BE                       | all languages                  |
 +-----------------+--------------------------------+--------------------------------+
-| utf_16_le       | UTF-16LE                       | all languages (BMP only)       |
+| utf_16_le       | UTF-16LE                       | all languages                  |
 +-----------------+--------------------------------+--------------------------------+
 | utf_7           | U7, unicode-1-1-utf-7          | all languages                  |
 +-----------------+--------------------------------+--------------------------------+
@@ -1165,6 +1165,44 @@
 |                    |         | operand                   |
 +--------------------+---------+---------------------------+
 
+The following codecs provide bytes-to-bytes mappings.
+
++--------------------+---------------------------+---------------------------+
+| Codec              | Aliases                   | Purpose                   |
++====================+===========================+===========================+
+| base64_codec       | base64, base-64           | Convert operand to MIME   |
+|                    |                           | base64                    |
++--------------------+---------------------------+---------------------------+
+| bz2_codec          | bz2                       | Compress the operand      |
+|                    |                           | using bz2                 |
++--------------------+---------------------------+---------------------------+
+| hex_codec          | hex                       | Convert operand to        |
+|                    |                           | hexadecimal               |
+|                    |                           | representation, with two  |
+|                    |                           | digits per byte           |
++--------------------+---------------------------+---------------------------+
+| quopri_codec       | quopri, quoted-printable, | Convert operand to MIME   |
+|                    | quotedprintable           | quoted printable          |
++--------------------+---------------------------+---------------------------+
+| uu_codec           | uu                        | Convert the operand using |
+|                    |                           | uuencode                  |
++--------------------+---------------------------+---------------------------+
+| zlib_codec         | zip, zlib                 | Compress the operand      |
+|                    |                           | using gzip                |
++--------------------+---------------------------+---------------------------+
+
+The following codecs provide string-to-string mappings.
+
++--------------------+---------------------------+---------------------------+
+| Codec              | Aliases                   | Purpose                   |
++====================+===========================+===========================+
+| rot_13             | rot13                     | Returns the Caesar-cypher |
+|                    |                           | encryption of the operand |
++--------------------+---------------------------+---------------------------+
+
+.. versionadded:: 3.2
+   bytes-to-bytes and string-to-string codecs.
+
 
 :mod:`encodings.idna` --- Internationalized Domain Names in Applications
 ------------------------------------------------------------------------

Modified: python/branches/py3k-cdecimal/Doc/library/collections.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/collections.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/collections.rst	Sun Jan  2 13:18:37 2011
@@ -28,7 +28,7 @@
 =====================   ====================================================================
 
 In addition to the concrete container classes, the collections module provides
-ABCs (abstract base classes) that can be used to test whether a class provides a
+:ref:`abstract-base-classes` that can be used to test whether a class provides a
 particular interface, for example, whether it is hashable or a mapping.
 
 .. seealso::
@@ -866,7 +866,7 @@
 original insertion position is changed and moved to the end::
 
     class LastUpdatedOrderedDict(OrderedDict):
-        'Store items is the order the keys were last added'
+        'Store items in the order the keys were last added'
         def __setitem__(self, key, value):
             if key in self:
                 del self[key]
@@ -959,6 +959,7 @@
    subclass) or an arbitrary sequence which can be converted into a string using
    the built-in :func:`str` function.
 
+.. _abstract-base-classes:
 
 ABCs - abstract base classes
 ----------------------------

Modified: python/branches/py3k-cdecimal/Doc/library/compileall.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/compileall.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/compileall.rst	Sun Jan  2 13:18:37 2011
@@ -6,9 +6,10 @@
 
 
 This module provides some utility functions to support installing Python
-libraries.  These functions compile Python source files in a directory tree,
-allowing users without permission to write to the libraries to take advantage of
-cached byte-code files.
+libraries.  These functions compile Python source files in a directory tree.
+This module can be used to create the cached byte-code files at library
+installation time, which makes them available for use even by users who don't
+have write permission to the library directories.
 
 
 Command-line use
@@ -27,7 +28,8 @@
 
 .. cmdoption:: -l
 
-   Do not recurse.
+   Do not recurse into subdirectories, only compile source code files directly
+   contained in the named or implied directories.
 
 .. cmdoption:: -f
 
@@ -35,55 +37,118 @@
 
 .. cmdoption:: -q
 
-   Do not print the list of files compiled.
+   Do not print the list of files compiled, print only error messages.
 
 .. cmdoption:: -d destdir
 
-   Purported directory name for error messages.
+   Directory prepended to the path to each file being compiled.  This will
+   appear in compilation time tracebacks, and is also compiled in to the
+   byte-code file, where it will be used in tracebacks and other messages in
+   cases where the source file does not exist at the time the byte-code file is
+   executed.
 
 .. cmdoption:: -x regex
 
-   Skip files with a full path that matches given regular expression.
+   regex is used to search the full path to each file considered for
+   compilation, and if the regex produces a match, the file is skipped.
 
 .. cmdoption:: -i list
 
-   Expand list with its content (file and directory names).
+   Read the file ``list`` and add each line that it contains to the list of
+   files and directories to compile.  If ``list`` is ``-``, read lines from
+   ``stdin``.
 
 .. cmdoption:: -b
 
-   Write legacy ``.pyc`` file path names.  Default is to write :pep:`3147`-style
-   byte-compiled path names.
+   Write the byte-code files to their legacy locations and names, which may
+   overwrite byte-code files created by another version of Python.  The default
+   is to write files to their :pep:`3147` locations and names, which allows
+   byte-code files from multiple versions of Python to coexist.
+
+.. versionchanged:: 3.2
+   Added the ``-i``, ``-b`` and ``-h`` options.
 
 
 Public functions
 ----------------
 
-.. function:: compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None, quiet=False, legacy=False)
+.. function:: compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None, quiet=False, legacy=False, optimize=-1)
 
    Recursively descend the directory tree named by *dir*, compiling all :file:`.py`
-   files along the way.  The *maxlevels* parameter is used to limit the depth of
-   the recursion; it defaults to ``10``.  If *ddir* is given, it is used as the
-   base path from  which the filenames used in error messages will be generated.
+   files along the way.
+
+   The *maxlevels* parameter is used to limit the depth of the recursion; it
+   defaults to ``10``.
+
+   If *ddir* is given, it is prepended to the path to each file being compiled
+   for use in compilation time tracebacks, and is also compiled in to the
+   byte-code file, where it will be used in tracebacks and other messages in
+   cases where the source file does not exist at the time the byte-code file is
+   executed.
+
    If *force* is true, modules are re-compiled even if the timestamps are up to
    date.
 
-   If *rx* is given, it specifies a regular expression of file names to exclude
-   from the search; that expression is searched for in the full path.
+   If *rx* is given, its search method is called on the complete path to each
+   file considered for compilation, and if it returns a true value, the file
+   is skipped.
+
+   If *quiet* is true, nothing is printed to the standard output unless errors
+   occur.
+
+   If *legacy* is true, byte-code files are written to their legacy locations
+   and names, which may overwrite byte-code files created by another version of
+   Python.  The default is to write files to their :pep:`3147` locations and
+   names, which allows byte-code files from multiple versions of Python to
+   coexist.
+
+   *optimize* specifies the optimization level for the compiler.  It is passed to
+   the built-in :func:`compile` function.
+
+   .. versionchanged:: 3.2
+      Added the *legacy* and *optimize* parameter.
+
 
-   If *quiet* is true, nothing is printed to the standard output in normal
-   operation.
+.. function:: compile_file(fullname, ddir=None, force=False, rx=None, quiet=False, legacy=False, optimize=-1)
 
-   If *legacy* is true, old-style ``.pyc`` file path names are written,
-   otherwise (the default), :pep:`3147`-style path names are written.
+   Compile the file with path *fullname*.
 
+   If *ddir* is given, it is prepended to the path to the file being compiled
+   for use in compilation time tracebacks, and is also compiled in to the
+   byte-code file, where it will be used in tracebacks and other messages in
+   cases where the source file does not exist at the time the byte-code file is
+   executed.
 
-.. function:: compile_path(skip_curdir=True, maxlevels=0, force=False, legacy=False)
+   If *ra* is given, its search method is passed the full path name to the
+   file being compiled, and if it returns a true value, the file is not
+   compiled and ``True`` is returned.
+
+   If *quiet* is true, nothing is printed to the standard output unless errors
+   occur.
+
+   If *legacy* is true, byte-code files are written to their legacy locations
+   and names, which may overwrite byte-code files created by another version of
+   Python.  The default is to write files to their :pep:`3147` locations and
+   names, which allows byte-code files from multiple versions of Python to
+   coexist.
+
+   *optimize* specifies the optimization level for the compiler.  It is passed to
+   the built-in :func:`compile` function.
+
+   .. versionadded:: 3.2
+
+
+.. function:: compile_path(skip_curdir=True, maxlevels=0, force=False, legacy=False, optimize=-1)
 
    Byte-compile all the :file:`.py` files found along ``sys.path``. If
-   *skip_curdir* is true (the default), the current directory is not included in
-   the search.  The *maxlevels* parameter defaults to ``0``, and the *force*
-   and *legacy* parameters default to ``False``. All are
-   passed to the :func:`compile_dir` function.
+   *skip_curdir* is true (the default), the current directory is not included
+   in the search.  All other parameters are passed to the :func:`compile_dir`
+   function.  Note that unlike the other compile functions, ``maxlevels``
+   defaults to ``0``.
+
+   .. versionchanged:: 3.2
+      Added the *legacy* and *optimize* parameter.
+
 
 To force a recompile of all the :file:`.py` files in the :file:`Lib/`
 subdirectory and all its subdirectories::

Modified: python/branches/py3k-cdecimal/Doc/library/concurrent.futures.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/concurrent.futures.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/concurrent.futures.rst	Sun Jan  2 13:18:37 2011
@@ -1,5 +1,5 @@
-:mod:`concurrent.futures` --- Concurrent computation
-====================================================
+:mod:`concurrent.futures` --- Launching parallel tasks
+======================================================
 
 .. module:: concurrent.futures
    :synopsis: Execute computations concurrently using threads or processes.
@@ -10,7 +10,7 @@
 asynchronously executing callables.
 
 The asynchronous execution can be be performed with threads, using
-:class:`ThreadPoolExecutor`, or seperate processes, using
+:class:`ThreadPoolExecutor`, or separate processes, using
 :class:`ProcessPoolExecutor`.  Both implement the same interface, which is
 defined by the abstract :class:`Executor` class.
 

Modified: python/branches/py3k-cdecimal/Doc/library/configparser.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/configparser.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/configparser.rst	Sun Jan  2 13:18:37 2011
@@ -17,11 +17,10 @@
    single: ini file
    single: Windows ini file
 
-This module provides the classes :class:`RawConfigParser` and
-:class:`SafeConfigParser`.  They implement a basic configuration
-language which provides a structure similar to what's found in Microsoft
-Windows INI files.  You can use this to write Python programs which can be
-customized by end users easily.
+This module provides the :class:`ConfigParser` class which implements a basic
+configuration language which provides a structure similar to what's found in
+Microsoft Windows INI files.  You can use this to write Python programs which
+can be customized by end users easily.
 
 .. note::
 
@@ -34,6 +33,10 @@
       Support for a creating Unix shell-like mini-languages which can be used
       as an alternate format for application configuration files.
 
+   Module :mod:`json`
+      The json module implements a subset of JavaScript syntax which can also
+      be used for this purpose.
+
 
 Quick Start
 -----------
@@ -43,17 +46,17 @@
 .. code-block:: ini
 
    [DEFAULT]
-     ServerAliveInterval = 45
-     Compression = yes
-     CompressionLevel = 9
-     ForwardX11 = yes
+   ServerAliveInterval = 45
+   Compression = yes
+   CompressionLevel = 9
+   ForwardX11 = yes
 
    [bitbucket.org]
-     User = hg
+   User = hg
 
    [topsecret.server.com]
-     Port = 50022
-     ForwardX11 = no
+   Port = 50022
+   ForwardX11 = no
 
 The structure of INI files is described `in the following section
 <#supported-ini-file-structure>`_.  Essentially, the file
@@ -64,7 +67,7 @@
 .. doctest::
 
    >>> import configparser
-   >>> config = configparser.RawConfigParser()
+   >>> config = configparser.ConfigParser()
    >>> config['DEFAULT'] = {'ServerAliveInterval': '45',
    ...                      'Compression': 'yes',
    ...                      'CompressionLevel': '9'}
@@ -89,7 +92,7 @@
 .. doctest::
 
    >>> import configparser
-   >>> config = configparser.RawConfigParser()
+   >>> config = configparser.ConfigParser()
    >>> config.sections()
    []
    >>> config.read('example.ini')
@@ -227,63 +230,129 @@
 
 Configuration files may include comments, prefixed by specific
 characters (``#`` and ``;`` by default [1]_).  Comments may appear on
-their own on an otherwise empty line, or may be entered on lines holding
-values or section names.  In the latter case, they need to be preceded
-by a whitespace character to be recognized as a comment.  For backwards
-compatibility, by default only ``;`` starts an inline comment, while
-``#`` does not [1]_.
-
-On top of the core functionality, :class:`SafeConfigParser` supports
-interpolation.  This means values can contain format strings which refer to
-other values in the same section, or values in a special ``DEFAULT`` section
-[1]_.  Additional defaults can be provided on initialization.
+their own on an otherwise empty line, possibly indented. [1]_
 
 For example:
 
 .. code-block:: ini
 
-   [Paths]
-   home_dir: /Users
-   my_dir: %(home_dir)s/lumberjack
-   my_pictures: %(my_dir)s/Pictures
+   [Simple Values]
+   key=value
+   spaces in keys=allowed
+   spaces in values=allowed as well
+   spaces around the delimiter = obviously
+   you can also use : to delimit keys from values
+
+   [All Values Are Strings]
+   values like this: 1000000
+   or this: 3.14159265359
+   are they treated as numbers? : no
+   integers, floats and booleans are held as: strings
+   can use the API to get converted values directly: true
 
    [Multiline Values]
    chorus: I'm a lumberjack, and I'm okay
-      I sleep all night and I work all day
+       I sleep all night and I work all day
 
    [No Values]
    key_without_value
    empty string value here =
 
-   [You can use comments] ; after a useful line
-   ; in an empty line
-   after: a_value ; here's another comment
-   inside: a         ;comment
-           multiline ;comment
-           value!    ;comment
-
-      [Sections Can Be Indented]
-         can_values_be_as_well = True
-         does_that_mean_anything_special = False
-         purpose = formatting for readability
-         multiline_values = are
-            handled just fine as
-            long as they are indented
-            deeper than the first line
-            of a value
-         # Did I mention we can indent comments, too?
-
-In the example above, :class:`SafeConfigParser` would resolve ``%(home_dir)s``
-to the value of ``home_dir`` (``/Users`` in this case).  ``%(my_dir)s`` in
-effect would resolve to ``/Users/lumberjack``.  All interpolations are done on
-demand so keys used in the chain of references do not have to be specified in
-any specific order in the configuration file.
-
-:class:`RawConfigParser` would simply return ``%(my_dir)s/Pictures`` as the
-value of ``my_pictures`` and ``%(home_dir)s/lumberjack`` as the value of
-``my_dir``.  Other features presented in the example are handled in the same
-manner by both parsers.
+   [You can use comments]
+   # like this
+   ; or this
+
+   # By default only in an empty line.
+   # Inline comments can be harmful because they prevent users
+   # from using the delimiting characters as parts of values.
+   # That being said, this can be customized.
+
+       [Sections Can Be Indented]
+           can_values_be_as_well = True
+           does_that_mean_anything_special = False
+           purpose = formatting for readability
+           multiline_values = are
+               handled just fine as
+               long as they are indented
+               deeper than the first line
+               of a value
+           # Did I mention we can indent comments, too?
+
+
+Interpolation of values
+-----------------------
+
+On top of the core functionality, :class:`ConfigParser` supports
+interpolation.  This means values can be preprocessed before returning them
+from ``get()`` calls.
+
+.. class:: BasicInterpolation()
+
+   The default implementation used by :class:`ConfigParser`.  It enables
+   values to contain format strings which refer to other values in the same
+   section, or values in the special default section [1]_.  Additional default
+   values can be provided on initialization.
+
+   For example:
+
+   .. code-block:: ini
+
+      [Paths]
+      home_dir: /Users
+      my_dir: %(home_dir)s/lumberjack
+      my_pictures: %(my_dir)s/Pictures
+
+
+   In the example above, :class:`ConfigParser` with *interpolation* set to
+   ``BasicInterpolation()`` would resolve ``%(home_dir)s`` to the value of
+   ``home_dir`` (``/Users`` in this case).  ``%(my_dir)s`` in effect would
+   resolve to ``/Users/lumberjack``.  All interpolations are done on demand so
+   keys used in the chain of references do not have to be specified in any
+   specific order in the configuration file.
+
+   With ``interpolation`` set to ``None``, the parser would simply return
+   ``%(my_dir)s/Pictures`` as the value of ``my_pictures`` and
+   ``%(home_dir)s/lumberjack`` as the value of ``my_dir``.
+
+.. class:: ExtendedInterpolation()
+
+   An alternative handler for interpolation which implements a more advanced
+   syntax, used for instance in ``zc.buildout``. Extended interpolation is
+   using ``${section:option}`` to denote a value from a foreign section.
+   Interpolation can span multiple levels. For convenience, if the ``section:``
+   part is omitted, interpolation defaults to the current section (and possibly
+   the default values from the special section).
+
+   For example, the configuration specified above with basic interpolation,
+   would look like this with extended interpolation:
+
+   .. code-block:: ini
+
+      [Paths]
+      home_dir: /Users
+      my_dir: ${home_dir}/lumberjack
+      my_pictures: ${my_dir}/Pictures
+
+   Values from other sections can be fetched as well:
+
+   .. code-block:: ini
+
+      [Common]
+      home_dir: /Users
+      library_dir: /Library
+      system_dir: /System
+      macports_dir: /opt/local
 
+      [Frameworks]
+      Python: 3.2
+      path: ${Common:system_dir}/Library/Frameworks/
+
+      [Arthur]
+      nickname: Two Sheds
+      last_name: Jackson
+      my_dir: ${Common:home_dir}/twosheds
+      my_pictures: ${my_dir}/Pictures
+      python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python}
 
 Mapping Protocol Access
 -----------------------
@@ -320,19 +389,22 @@
   the default value to be visible again.  Trying to delete a default value
   causes a ``KeyError``.
 
-* Trying to delete the ``DEFAULTSECT`` throws ``ValueError``.
-
-* There are two parser-level methods in the legacy API that hide the dictionary
-  interface and are incompatible:
-
-  * ``parser.get(section, option, **kwargs)`` - the second argument is **not** a
-    fallback value
+* Trying to delete the ``DEFAULTSECT`` raises ``ValueError``.
 
-  * ``parser.items(section)`` - this returns a list of *option*, *value* pairs
-    for a specified ``section``
+* ``parser.get(section, option, **kwargs)`` - the second argument is **not**
+  a fallback value. Note however that the section-level ``get()`` methods are
+  compatible both with the mapping protocol and the classic configparser API.
+
+* ``parser.items()`` is compatible with the mapping protocol (returns a list of
+  *section_name*, *section_proxy* pairs including the DEFAULTSECT).  However,
+  this method can also be invoked with arguments: ``parser.items(section, raw,
+  vars)``. The latter call returns a list of *option*, *value* pairs for
+  a specified ``section``, with all interpolations expanded (unless
+  ``raw=True`` is provided).
 
 The mapping protocol is implemented on top of the existing legacy API so that
-subclassing the original interface makes the mappings work as expected as well.
+subclasses overriding the original interface still should have mappings working
+as expected.
 
 
 Customizing Parser Behaviour
@@ -350,9 +422,9 @@
 * *defaults*, default value: ``None``
 
   This option accepts a dictionary of key-value pairs which will be initially
-  put in the ``DEFAULTSECT``.  This makes for an elegant way to support concise
-  configuration files that don't specify values which are the same as the
-  documented default.
+  put in the ``DEFAULT`` section.  This makes for an elegant way to support
+  concise configuration files that don't specify values which are the same as
+  the documented default.
 
   Hint: if you want to specify default values for a specific section, use
   :meth:`read_dict` before you read the actual file.
@@ -374,7 +446,7 @@
 
   .. doctest::
 
-     >>> parser = configparser.RawConfigParser()
+     >>> parser = configparser.ConfigParser()
      >>> parser.read_dict({'section1': {'key1': 'value1',
      ...                                'key2': 'value2',
      ...                                'key3': 'value3'},
@@ -395,7 +467,7 @@
   .. doctest::
 
      >>> from collections import OrderedDict
-     >>> parser = configparser.RawConfigParser()
+     >>> parser = configparser.ConfigParser()
      >>> parser.read_dict(
      ...   OrderedDict((
      ...     ('s1',
@@ -439,9 +511,10 @@
      ...   skip-external-locking
      ...   old_passwords = 1
      ...   skip-bdb
-     ...   skip-innodb # we don't need ACID today
+     ...   # we don't need ACID today
+     ...   skip-innodb
      ... """
-     >>> config = configparser.RawConfigParser(allow_no_value=True)
+     >>> config = configparser.ConfigParser(allow_no_value=True)
      >>> config.read_string(sample_config)
 
      >>> # Settings with values are treated as before:
@@ -464,30 +537,80 @@
   This means values (but not keys) can contain the delimiters.
 
   See also the *space_around_delimiters* argument to
-  :meth:`RawConfigParser.write`.
+  :meth:`ConfigParser.write`.
 
-* *comment_prefixes*, default value: ``_COMPATIBLE`` (``'#'`` valid on empty
-  lines, ``';'`` valid also on non-empty lines)
+* *comment_prefixes*, default value: ``('#', ';')``
 
-  Comment prefixes are strings that indicate the start of a valid comment
-  within a config file.  The peculiar default value allows for comments starting
-  with ``'#'`` or ``';'`` but only the latter can be used in a non-empty line.
-  This is obviously dictated by backwards compatibiliy.  A more predictable
-  approach would be to specify prefixes as ``('#', ';')`` which will allow for
-  both prefixes to be used in non-empty lines.
+* *inline_comment_prefixes*, default value: ``None``
+
+  Comment prefixes are strings that indicate the start of a valid comment within
+  a config file. *comment_prefixes* are used only on otherwise empty lines
+  (optionally indented) whereas *inline_comment_prefixes* can be used after
+  every valid value (e.g.  section names, options and empty lines as well). By
+  default inline comments are disabled and ``'#'`` and ``';'`` are used as
+  prefixes for whole line comments.
+
+  .. versionchanged:: 3.2
+     In previous versions of :mod:`configparser` behaviour matched
+     ``comment_prefixes=('#',';')`` and ``inline_comment_prefixes=(';',)``.
 
   Please note that config parsers don't support escaping of comment prefixes so
-  leaving characters out of *comment_prefixes* is a way of ensuring they can be
-  used as parts of keys or values.
+  using *inline_comment_prefixes* may prevent users from specifying option
+  values with characters used as comment prefixes. When in doubt, avoid setting
+  *inline_comment_prefixes*. In any circumstances, the only way of storing
+  comment prefix characters at the beginning of a line in multiline values is to
+  interpolate the prefix, for example::
+
+    >>> from configparser import ConfigParser, ExtendedInterpolation
+    >>> parser = ConfigParser(interpolation=ExtendedInterpolation())
+    >>> # the default BasicInterpolation could be used as well
+    >>> parser.read_string("""
+    ... [DEFAULT]
+    ... hash = #
+    ...
+    ... [hashes]
+    ... shebang =
+    ...   ${hash}!/usr/bin/env python
+    ...   ${hash} -*- coding: utf-8 -*-
+    ...
+    ... extensions =
+    ...   enabled_extension
+    ...   another_extension
+    ...   #disabled_by_comment
+    ...   yet_another_extension
+    ...
+    ... interpolation not necessary = if # is not at line start
+    ... even in multiline values = line #1
+    ...   line #2
+    ...   line #3
+    ... """)
+    >>> print(parser['hashes']['shebang'])
+
+    #!/usr/bin/env python
+    # -*- coding: utf-8 -*-
+    >>> print(parser['hashes']['extensions'])
+
+    enabled_extension
+    another_extension
+    yet_another_extension
+    >>> print(parser['hashes']['interpolation not necessary'])
+    if # is not at line start
+    >>> print(parser['hashes']['even in multiline values'])
+    line #1
+    line #2
+    line #3
 
-* *strict*, default value: ``False``
+* *strict*, default value: ``True``
 
-  If set to ``True``, the parser will not allow for any section or option
+  When set to ``True``, the parser will not allow for any section or option
   duplicates while reading from a single source (using :meth:`read_file`,
-  :meth:`read_string` or :meth:`read_dict`).  The default is ``False`` only
-  because of backwards compatibility reasons.  It is recommended to use strict
+  :meth:`read_string` or :meth:`read_dict`). It is recommended to use strict
   parsers in new applications.
 
+  .. versionchanged:: 3.2
+     In previous versions of :mod:`configparser` behaviour matched
+     ``strict=False``.
+
 * *empty_lines_in_values*, default value: ``True``
 
   In config parsers, values can span multiple lines as long as they are
@@ -505,13 +628,35 @@
 
       this = is still a part of the multiline value of 'key'
 
-
   This can be especially problematic for the user to see if she's using a
   proportional font to edit the file.  That is why when your application does
   not need values with empty lines, you should consider disallowing them.  This
   will make empty lines split keys every time.  In the example above, it would
   produce two keys, ``key`` and ``this``.
 
+* *default_section*, default value: ``configparser.DEFAULTSECT`` (that is:
+  ``"DEFAULT"``)
+
+  The convention of allowing a special section of default values for other
+  sections or interpolation purposes is a powerful concept of this library,
+  letting users create complex declarative configurations. This section is
+  normally called ``"DEFAULT"`` but this can be customized to point to any
+  other valid section name. Some typical values include: ``"general"`` or
+  ``"common"``. The name provided is used for recognizing default sections when
+  reading from any source and is used when writing configuration back to
+  a file. Its current value can be retrieved using the
+  ``parser_instance.default_section`` attribute and may be modified at runtime
+  (i.e. to convert files from one format to another).
+
+* *interpolation*, default value: ``configparser.BasicInterpolation``
+
+  Interpolation behaviour may be customized by providing a custom handler
+  through the *interpolation* argument. ``None`` can be used to turn off
+  interpolation completely, ``ExtendedInterpolation()`` provides a more
+  advanced variant inspired by ``zc.buildout``. More on the subject in the
+  `dedicated documentation section <#interpolation-of-values>`_.
+  :class:`RawConfigParser` has a default value of ``None``.
+
 
 More advanced customization may be achieved by overriding default values of
 these parser attributes.  The defaults are defined on the classes, so they
@@ -527,7 +672,7 @@
 
   .. doctest::
 
-     >>> custom = configparser.RawConfigParser()
+     >>> custom = configparser.ConfigParser()
      >>> custom['section1'] = {'funky': 'nope'}
      >>> custom['section1'].getboolean('funky')
      Traceback (most recent call last):
@@ -557,7 +702,7 @@
      ... [Section2]
      ... AnotherKey = Value
      ... """
-     >>> typical = configparser.RawConfigParser()
+     >>> typical = configparser.ConfigParser()
      >>> typical.read_string(config)
      >>> list(typical['Section1'].keys())
      ['key']
@@ -575,11 +720,11 @@
 Legacy API Examples
 -------------------
 
-Mainly because of backwards compatibility concerns, :mod:`configparser` provides
-also a legacy API with explicit ``get``/``set`` methods.  While there are valid
-use cases for the methods outlined below, mapping protocol access is preferred
-for new projects.  The legacy API is at times more advanced, low-level and
-downright counterintuitive.
+Mainly because of backwards compatibility concerns, :mod:`configparser`
+provides also a legacy API with explicit ``get``/``set`` methods.  While there
+are valid use cases for the methods outlined below, mapping protocol access is
+preferred for new projects.  The legacy API is at times more advanced,
+low-level and downright counterintuitive.
 
 An example of writing to a configuration file::
 
@@ -587,12 +732,11 @@
 
    config = configparser.RawConfigParser()
 
-   # Please note that using RawConfigParser's and the raw mode of
-   # ConfigParser's respective set functions, you can assign non-string values
-   # to keys internally, but will receive an error when attempting to write to
-   # a file or when you get it in non-raw mode. Setting values using the
-   # mapping protocol or SafeConfigParser's set() does not allow such
-   # assignments to take place.
+   # Please note that using RawConfigParser's set functions, you can assign
+   # non-string values to keys internally, but will receive an error when
+   # attempting to write to a file or when you get it in non-raw mode. Setting
+   # values using the mapping protocol or ConfigParser's set() does not allow
+   # such assignments to take place.
    config.add_section('Section1')
    config.set('Section1', 'int', '15')
    config.set('Section1', 'bool', 'true')
@@ -623,12 +767,11 @@
    if config.getboolean('Section1', 'bool'):
        print(config.get('Section1', 'foo'))
 
-To get interpolation, use :class:`SafeConfigParser` or, if
-you absolutely have to, a :class:`ConfigParser`::
+To get interpolation, use :class:`ConfigParser`::
 
    import configparser
 
-   cfg = configparser.SafeConfigParser()
+   cfg = configparser.ConfigParser()
    cfg.read('example.cfg')
 
    # Set the optional `raw` argument of get() to True if you wish to disable
@@ -657,13 +800,13 @@
    print(cfg.get('Section1', 'monster', fallback=None))
          # -> None
 
-Default values are available in all three types of ConfigParsers.  They are
-used in interpolation if an option used is not defined elsewhere. ::
+Default values are available in both types of ConfigParsers.  They are used in
+interpolation if an option used is not defined elsewhere. ::
 
    import configparser
 
    # New instance with 'bar' and 'baz' defaulting to 'Life' and 'hard' each
-   config = configparser.SafeConfigParser({'bar': 'Life', 'baz': 'hard'})
+   config = configparser.ConfigParser({'bar': 'Life', 'baz': 'hard'})
    config.read('example.cfg')
 
    print(config.get('Section1', 'foo')) # -> "Python is fun!"
@@ -672,42 +815,62 @@
    print(config.get('Section1', 'foo')) # -> "Life is hard!"
 
 
-.. _rawconfigparser-objects:
+.. _configparser-objects:
 
-RawConfigParser Objects
------------------------
+ConfigParser Objects
+--------------------
 
-.. class:: RawConfigParser(defaults=None, dict_type=collections.OrderedDict, allow_no_value=False, delimiters=('=', ':'), comment_prefixes=_COMPATIBLE, strict=False, empty_lines_in_values=True)
+.. class:: ConfigParser(defaults=None, dict_type=collections.OrderedDict, allow_no_value=False, delimiters=('=', ':'), comment_prefixes=('#', ';'), inline_comment_prefixes=None, strict=True, empty_lines_in_values=True, default_section=configparser.DEFAULTSECT, interpolation=BasicInterpolation())
 
-   The basic configuration parser.  When *defaults* is given, it is initialized
+   The main configuration parser.  When *defaults* is given, it is initialized
    into the dictionary of intrinsic defaults.  When *dict_type* is given, it
    will be used to create the dictionary objects for the list of sections, for
    the options within a section, and for the default values.
 
    When *delimiters* is given, it is used as the set of substrings that
    divide keys from values.  When *comment_prefixes* is given, it will be used
-   as the set of substrings that prefix comments in a line, both for the whole
+   as the set of substrings that prefix comments in otherwise empty lines.
+   Comments can be indented. When *inline_comment_prefixes* is given, it will be
+   used as the set of substrings that prefix comments in non-empty lines.
+
    line and inline comments.  For backwards compatibility, the default value for
    *comment_prefixes* is a special value that indicates that ``;`` and ``#`` can
    start whole line comments while only ``;`` can start inline comments.
 
-   When *strict* is ``True`` (default: ``False``), the parser won't allow for
+   When *strict* is ``True`` (the default), the parser won't allow for
    any section or option duplicates while reading from a single source (file,
    string or dictionary), raising :exc:`DuplicateSectionError` or
    :exc:`DuplicateOptionError`.  When *empty_lines_in_values* is ``False``
    (default: ``True``), each empty line marks the end of an option.  Otherwise,
    internal empty lines of a multiline option are kept as part of the value.
    When *allow_no_value* is ``True`` (default: ``False``), options without
-   values are accepted; the value presented for these is ``None``.
+   values are accepted; the value held for these is ``None`` and they are
+   serialized without the trailing delimiter.
 
-   This class does not support the magical interpolation behavior.
+   When *default_section* is given, it specifies the name for the special
+   section holding default values for other sections and interpolation purposes
+   (normally named ``"DEFAULT"``). This value can be retrieved and changed on
+   runtime using the ``default_section`` instance attribute.
+
+   Interpolation behaviour may be customized by providing a custom handler
+   through the *interpolation* argument. ``None`` can be used to turn off
+   interpolation completely, ``ExtendedInterpolation()`` provides a more
+   advanced variant inspired by ``zc.buildout``. More on the subject in the
+   `dedicated documentation section <#interpolation-of-values>`_.
+
+   All option names used in interpolation will be passed through the
+   :meth:`optionxform` method just like any other option name reference.  For
+   example, using the default implementation of :meth:`optionxform` (which
+   converts option names to lower case), the values ``foo %(bar)s`` and ``foo
+   %(BAR)s`` are equivalent.
 
    .. versionchanged:: 3.1
       The default *dict_type* is :class:`collections.OrderedDict`.
 
    .. versionchanged:: 3.2
-      *allow_no_value*, *delimiters*, *comment_prefixes*, *strict* and
-      *empty_lines_in_values* were added.
+      *allow_no_value*, *delimiters*, *comment_prefixes*, *strict*,
+      *empty_lines_in_values*, *default_section* and *interpolation* were
+      added.
 
 
    .. method:: defaults()
@@ -717,22 +880,25 @@
 
    .. method:: sections()
 
-      Return a list of the sections available; ``DEFAULT`` is not included in
-      the list.
+      Return a list of the sections available; the *default section* is not
+      included in the list.
 
 
    .. method:: add_section(section)
 
       Add a section named *section* to the instance.  If a section by the given
-      name already exists, :exc:`DuplicateSectionError` is raised.  If the name
-      ``DEFAULT`` (or any of it's case-insensitive variants) is passed,
-      :exc:`ValueError` is raised.
+      name already exists, :exc:`DuplicateSectionError` is raised.  If the
+      *default section* name is passed, :exc:`ValueError` is raised.  The name
+      of the section must be a string; if not, :exc:`TypeError` is raised.
+
+      .. versionchanged:: 3.2
+         Non-string section names raise :exc:`TypeError`.
 
 
    .. method:: has_section(section)
 
-      Indicates whether the named section is present in the configuration.  The
-      ``DEFAULT`` section is not acknowledged.
+      Indicates whether the named *section* is present in the configuration.
+      The *default section* is not acknowledged.
 
 
    .. method:: options(section)
@@ -742,23 +908,25 @@
 
    .. method:: has_option(section, option)
 
-      If the given section exists, and contains the given option, return
-      :const:`True`; otherwise return :const:`False`.
+      If the given *section* exists, and contains the given *option*, return
+      :const:`True`; otherwise return :const:`False`. If the specified
+      *section* is :const:`None` or an empty string, DEFAULT is assumed.
 
 
    .. method:: read(filenames, encoding=None)
 
       Attempt to read and parse a list of filenames, returning a list of
       filenames which were successfully parsed.  If *filenames* is a string, it
-      is treated as a single filename.  If a file named in *filenames* cannot be
-      opened, that file will be ignored.  This is designed so that you can
-      specify a list of potential configuration file locations (for example, the
-      current directory, the user's home directory, and some system-wide
-      directory), and all existing configuration files in the list will be read.
-      If none of the named files exist, the :class:`ConfigParser` instance will
-      contain an empty dataset.  An application which requires initial values to
-      be loaded from a file should load the required file or files using
-      :meth:`read_file` before calling :meth:`read` for any optional files::
+      is treated as a single filename.  If a file named in *filenames* cannot
+      be opened, that file will be ignored.  This is designed so that you can
+      specify a list of potential configuration file locations (for example,
+      the current directory, the user's home directory, and some system-wide
+      directory), and all existing configuration files in the list will be
+      read.  If none of the named files exist, the :class:`ConfigParser`
+      instance will contain an empty dataset.  An application which requires
+      initial values to be loaded from a file should load the required file or
+      files using :meth:`read_file` before calling :meth:`read` for any
+      optional files::
 
          import configparser, os
 
@@ -800,17 +968,21 @@
 
    .. method:: read_dict(dictionary, source='')
 
-      Load configuration from a dictionary.  Keys are section names, values are
-      dictionaries with keys and values that should be present in the section.
-      If the used dictionary type preserves order, sections and their keys will
-      be added in order.  Values are automatically converted to strings.
+      Load configuration from any object that provides a dict-like ``items()``
+      method.  Keys are section names, values are dictionaries with keys and
+      values that should be present in the section.  If the used dictionary
+      type preserves order, sections and their keys will be added in order.
+      Values are automatically converted to strings.
 
       Optional argument *source* specifies a context-specific name of the
       dictionary passed.  If not given, ```` is used.
 
+      This method can be used to copy state between parsers.
+
       .. versionadded:: 3.2
 
-   .. method:: get(section, option, [vars, fallback])
+
+   .. method:: get(section, option, raw=False, [vars, fallback])
 
       Get an *option* value for the named *section*.  If *vars* is provided, it
       must be a dictionary.  The *option* is looked up in *vars* (if provided),
@@ -818,58 +990,57 @@
       and *fallback* is provided, it is used as a fallback value.  ``None`` can
       be provided as a *fallback* value.
 
+      All the ``'%'`` interpolations are expanded in the return values, unless
+      the *raw* argument is true.  Values for interpolation keys are looked up
+      in the same manner as the option.
+
       .. versionchanged:: 3.2
-         Arguments *vars* and *fallback* are keyword only to protect users from
-         trying to use the third argument as the *fallback* fallback (especially
-         when using the mapping protocol).
+         Arguments *raw*, *vars* and *fallback* are keyword only to protect
+         users from trying to use the third argument as the *fallback* fallback
+         (especially when using the mapping protocol).
 
 
-   .. method:: getint(section, option, [vars, fallback])
+   .. method:: getint(section, option, raw=False, [vars, fallback])
 
       A convenience method which coerces the *option* in the specified *section*
-      to an integer.  See :meth:`get` for explanation of *vars* and *fallback*.
+      to an integer.  See :meth:`get` for explanation of *raw*, *vars* and
+      *fallback*.
 
 
-   .. method:: getfloat(section, option, [vars, fallback])
+   .. method:: getfloat(section, option, raw=False, [vars, fallback])
 
       A convenience method which coerces the *option* in the specified *section*
-      to a floating point number.  See :meth:`get` for explanation of *vars* and
-      *fallback*.
+      to a floating point number.  See :meth:`get` for explanation of *raw*,
+      *vars* and *fallback*.
 
 
-   .. method:: getboolean(section, option, [vars, fallback])
+   .. method:: getboolean(section, option, raw=False, [vars, fallback])
 
       A convenience method which coerces the *option* in the specified *section*
       to a Boolean value.  Note that the accepted values for the option are
-      ``"1"``, ``"yes"``, ``"true"``, and ``"on"``, which cause this method to
-      return ``True``, and ``"0"``, ``"no"``, ``"false"``, and ``"off"``, which
+      ``'1'``, ``'yes'``, ``'true'``, and ``'on'``, which cause this method to
+      return ``True``, and ``'0'``, ``'no'``, ``'false'``, and ``'off'``, which
       cause it to return ``False``.  These string values are checked in a
       case-insensitive manner.  Any other value will cause it to raise
-      :exc:`ValueError`. See :meth:`get` for explanation of *vars* and
+      :exc:`ValueError`.  See :meth:`get` for explanation of *raw*, *vars* and
       *fallback*.
 
 
-   .. method:: items(section)
+   .. method:: items([section], raw=False, vars=None)
 
-      Return a list of *name*, *value* pairs for each option in the given
-      *section*.
+      When *section* is not given, return a list of *section_name*,
+      *section_proxy* pairs, including DEFAULTSECT.
+
+      Otherwise, return a list of *name*, *value* pairs for the options in the
+      given *section*.  Optional arguments have the same meaning as for the
+      :meth:`get` method.
 
 
    .. method:: set(section, option, value)
 
       If the given section exists, set the given option to the specified value;
-      otherwise raise :exc:`NoSectionError`.  While it is possible to use
-      :class:`RawConfigParser` (or :class:`ConfigParser` with *raw* parameters
-      set to true) for *internal* storage of non-string values, full
-      functionality (including interpolation and output to files) can only be
-      achieved using string values.
-
-      .. note::
-
-         This method lets users assign non-string values to keys internally.
-         This behaviour is unsupported and will cause errors when attempting to
-         write to a file or get it in non-raw mode.  **Use the mapping protocol
-         API** which does not allow such assignments to take place.
+      otherwise raise :exc:`NoSectionError`.  *option* and *value* must be
+      strings; if not, :exc:`TypeError` is raised.
 
 
    .. method:: write(fileobject, space_around_delimiters=True)
@@ -921,134 +1092,52 @@
          Use :meth:`read_file` instead.
 
 
-.. _configparser-objects:
-
-ConfigParser Objects
---------------------
-
-.. warning::
-   Whenever you can, consider using :class:`SafeConfigParser` which adds
-   validation and escaping for the interpolation.
-
-The :class:`ConfigParser` class extends some methods of the
-:class:`RawConfigParser` interface, adding some optional arguments.
-
-.. class:: ConfigParser(defaults=None, dict_type=collections.OrderedDict, allow_no_value=False, delimiters=('=', ':'), comment_prefixes=_COMPATIBLE, strict=False, empty_lines_in_values=True)
-
-   Derived class of :class:`RawConfigParser` that implements the magical
-   interpolation feature and adds optional arguments to the :meth:`get` and
-   :meth:`items` methods.
-
-   :class:`SafeConfigParser` is generally recommended over this class if you
-   need interpolation.
-
-   The values in *defaults* must be appropriate for the ``%()s`` string
-   interpolation.
-
-   All option names used in interpolation will be passed through the
-   :meth:`optionxform` method just like any other option name reference.  For
-   example, using the default implementation of :meth:`optionxform` (which
-   converts option names to lower case), the values ``foo %(bar)s`` and ``foo
-   %(BAR)s`` are equivalent.
-
-   .. versionchanged:: 3.1
-      The default *dict_type* is :class:`collections.OrderedDict`.
-
-   .. versionchanged:: 3.2
-      *allow_no_value*, *delimiters*, *comment_prefixes*,
-      *strict* and *empty_lines_in_values* were added.
-
-
-   .. method:: get(section, option, raw=False, [vars, fallback])
-
-      Get an *option* value for the named *section*.  If *vars* is provided, it
-      must be a dictionary.  The *option* is looked up in *vars* (if provided),
-      *section*, and in *DEFAULTSECT* in that order.  If the key is not found
-      and *fallback* is provided, it is used as a fallback value.  ``None`` can
-      be provided as a *fallback* value.
-
-      All the ``'%'`` interpolations are expanded in the return values, unless
-      the *raw* argument is true.  Values for interpolation keys are looked up
-      in the same manner as the option.
-
-      .. versionchanged:: 3.2
-         Arguments *raw*, *vars* and *fallback* are keyword only to protect
-         users from trying to use the third argument as the *fallback* fallback
-         (especially when using the mapping protocol).
-
-
-   .. method:: getint(section, option, raw=False, [vars, fallback])
-
-      A convenience method which coerces the *option* in the specified *section*
-      to an integer.  See :meth:`get` for explanation of *raw*, *vars* and
-      *fallback*.
-
-
-   .. method:: getfloat(section, option, raw=False, [vars, fallback])
-
-      A convenience method which coerces the *option* in the specified *section*
-      to a floating point number.  See :meth:`get` for explanation of *raw*,
-      *vars* and *fallback*.
-
-
-   .. method:: getboolean(section, option, raw=False, [vars, fallback])
-
-      A convenience method which coerces the *option* in the specified *section*
-      to a Boolean value.  Note that the accepted values for the option are
-      ``'1'``, ``'yes'``, ``'true'``, and ``'on'``, which cause this method to
-      return ``True``, and ``'0'``, ``'no'``, ``'false'``, and ``'off'``, which
-      cause it to return ``False``.  These string values are checked in a
-      case-insensitive manner.  Any other value will cause it to raise
-      :exc:`ValueError`.  See :meth:`get` for explanation of *raw*, *vars* and
-      *fallback*.
-
-
-   .. method:: items(section, raw=False, vars=None)
-
-      Return a list of *name*, *value* pairs for the options in the given
-      *section*.  Optional arguments have the same meaning as for the
-      :meth:`get` method.
-
-
 .. data:: MAX_INTERPOLATION_DEPTH
 
    The maximum depth for recursive interpolation for :meth:`get` when the *raw*
-   parameter is false.  This is relevant only for the :class:`ConfigParser` class.
+   parameter is false.  This is relevant only when the default *interpolation*
+   is used.
 
 
-.. _safeconfigparser-objects:
+.. _rawconfigparser-objects:
 
-SafeConfigParser Objects
-------------------------
+RawConfigParser Objects
+-----------------------
 
-.. class:: SafeConfigParser(defaults=None, dict_type=collections.OrderedDict, allow_no_value=False, delimiters=('=', ':'), comment_prefixes=_COMPATIBLE, strict=False, empty_lines_in_values=True)
+.. class:: RawConfigParser(defaults=None, dict_type=collections.OrderedDict, allow_no_value=False, delimiters=('=', ':'), comment_prefixes=('#', ';'), inline_comment_prefixes=None, strict=True, empty_lines_in_values=True, default_section=configaparser.DEFAULTSECT, interpolation=None)
 
-   Derived class of :class:`ConfigParser` that implements a variant of the
-   magical interpolation feature.  This implementation is more predictable as
-   it validates the interpolation syntax used within a configuration file.
-   This class also enables escaping the interpolation character (a key can have
-   ``%`` as part of the value by specifying ``%%`` in the file).
+   Legacy variant of the :class:`ConfigParser` with interpolation disabled
+   by default and unsafe ``add_section`` and ``set`` methods.
 
-   Applications that don't require interpolation should use
-   :class:`RawConfigParser`, otherwise :class:`SafeConfigParser` is the best
-   option.
+   .. note::
+      Consider using :class:`ConfigParser` instead which checks types of
+      the values to be stored internally. If you don't want interpolation, you
+      can use ``ConfigParser(interpolation=None)``.
 
-   .. versionchanged:: 3.1
-      The default *dict_type* is :class:`collections.OrderedDict`.
 
-   .. versionchanged:: 3.2
-      *allow_no_value*, *delimiters*, *comment_prefixes*, *strict* and
-      *empty_lines_in_values* were added.
+   .. method:: add_section(section)
 
+      Add a section named *section* to the instance.  If a section by the given
+      name already exists, :exc:`DuplicateSectionError` is raised.  If the
+      *default section* name is passed, :exc:`ValueError` is raised.
+
+      Type of *section* is not checked which lets users create non-string named
+      sections. This behaviour is unsupported and may cause internal errors.
 
-   The :class:`SafeConfigParser` class implements the same extended interface
-   as :class:`ConfigParser`, with the following addition:
 
    .. method:: set(section, option, value)
 
       If the given section exists, set the given option to the specified value;
-      otherwise raise :exc:`NoSectionError`.  *value* must be a string; if not,
-      :exc:`TypeError` is raised.
+      otherwise raise :exc:`NoSectionError`.  While it is possible to use
+      :class:`RawConfigParser` (or :class:`ConfigParser` with *raw* parameters
+      set to true) for *internal* storage of non-string values, full
+      functionality (including interpolation and output to files) can only be
+      achieved using string values.
+
+      This method lets users assign non-string values to keys internally.  This
+      behaviour is unsupported and will cause errors when attempting to write
+      to a file or get it in non-raw mode.  **Use the mapping protocol API**
+      which does not allow such assignments to take place.
 
 
 Exceptions

Modified: python/branches/py3k-cdecimal/Doc/library/ctypes.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/ctypes.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/ctypes.rst	Sun Jan  2 13:18:37 2011
@@ -1930,22 +1930,6 @@
    but it is possible to enlarge the buffer.
 
 
-.. function:: set_conversion_mode(encoding, errors)
-
-   This function sets the rules that ctypes objects use when converting between
-   bytes objects and (unicode) strings. *encoding* must be a string specifying an
-   encoding, like ``'utf-8'`` or ``'mbcs'``, *errors* must be a string specifying
-   the error handling on encoding/decoding errors. Examples of possible values are
-   ``'strict'``, ``'replace'``, or ``'ignore'``.
-
-   :func:`set_conversion_mode` returns a 2-tuple containing the previous
-   conversion rules. On windows, the initial conversion rules are ``('mbcs',
-   'ignore')``, on other systems ``('ascii', 'strict')``.
-
-   You can set the *encoding* to ``'undefined'`` to completely disable automatic
-   conversions.
-
-
 .. function:: set_errno(value)
 
    Set the current value of the ctypes-private copy of the system :data:`errno`

Modified: python/branches/py3k-cdecimal/Doc/library/curses.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/curses.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/curses.rst	Sun Jan  2 13:18:37 2011
@@ -49,7 +49,7 @@
       Tutorial material on using curses with Python, by Andrew Kuchling and Eric
       Raymond.
 
-   The :file:`Demo/curses/` directory in the Python source distribution contains
+   The :file:`Tools/demo/` directory in the Python source distribution contains
    some example programs using the curses bindings provided by this module.
 
 

Modified: python/branches/py3k-cdecimal/Doc/library/dbm.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/dbm.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/dbm.rst	Sun Jan  2 13:18:37 2011
@@ -20,7 +20,7 @@
 
 .. function:: whichdb(filename)
 
-   This functionattempts to guess which of the several simple database modules
+   This function attempts to guess which of the several simple database modules
    available --- :mod:`dbm.gnu`, :mod:`dbm.ndbm` or :mod:`dbm.dumb` --- should
    be used to open a given file.
 
@@ -61,10 +61,15 @@
    modified by the prevailing umask).
 
 
-The object returned by :func:`.open` supports most of the same functionality as
+The object returned by :func:`.open` supports the same basic functionality as
 dictionaries; keys and their corresponding values can be stored, retrieved, and
 deleted, and the :keyword:`in` operator and the :meth:`keys` method are
-available. Key and values are always stored as bytes. This means that when
+available, as well as :meth:`get` and :meth:`setdefault`.
+
+.. versionchanged:: 3.2
+   :meth:`get` and :meth:`setdefault` are now available in all database modules.
+
+Key and values are always stored as bytes. This means that when
 strings are used they are implicitly converted to the default encoding before
 being stored.
 
@@ -86,10 +91,8 @@
    # Notice how the value is now in bytes.
    assert db['www.cnn.com'] == b'Cable News Network'
 
-   # Loop through contents.  Other dictionary methods
-   # such as .keys(), .values() also work.
-   for k, v in db.iteritems():
-       print(k, '\t', v)
+   # Often-used methods of the dict interface work too.
+   print(db.get('python.org', b'not present'))
 
    # Storing a non-string key or value will raise an exception (most
    # likely a TypeError).

Modified: python/branches/py3k-cdecimal/Doc/library/difflib.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/difflib.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/difflib.rst	Sun Jan  2 13:18:37 2011
@@ -17,6 +17,7 @@
 information in various formats, including HTML and context and unified
 diffs. For comparing directories and files, see also, the :mod:`filecmp` module.
 
+
 .. class:: SequenceMatcher
 
    This is a flexible class for comparing pairs of sequences of any type, so long
@@ -35,6 +36,17 @@
    complicated way on how many elements the sequences have in common; best case
    time is linear.
 
+   **Automatic junk heuristic:** :class:`SequenceMatcher` supports a heuristic that
+   automatically treats certain sequence items as junk. The heuristic counts how many
+   times each individual item appears in the sequence. If an item's duplicates (after
+   the first one) account for more than 1% of the sequence and the sequence is at least
+   200 items long, this item is marked as "popular" and is treated as junk for
+   the purpose of sequence matching. This heuristic can be turned off by setting
+   the ``autojunk`` argument to ``False`` when creating the :class:`SequenceMatcher`.
+
+   .. versionadded:: 3.2
+      The *autojunk* parameter.
+
 
 .. class:: Differ
 
@@ -324,7 +336,7 @@
 The :class:`SequenceMatcher` class has this constructor:
 
 
-.. class:: SequenceMatcher(isjunk=None, a='', b='')
+.. class:: SequenceMatcher(isjunk=None, a='', b='', autojunk=True)
 
    Optional argument *isjunk* must be ``None`` (the default) or a one-argument
    function that takes a sequence element and returns true if and only if the
@@ -340,8 +352,23 @@
    The optional arguments *a* and *b* are sequences to be compared; both default to
    empty strings.  The elements of both sequences must be :term:`hashable`.
 
-   :class:`SequenceMatcher` objects have the following methods:
+   The optional argument *autojunk* can be used to disable the automatic junk
+   heuristic.
 
+   .. versionadded:: 3.2
+      The *autojunk* parameter.
+
+   SequenceMatcher objects get three data attributes: *bjunk* is the
+   set of elements of *b* for which *isjunk* is True; *bpopular* is the set of
+   non-junk elements considered popular by the heuristic (if it is not
+   disabled); *b2j* is a dict mapping the remaining elements of *b* to a list
+   of positions where they occur. All three are reset whenever *b* is reset
+   with :meth:`set_seqs` or :meth:`set_seq2`.
+
+   .. versionadded:: 3.2
+      The *bjunk* and *bpopular* attributes.
+
+   :class:`SequenceMatcher` objects have the following methods:
 
    .. method:: set_seqs(a, b)
 
@@ -520,7 +547,7 @@
 SequenceMatcher Examples
 ------------------------
 
-This example compares two strings, considering blanks to be "junk:"
+This example compares two strings, considering blanks to be "junk":
 
    >>> s = SequenceMatcher(lambda x: x == " ",
    ...                     "private Thread currentThread;",

Modified: python/branches/py3k-cdecimal/Doc/library/dis.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/dis.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/dis.rst	Sun Jan  2 13:18:37 2011
@@ -733,11 +733,6 @@
    Used by the :keyword:`del` statement.
 
 
-.. opcode:: SET_LINENO (lineno)
-
-   This opcode is obsolete.
-
-
 .. opcode:: RAISE_VARARGS (argc)
 
    Raises an exception. *argc* indicates the number of parameters to the raise

Modified: python/branches/py3k-cdecimal/Doc/library/doctest.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/doctest.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/doctest.rst	Sun Jan  2 13:18:37 2011
@@ -922,7 +922,7 @@
 
    def load_tests(loader, tests, ignore):
        tests.addTests(doctest.DocTestSuite(my_module_with_doctests))
-       return test
+       return tests
 
 There are two main functions for creating :class:`unittest.TestSuite` instances
 from text files and modules with doctests:

Modified: python/branches/py3k-cdecimal/Doc/library/email.header.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/email.header.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/email.header.rst	Sun Jan  2 13:18:37 2011
@@ -63,7 +63,7 @@
    character set is used both as *s*'s initial charset and as the default for
    subsequent :meth:`append` calls.
 
-   The maximum line length can be specified explicit via *maxlinelen*.  For
+   The maximum line length can be specified explicitly via *maxlinelen*.  For
    splitting the first line to a shorter value (to account for the field header
    which isn't included in *s*, e.g. :mailheader:`Subject`) pass in the name of the
    field in *header_name*.  The default *maxlinelen* is 76, and the default value

Modified: python/branches/py3k-cdecimal/Doc/library/email.message.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/email.message.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/email.message.rst	Sun Jan  2 13:18:37 2011
@@ -270,7 +270,15 @@
       taken as the parameter name, with underscores converted to dashes (since
       dashes are illegal in Python identifiers).  Normally, the parameter will
       be added as ``key="value"`` unless the value is ``None``, in which case
-      only the key will be added.
+      only the key will be added.  If the value contains non-ASCII characters,
+      it can be specified as a three tuple in the format
+      ``(CHARSET, LANGUAGE, VALUE)``, where ``CHARSET`` is a string naming the
+      charset to be used to encode the value, ``LANGUAGE`` can usually be set
+      to ``None`` or the empty string (see :rfc:`2231` for other possibilities),
+      and ``VALUE`` is the string value containing non-ASCII code points.  If
+      a three tuple is not passed and the value contains non-ASCII characters,
+      it is automatically encoded in :rfc:`2231` format using a ``CHARSET``
+      of ``utf-8`` and a ``LANGUAGE`` of ``None``.
 
       Here's an example::
 
@@ -280,6 +288,15 @@
 
          Content-Disposition: attachment; filename="bud.gif"
 
+      An example with with non-ASCII characters::
+
+         msg.add_header('Content-Disposition', 'attachment',
+                        filename=('iso-8859-1', '', 'Fu??baller.ppt'))
+
+      Which produces ::
+
+         Content-Disposition: attachment; filename*="iso-8859-1''Fu%DFballer.ppt"
+
 
    .. method:: replace_header(_name, _value)
 
@@ -369,7 +386,7 @@
       :rfc:`2231`, you can collapse the parameter value by calling
       :func:`email.utils.collapse_rfc2231_value`, passing in the return value
       from :meth:`get_param`.  This will return a suitably decoded Unicode
-      string whn the value is a tuple, or the original string unquoted if it
+      string when the value is a tuple, or the original string unquoted if it
       isn't.  For example::
 
          rawparam = msg.get_param('foo')

Modified: python/branches/py3k-cdecimal/Doc/library/email.util.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/email.util.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/email.util.rst	Sun Jan  2 13:18:37 2011
@@ -105,11 +105,17 @@
    ``False``.  The default is ``False``.
 
 
-.. function:: make_msgid(idstring=None)
+.. function:: make_msgid(idstring=None, domain=None)
 
    Returns a string suitable for an :rfc:`2822`\ -compliant
    :mailheader:`Message-ID` header.  Optional *idstring* if given, is a string
-   used to strengthen the uniqueness of the message id.
+   used to strengthen the uniqueness of the message id.  Optional *domain* if
+   given provides the portion of the msgid after the '@'.  The default is the
+   local hostname.  It is not normally necessary to override this default, but
+   may be useful certain cases, such as a constructing distributed system that
+   uses a consistent domain name across multiple hosts.
+
+   .. versionchanged:: 3.2 domain keyword added
 
 
 .. function:: decode_rfc2231(s)

Modified: python/branches/py3k-cdecimal/Doc/library/exceptions.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/exceptions.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/exceptions.rst	Sun Jan  2 13:18:37 2011
@@ -63,6 +63,12 @@
    :exc:`FloatingPointError`.
 
 
+.. exception:: BufferError
+
+   Raised when a :ref:`buffer ` related operation cannot be
+   performed.
+
+
 .. exception:: LookupError
 
    The base class for the exceptions that are raised when a key or index used on
@@ -257,6 +263,18 @@
    of the exception instance returns only the message.
 
 
+.. exception:: IndentationError
+
+   Base class for syntax errors related to incorrect indentation.  This is a
+   subclass of :exc:`SyntaxError`.
+
+
+.. exception:: TabError
+
+   Raised when indentation contains an inconsistent use of tabs and spaces.
+   This is a subclass of :exc:`IndentationError`.
+
+
 .. exception:: SystemError
 
    Raised when the interpreter finds an internal error, but the situation does not

Modified: python/branches/py3k-cdecimal/Doc/library/fileformats.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/fileformats.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/fileformats.rst	Sun Jan  2 13:18:37 2011
@@ -5,7 +5,7 @@
 ************
 
 The modules described in this chapter parse various miscellaneous file formats
-that aren't markup languages or are related to e-mail.
+that aren't markup languages and are not related to e-mail.
 
 
 .. toctree::

Modified: python/branches/py3k-cdecimal/Doc/library/functions.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/functions.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/functions.rst	Sun Jan  2 13:18:37 2011
@@ -7,6 +7,24 @@
 The Python interpreter has a number of functions and types built into it that
 are always available.  They are listed here in alphabetical order.
 
+===================  =================  ==================  ================  ====================
+..                   ..                 Built-in Functions  ..                ..
+===================  =================  ==================  ================  ====================
+:func:`abs`          :func:`dict`       :func:`help`        :func:`min`       :func:`setattr`
+:func:`all`          :func:`dir`        :func:`hex`         :func:`next`      :func:`slice`
+:func:`any`          :func:`divmod`     :func:`id`          :func:`object`    :func:`sorted`
+:func:`ascii`        :func:`enumerate`  :func:`input`       :func:`oct`       :func:`staticmethod`
+:func:`bin`          :func:`eval`       :func:`int`         :func:`open`      :func:`str`
+:func:`bool`         :func:`exec`       :func:`isinstance`  :func:`ord`       :func:`sum`
+:func:`bytearray`    :func:`filter`     :func:`issubclass`  :func:`pow`       :func:`super`
+:func:`bytes`        :func:`float`      :func:`iter`        :func:`print`     :func:`tuple`
+:func:`callable`     :func:`format`     :func:`len`         :func:`property`  :func:`type`
+:func:`chr`          :func:`frozenset`  :func:`list`        :func:`range`     :func:`vars`
+:func:`classmethod`  :func:`getattr`    :func:`locals`      :func:`repr`      :func:`zip`
+:func:`compile`      :func:`globals`    :func:`map`         :func:`reversed`  :func:`__import__`
+:func:`complex`      :func:`hasattr`    :func:`max`         :func:`round`
+:func:`delattr`      :func:`hash`       :func:`memoryview`  :func:`set`
+===================  =================  ==================  ================  ====================
 
 .. function:: abs(x)
 
@@ -103,6 +121,19 @@
    Bytes objects can also be created with literals, see :ref:`strings`.
 
 
+.. function:: callable(object)
+
+   Return :const:`True` if the *object* argument appears callable,
+   :const:`False` if not.  If this returns true, it is still possible that a
+   call fails, but if it is false, calling *object* will never succeed.
+   Note that classes are callable (calling a class returns a new instance);
+   instances are callable if their class has a :meth:`__call__` method.
+
+   .. versionadded:: 3.2
+      This function was first removed in Python 3.0 and then brought back
+      in Python 3.2.
+
+
 .. function:: chr(i)
 
    Return the string representing a character whose Unicode codepoint is the integer
@@ -143,7 +174,7 @@
    type hierarchy in :ref:`types`.
 
 
-.. function:: compile(source, filename, mode, flags=0, dont_inherit=False)
+.. function:: compile(source, filename, mode, flags=0, dont_inherit=False, optimize=-1)
 
    Compile the *source* into a code or AST object.  Code objects can be executed
    by :func:`exec` or :func:`eval`.  *source* can either be a string or an AST
@@ -175,6 +206,12 @@
    can be found as the :attr:`compiler_flag` attribute on the :class:`_Feature`
    instance in the :mod:`__future__` module.
 
+   The argument *optimize* specifies the optimization level of the compiler; the
+   default value of ``-1`` selects the optimization level of the interpreter as
+   given by :option:`-O` options.  Explicit levels are ``0`` (no optimization;
+   ``__debug__`` is true), ``1`` (asserts are removed, ``__debug__`` is false)
+   or ``2`` (docstrings are removed too).
+
    This function raises :exc:`SyntaxError` if the compiled source is invalid,
    and :exc:`TypeError` if the source contains null bytes.
 
@@ -187,7 +224,7 @@
 
    .. versionchanged:: 3.2
       Allowed use of Windows and Mac newlines.  Also input in ``'exec'`` mode
-      does not have to end in a newline anymore.
+      does not have to end in a newline anymore.  Added the *optimize* parameter.
 
 
 .. function:: complex([real[, imag]])
@@ -417,8 +454,8 @@
       sign: "+" | "-"
       infinity: "Infinity" | "inf"
       nan: "nan"
-      numeric-value: `floatnumber` | `infinity` | `nan`
-      numeric-string: [`sign`] `numeric-value`
+      numeric_value: `floatnumber` | `infinity` | `nan`
+      numeric_string: [`sign`] `numeric_value`
 
    Here ``floatnumber`` is the form of a Python floating-point literal,
    described in :ref:`floating`.  Case is not significant, so, for example,
@@ -992,8 +1029,33 @@
       >>> list(range(1, 0))
       []
 
+   Range objects implement the :class:`collections.Sequence` ABC, and provide
+   features such as containment tests, element index lookup, slicing and
+   support for negative indices:
+
+      >>> r = range(0, 20, 2)
+      >>> r
+      range(0, 20, 2)
+      >>> 11 in r
+      False
+      >>> 10 in r
+      True
+      >>> r.index(10)
+      5
+      >>> r[5]
+      10
+      >>> r[:5]
+      range(0, 10, 2)
+      >>> r[-1]
+      18
+
+   Ranges containing absolute values larger than :data:`sys.maxsize` are permitted
+   but some features (such as :func:`len`) will raise :exc:`OverflowError`.
+
    .. versionchanged:: 3.2
-      Testing integers for membership takes constant time instead of iterating
+      Implement the Sequence ABC.
+      Support slicing and negative indices.
+      Test integers for membership in constant time instead of iterating
       through all items.
 
 

Modified: python/branches/py3k-cdecimal/Doc/library/functools.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/functools.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/functools.rst	Sun Jan  2 13:18:37 2011
@@ -32,7 +32,7 @@
    A compare function is any callable that accept two arguments, compares them,
    and returns a negative number for less-than, zero for equality, or a positive
    number for greater-than.  A key function is a callable that accepts one
-   argument and returns another value that indicates the position in the desired
+   argument and returns another value indicating the position in the desired
    collation sequence.
 
    Example::
@@ -42,37 +42,76 @@
    .. versionadded:: 3.2
 
 
-.. decorator:: lru_cache(maxsize)
+.. decorator:: lru_cache(maxsize=100)
 
    Decorator to wrap a function with a memoizing callable that saves up to the
    *maxsize* most recent calls.  It can save time when an expensive or I/O bound
    function is periodically called with the same arguments.
 
-   The *maxsize* parameter defaults to 100.  Since a dictionary is used to cache
-   results, the positional and keyword arguments to the function must be
-   hashable.
-
-   The wrapped function is instrumented with two attributes, :attr:`cache_hits`
-   and :attr:`cache_misses` which count the number of successful or unsuccessful
-   cache lookups.  These statistics are helpful for tuning the *maxsize*
-   parameter and for measuring the cache's effectiveness.
+   Since a dictionary is used to cache results, the positional and keyword
+   arguments to the function must be hashable.
 
-   The wrapped function also has a :attr:`cache_clear` attribute which can be
-   called (with no arguments) to clear the cache.
+   If *maxsize* is set to None, the LRU feature is disabled and the cache
+   can grow without bound.
+
+   To help measure the effectiveness of the cache and tune the *maxsize*
+   parameter, the wrapped function is instrumented with a :func:`cache_info`
+   function that returns a :term:`named tuple` showing *hits*, *misses*,
+   *maxsize* and *currsize*.  In a multi-threaded environment, the hits
+   and misses are approximate.
+
+   The decorator also provides a :func:`cache_clear` function for clearing or
+   invalidating the cache.
 
    The original underlying function is accessible through the
-   :attr:`__wrapped__` attribute.  This allows introspection, bypassing
-   the cache, or rewrapping the function with a different caching tool.
+   :attr:`__wrapped__` attribute.  This is useful for introspection, for
+   bypassing the cache, or for rewrapping the function with a different cache.
 
-   A `LRU (least recently used) cache
-   `_
-   is indicated when the pattern of calls changes over time, such as
-   when more recent calls are the best predictors of upcoming calls
-   (for example, the most popular articles on a news server tend to
-   change every day).
+   An `LRU (least recently used) cache
+   `_ works
+   best when more recent calls are the best predictors of upcoming calls (for
+   example, the most popular articles on a news server tend to change daily).
+   The cache's size limit assures that the cache does not grow without bound on
+   long-running processes such as web servers.
+
+   Example of an LRU cache for static web content::
+
+        @lru_cache(maxsize=20)
+        def get_pep(num):
+            'Retrieve text of a Python Enhancement Proposal'
+            resource = 'http://www.python.org/dev/peps/pep-%04d/' % num
+            try:
+                with urllib.request.urlopen(resource) as s:
+                    return s.read()
+            except urllib.error.HTTPError:
+                return 'Not Found'
+
+        >>> for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991:
+        ...     pep = get_pep(n)
+        ...     print(n, len(pep))
+
+        >>> print(get_pep.cache_info())
+        CacheInfo(hits=3, misses=8, maxsize=20, currsize=8)
+
+   Example of efficiently computing
+   `Fibonacci numbers `_
+   using a cache to implement a
+   `dynamic programming `_
+   technique::
+
+        @lru_cache(maxsize=None)
+        def fib(n):
+            if n < 2:
+                return n
+            return fib(n-1) + fib(n-2)
 
-   .. versionadded:: 3.2
+        >>> print([fib(n) for n in range(16)])
+        [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
 
+        >>> print(fib.cache_info())
+        CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)
+
+   .. versionadded:: 3.2
 
 .. decorator:: total_ordering
 

Modified: python/branches/py3k-cdecimal/Doc/library/grp.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/grp.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/grp.rst	Sun Jan  2 13:18:37 2011
@@ -30,7 +30,9 @@
 The gid is an integer, name and password are strings, and the member list is a
 list of strings. (Note that most users are not explicitly listed as members of
 the group they are in according to the password database.  Check both databases
-to get complete membership information.)
+to get complete membership information.  Also note that a ``gr_name`` that
+starts with a ``+`` or ``-`` is likely to be a YP/NIS reference and may not be
+accessible via :func:`getgrnam` or :func:`getgrgid`.)
 
 It defines the following items:
 

Modified: python/branches/py3k-cdecimal/Doc/library/hashlib.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/hashlib.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/hashlib.rst	Sun Jan  2 13:18:37 2011
@@ -135,7 +135,7 @@
 .. method:: hash.digest()
 
    Return the digest of the data passed to the :meth:`update` method so far.
-   This is a bytes array of size :attr:`digest_size` which may contain bytes in
+   This is a bytes object of size :attr:`digest_size` which may contain bytes in
    the whole range from 0 to 255.
 
 

Modified: python/branches/py3k-cdecimal/Doc/library/heapq.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/heapq.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/heapq.rst	Sun Jan  2 13:18:37 2011
@@ -16,11 +16,12 @@
    Latest version of the :source:`heapq Python source code
    `
 
-Heaps are arrays for which ``heap[k] <= heap[2*k+1]`` and ``heap[k] <=
-heap[2*k+2]`` for all *k*, counting elements from zero.  For the sake of
-comparison, non-existing elements are considered to be infinite.  The
-interesting property of a heap is that ``heap[0]`` is always its smallest
-element.
+Heaps are binary trees for which every parent node has a value less than or
+equal to any of its children.  This implementation uses arrays for which
+``heap[k] <= heap[2*k+1]`` and ``heap[k] <= heap[2*k+2]`` for all *k*, counting
+elements from zero.  For the sake of comparison, non-existing elements are
+considered to be infinite.  The interesting property of a heap is that its
+smallest element is always the root, ``heap[0]``.
 
 The API below differs from textbook heap algorithms in two aspects: (a) We use
 zero-based indexing.  This makes the relationship between the index for a node

Modified: python/branches/py3k-cdecimal/Doc/library/html.parser.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/html.parser.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/html.parser.rst	Sun Jan  2 13:18:37 2011
@@ -12,9 +12,13 @@
 This module defines a class :class:`HTMLParser` which serves as the basis for
 parsing text files formatted in HTML (HyperText Mark-up Language) and XHTML.
 
-.. class:: HTMLParser()
+.. class:: HTMLParser(strict=True)
 
-   The :class:`HTMLParser` class is instantiated without arguments.
+   Create a parser instance.  If *strict* is ``True`` (the default), invalid
+   html results in :exc:`~html.parser.HTMLParseError` exceptions [#]_.  If
+   *strict* is ``False``, the parser uses heuristics to make a best guess at
+   the intention of any invalid html it encounters, similar to the way most
+   browsers do.
 
    An :class:`HTMLParser` instance is fed HTML data and calls handler functions when tags
    begin and end.  The :class:`HTMLParser` class is meant to be overridden by the
@@ -23,6 +27,8 @@
    This parser does not check that end tags match start tags or call the end-tag
    handler for elements which are closed implicitly by closing an outer element.
 
+   .. versionchanged:: 3.2 *strict* keyword added
+
 An exception is defined as well:
 
 
@@ -191,3 +197,8 @@
    Encountered a html end tag
 
 
+.. rubric:: Footnotes
+
+.. [#] For backward compatibility reasons *strict* mode does not raise
+       exceptions for all non-compliant HTML.  That is, some invalid HTML
+       is tolerated even in *strict* mode.

Modified: python/branches/py3k-cdecimal/Doc/library/http.client.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/http.client.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/http.client.rst	Sun Jan  2 13:18:37 2011
@@ -23,16 +23,13 @@
 The module provides the following classes:
 
 
-.. class:: HTTPConnection(host, port=None, strict=None[, timeout[, source_address]])
+.. class:: HTTPConnection(host, port=None[, strict[, timeout[, source_address]]])
 
    An :class:`HTTPConnection` instance represents one transaction with an HTTP
    server.  It should be instantiated passing it a host and optional port
    number.  If no port number is passed, the port is extracted from the host
    string if it has the form ``host:port``, else the default HTTP port (80) is
-   used.  When True, the optional parameter *strict* (which defaults to a false
-   value) causes ``BadStatusLine`` to
-   be raised if the status line can't be parsed as a valid HTTP/1.0 or 1.1
-   status line.  If the optional *timeout* parameter is given, blocking
+   used.  If the optional *timeout* parameter is given, blocking
    operations (like connection attempts) will timeout after that many seconds
    (if it is not given, the global default timeout setting is used).
    The optional *source_address* parameter may be a typle of a (host, port)
@@ -49,8 +46,12 @@
    .. versionchanged:: 3.2
       *source_address* was added.
 
+   .. versionchanged:: 3.2
+      The *strict* parameter is deprecated.  HTTP 0.9-style "Simple Responses"
+      are not supported anymore.
+
 
-.. class:: HTTPSConnection(host, port=None, key_file=None, cert_file=None, strict=None[, timeout[, source_address]], *, context=None, check_hostname=None)
+.. class:: HTTPSConnection(host, port=None, key_file=None, cert_file=None[, strict[, timeout[, source_address]]], *, context=None, check_hostname=None)
 
    A subclass of :class:`HTTPConnection` that uses SSL for communication with
    secure servers.  Default port is ``443``.  If *context* is specified, it
@@ -80,12 +81,20 @@
       This class now supports HTTPS virtual hosts if possible (that is,
       if :data:`ssl.HAS_SNI` is true).
 
+   .. versionchanged:: 3.2
+      The *strict* parameter is deprecated.  HTTP 0.9-style "Simple Responses"
+      are not supported anymore.
+
 
-.. class:: HTTPResponse(sock, debuglevel=0, strict=0, method=None, url=None)
+.. class:: HTTPResponse(sock, debuglevel=0[, strict], method=None, url=None)
 
    Class whose instances are returned upon successful connection.  Not
    instantiated directly by user.
 
+   .. versionchanged:: 3.2
+      The *strict* parameter is deprecated.  HTTP 0.9-style "Simple Responses"
+      are not supported anymore.
+
 
 The following exceptions are raised as appropriate:
 
@@ -384,14 +393,18 @@
    string.
 
    The *body* may also be an open :term:`file object`, in which case the
-   contents of the file is sent; this file object should support
-   ``fileno()`` and ``read()`` methods. The header Content-Length is
-   automatically set to the length of the file as reported by
-   stat.
+   contents of the file is sent; this file object should support ``fileno()``
+   and ``read()`` methods. The header Content-Length is automatically set to
+   the length of the file as reported by stat. The *body* argument may also be
+   an iterable and Contet-Length header should be explicitly provided when the
+   body is an iterable.
 
    The *headers* argument should be a mapping of extra HTTP
    headers to send with the request.
 
+   .. versionadded:: 3.2
+      *body* can now be an iterable.
+
 .. method:: HTTPConnection.getresponse()
 
    Should be called after a request is sent to get the response from the server.
@@ -405,8 +418,10 @@
 
 .. method:: HTTPConnection.set_debuglevel(level)
 
-   Set the debugging level (the amount of debugging output printed). The default
-   debug level is ``0``, meaning no debugging output is printed.
+   Set the debugging level.  The default debug level is ``0``, meaning no
+   debugging output is printed.  Any value greater than ``0`` will cause all
+   currently defined debug output to be printed to stdout.  The ``debuglevel``
+   is passed to any new :class:`HTTPResponse` objects that are created.
 
    .. versionadded:: 3.1
 

Modified: python/branches/py3k-cdecimal/Doc/library/imp.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/imp.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/imp.rst	Sun Jan  2 13:18:37 2011
@@ -190,8 +190,8 @@
    continue to use the old class definition.  The same is true for derived classes.
 
 
-The following functions and data provide conveniences for handling :pep:`3147`
-byte-compiled file paths.
+The following functions are conveniences for handling :pep:`3147` byte-compiled
+file paths.
 
 .. versionadded:: 3.2
 
@@ -258,88 +258,6 @@
 
    The module was found as a frozen module (see :func:`init_frozen`).
 
-The following constant and functions are obsolete; their functionality is
-available through :func:`find_module` or :func:`load_module`. They are kept
-around for backward compatibility:
-
-
-.. data:: SEARCH_ERROR
-
-   Unused.
-
-
-.. function:: init_builtin(name)
-
-   Initialize the built-in module called *name* and return its module object along
-   with storing it in ``sys.modules``.  If the module was already initialized, it
-   will be initialized *again*.  Re-initialization involves the copying of the
-   built-in module's ``__dict__`` from the cached module over the module's entry in
-   ``sys.modules``.  If there is no built-in module called *name*, ``None`` is
-   returned.
-
-
-.. function:: init_frozen(name)
-
-   Initialize the frozen module called *name* and return its module object.  If
-   the module was already initialized, it will be initialized *again*.  If there
-   is no frozen module called *name*, ``None`` is returned.  (Frozen modules are
-   modules written in Python whose compiled byte-code object is incorporated
-   into a custom-built Python interpreter by Python's :program:`freeze`
-   utility. See :file:`Tools/freeze/` for now.)
-
-
-.. function:: is_builtin(name)
-
-   Return ``1`` if there is a built-in module called *name* which can be
-   initialized again.  Return ``-1`` if there is a built-in module called *name*
-   which cannot be initialized again (see :func:`init_builtin`).  Return ``0`` if
-   there is no built-in module called *name*.
-
-
-.. function:: is_frozen(name)
-
-   Return ``True`` if there is a frozen module (see :func:`init_frozen`) called
-   *name*, or ``False`` if there is no such module.
-
-
-.. function:: load_compiled(name, pathname, [file])
-
-   .. index:: pair: file; byte-code
-
-   Load and initialize a module implemented as a byte-compiled code file and return
-   its module object.  If the module was already initialized, it will be
-   initialized *again*.  The *name* argument is used to create or access a module
-   object.  The *pathname* argument points to the byte-compiled code file.  The
-   *file* argument is the byte-compiled code file, open for reading in binary mode,
-   from the beginning. It must currently be a real file object, not a user-defined
-   class emulating a file.
-
-
-.. function:: load_dynamic(name, pathname[, file])
-
-   Load and initialize a module implemented as a dynamically loadable shared
-   library and return its module object.  If the module was already initialized, it
-   will be initialized *again*. Re-initialization involves copying the ``__dict__``
-   attribute of the cached instance of the module over the value used in the module
-   cached in ``sys.modules``.  The *pathname* argument must point to the shared
-   library.  The *name* argument is used to construct the name of the
-   initialization function: an external C function called ``initname()`` in the
-   shared library is called.  The optional *file* argument is ignored.  (Note:
-   using shared libraries is highly system dependent, and not all systems support
-   it.)
-
-
-.. function:: load_source(name, pathname[, file])
-
-   Load and initialize a module implemented as a Python source file and return its
-   module object.  If the module was already initialized, it will be initialized
-   *again*.  The *name* argument is used to create or access a module object.  The
-   *pathname* argument points to the source file.  The *file* argument is the
-   source file, open for reading as text, from the beginning. It must currently be
-   a real file object, not a user-defined class emulating a file.  Note that if a
-   properly matching byte-compiled file (with suffix :file:`.pyc` or :file:`.pyo`)
-   exists, it will be used instead of parsing the given source file.
-
 
 .. class:: NullImporter(path_string)
 
@@ -390,10 +308,3 @@
            # Since we may exit via an exception, close fp explicitly.
            if fp:
                fp.close()
-
-.. index:: module: knee
-
-A more complete example that implements hierarchical module names and includes a
-:func:`reload` function can be found in the module :mod:`knee`.  The :mod:`knee`
-module can be found in :file:`Demo/imputil/` in the Python source distribution.
-

Modified: python/branches/py3k-cdecimal/Doc/library/inspect.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/inspect.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/inspect.rst	Sun Jan  2 13:18:37 2011
@@ -630,17 +630,17 @@
 When implementing coroutine schedulers and for other advanced uses of
 generators, it is useful to determine whether a generator is currently
 executing, is waiting to start or resume or execution, or has already
-terminated. func:`getgeneratorstate` allows the current state of a
+terminated. :func:`getgeneratorstate` allows the current state of a
 generator to be determined easily.
 
 .. function:: getgeneratorstate(generator)
 
-    Get current state of a generator-iterator.
+   Get current state of a generator-iterator.
 
-    Possible states are:
-      GEN_CREATED: Waiting to start execution.
-      GEN_RUNNING: Currently being executed by the interpreter.
-      GEN_SUSPENDED: Currently suspended at a yield expression.
-      GEN_CLOSED: Execution has completed.
+   Possible states are:
+   -  GEN_CREATED: Waiting to start execution.
+   -  GEN_RUNNING: Currently being executed by the interpreter.
+   -  GEN_SUSPENDED: Currently suspended at a yield expression.
+   -  GEN_CLOSED: Execution has completed.
 
    .. versionadded:: 3.2

Modified: python/branches/py3k-cdecimal/Doc/library/io.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/io.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/io.rst	Sun Jan  2 13:18:37 2011
@@ -54,12 +54,6 @@
 The text stream API is described in detail in the documentation for the
 :class:`TextIOBase`.
 
-.. note::
-
-   Text I/O over a binary storage (such as a file) is significantly slower than
-   binary I/O over the same storage.  This can become noticeable if you handle
-   huge amounts of text data (for example very large log files).
-
 
 Binary I/O
 ^^^^^^^^^^
@@ -361,9 +355,9 @@
 
    .. method:: readinto(b)
 
-      Read up to len(b) bytes into bytearray *b* and return the number ofbytes
-      read.  If the object is in non-blocking mode and no bytes are available,
-      ``None`` is returned.
+      Read up to len(b) bytes into bytearray *b* and return the number
+      of bytes read.  If the object is in non-blocking mode and no
+      bytes are available, ``None`` is returned.
 
    .. method:: write(b)
 
@@ -506,8 +500,8 @@
 Buffered Streams
 ^^^^^^^^^^^^^^^^
 
-In many situations, buffered I/O streams will provide higher performance
-(bandwidth and latency) than raw I/O streams.  Their API is also more usable.
+Buffered I/O streams provide a higher-level interface to an I/O device
+than raw I/O does.
 
 .. class:: BytesIO([initial_bytes])
 
@@ -784,14 +778,72 @@
       # .getvalue() will now raise an exception.
       output.close()
 
-   .. note::
-
-      :class:`StringIO` uses a native text storage and doesn't suffer from the
-      performance issues of other text streams, such as those based on
-      :class:`TextIOWrapper`.
 
 .. class:: IncrementalNewlineDecoder
 
    A helper codec that decodes newlines for universal newlines mode.  It
    inherits :class:`codecs.IncrementalDecoder`.
 
+
+Advanced topics
+---------------
+
+Here we will discuss several advanced topics pertaining to the concrete
+I/O implementations described above.
+
+Performance
+^^^^^^^^^^^
+
+Binary I/O
+""""""""""
+
+By reading and writing only large chunks of data even when the user asks
+for a single byte, buffered I/O is designed to hide any inefficiency in
+calling and executing the operating system's unbuffered I/O routines.  The
+gain will vary very much depending on the OS and the kind of I/O which is
+performed (for example, on some contemporary OSes such as Linux, unbuffered
+disk I/O can be as fast as buffered I/O).  The bottom line, however, is
+that buffered I/O will offer you predictable performance regardless of the
+platform and the backing device.  Therefore, it is most always preferable to
+use buffered I/O rather than unbuffered I/O.
+
+Text I/O
+""""""""
+
+Text I/O over a binary storage (such as a file) is significantly slower than
+binary I/O over the same storage, because it implies conversions from
+unicode to binary data using a character codec.  This can become noticeable
+if you handle huge amounts of text data (for example very large log files).
+
+:class:`StringIO`, however, is a native in-memory unicode container and will
+exhibit similar speed to :class:`BytesIO`.
+
+Multi-threading
+^^^^^^^^^^^^^^^
+
+:class:`FileIO` objects are thread-safe to the extent that the operating
+system calls (such as ``read(2)`` under Unix) they are wrapping are thread-safe
+too.
+
+Binary buffered objects (instances of :class:`BufferedReader`,
+:class:`BufferedWriter`, :class:`BufferedRandom` and :class:`BufferedRWPair`)
+protect their internal structures using a lock; it is therefore safe to call
+them from multiple threads at once.
+
+:class:`TextIOWrapper` objects are not thread-safe.
+
+Reentrancy
+^^^^^^^^^^
+
+Binary buffered objects (instances of :class:`BufferedReader`,
+:class:`BufferedWriter`, :class:`BufferedRandom` and :class:`BufferedRWPair`)
+are not reentrant.  While reentrant calls will not happen in normal situations,
+they can arise if you are doing I/O in a :mod:`signal` handler.  If it is
+attempted to enter a buffered object again while already being accessed
+*from the same thread*, then a :exc:`RuntimeError` is raised.
+
+The above implicitly extends to text files, since the :func:`open()`
+function will wrap a buffered object inside a :class:`TextIOWrapper`.  This
+includes standard streams and therefore affects the built-in function
+:func:`print()` as well.
+

Modified: python/branches/py3k-cdecimal/Doc/library/itertools.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/itertools.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/itertools.rst	Sun Jan  2 13:18:37 2011
@@ -46,6 +46,7 @@
 ====================    ============================    =================================================   =============================================================
 Iterator                Arguments                       Results                                             Example
 ====================    ============================    =================================================   =============================================================
+:func:`accumulate`      p                               p0, p0+p1, p0+p1+p2, ...                            ``accumulate([1,2,3,4,5]) --> 1 3 6 10 15``
 :func:`chain`           p, q, ...                       p0, p1, ... plast, q0, q1, ...                      ``chain('ABC', 'DEF') --> A B C D E F``
 :func:`compress`        data, selectors                 (d[0] if s[0]), (d[1] if s[1]), ...                 ``compress('ABCDEF', [1,0,1,0,1,1]) --> A C E F``
 :func:`dropwhile`       pred, seq                       seq[n], seq[n+1], starting when pred fails          ``dropwhile(lambda x: x<5, [1,4,6,4,1]) --> 6 4 1``
@@ -83,6 +84,22 @@
 streams of infinite length, so they should only be accessed by functions or
 loops that truncate the stream.
 
+.. function:: accumulate(iterable)
+
+    Make an iterator that returns accumulated sums. Elements may be any addable
+    type including :class:`Decimal` or :class:`Fraction`.  Equivalent to::
+
+        def accumulate(iterable):
+            'Return running totals'
+            # accumulate([1,2,3,4,5]) --> 1 3 6 10 15
+            it = iter(iterable)
+            total = next(it)
+            yield total
+            for element in it:
+                total = total + element
+                yield total
+
+    .. versionadded:: 3.2
 
 .. function:: chain(*iterables)
 
@@ -560,8 +577,8 @@
 
 .. _itertools-recipes:
 
-Recipes
--------
+Itertools Recipes
+-----------------
 
 This section shows recipes for creating an extended toolset using the existing
 itertools as building blocks.

Modified: python/branches/py3k-cdecimal/Doc/library/logging.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/logging.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/logging.rst	Sun Jan  2 13:18:37 2011
@@ -2,7 +2,7 @@
 ==============================================
 
 .. module:: logging
-   :synopsis: Flexible error logging system for applications.
+   :synopsis: Flexible event logging system for applications.
 
 
 .. moduleauthor:: Vinay Sajip 
@@ -11,748 +11,107 @@
 
 .. index:: pair: Errors; logging
 
-This module defines functions and classes which implement a flexible error
-logging system for applications.
+.. sidebar:: Important
 
-Logging is performed by calling methods on instances of the :class:`Logger`
-class (hereafter called :dfn:`loggers`). Each instance has a name, and they are
-conceptually arranged in a namespace hierarchy using dots (periods) as
-separators. For example, a logger named "scan" is the parent of loggers
-"scan.text", "scan.html" and "scan.pdf". Logger names can be anything you want,
-and indicate the area of an application in which a logged message originates.
-
-Logged messages also have levels of importance associated with them. The default
-levels provided are :const:`DEBUG`, :const:`INFO`, :const:`WARNING`,
-:const:`ERROR` and :const:`CRITICAL`. As a convenience, you indicate the
-importance of a logged message by calling an appropriate method of
-:class:`Logger`. The methods are :meth:`debug`, :meth:`info`, :meth:`warning`,
-:meth:`error` and :meth:`critical`, which mirror the default levels. You are not
-constrained to use these levels: you can specify your own and use a more general
-:class:`Logger` method, :meth:`log`, which takes an explicit level argument.
+   This page contains the API reference information. For tutorial
+   information and discussion of more advanced topics, see
 
+   * :ref:`Basic Tutorial `
+   * :ref:`Advanced Tutorial `
+   * :ref:`Logging Cookbook `
 
-Logging tutorial
-----------------
+
+This module defines functions and classes which implement a flexible event
+logging system for applications and libraries.
 
 The key benefit of having the logging API provided by a standard library module
 is that all Python modules can participate in logging, so your application log
-can include messages from third-party modules.
-
-It is, of course, possible to log messages with different verbosity levels or to
-different destinations.  Support for writing log messages to files, HTTP
-GET/POST locations, email via SMTP, generic sockets, or OS-specific logging
-mechanisms are all supported by the standard module.  You can also create your
-own log destination class if you have special requirements not met by any of the
-built-in classes.
-
-Simple examples
-^^^^^^^^^^^^^^^
-
-.. sectionauthor:: Doug Hellmann
-.. (see )
-
-Most applications are probably going to want to log to a file, so let's start
-with that case. Using the :func:`basicConfig` function, we can set up the
-default handler so that debug messages are written to a file (in the example,
-we assume that you have the appropriate permissions to create a file called
-*example.log* in the current directory)::
-
-   import logging
-   LOG_FILENAME = 'example.log'
-   logging.basicConfig(filename=LOG_FILENAME,level=logging.DEBUG)
-
-   logging.debug('This message should go to the log file')
-
-And now if we open the file and look at what we have, we should find the log
-message::
-
-   DEBUG:root:This message should go to the log file
-
-If you run the script repeatedly, the additional log messages are appended to
-the file.  To create a new file each time, you can pass a *filemode* argument to
-:func:`basicConfig` with a value of ``'w'``.  Rather than managing the file size
-yourself, though, it is simpler to use a :class:`RotatingFileHandler`::
-
-   import glob
-   import logging
-   import logging.handlers
-
-   LOG_FILENAME = 'logging_rotatingfile_example.out'
-
-   # Set up a specific logger with our desired output level
-   my_logger = logging.getLogger('MyLogger')
-   my_logger.setLevel(logging.DEBUG)
-
-   # Add the log message handler to the logger
-   handler = logging.handlers.RotatingFileHandler(
-                 LOG_FILENAME, maxBytes=20, backupCount=5)
-
-   my_logger.addHandler(handler)
-
-   # Log some messages
-   for i in range(20):
-       my_logger.debug('i = %d' % i)
-
-   # See what files are created
-   logfiles = glob.glob('%s*' % LOG_FILENAME)
-
-   for filename in logfiles:
-       print(filename)
-
-The result should be 6 separate files, each with part of the log history for the
-application::
-
-   logging_rotatingfile_example.out
-   logging_rotatingfile_example.out.1
-   logging_rotatingfile_example.out.2
-   logging_rotatingfile_example.out.3
-   logging_rotatingfile_example.out.4
-   logging_rotatingfile_example.out.5
-
-The most current file is always :file:`logging_rotatingfile_example.out`,
-and each time it reaches the size limit it is renamed with the suffix
-``.1``. Each of the existing backup files is renamed to increment the suffix
-(``.1`` becomes ``.2``, etc.)  and the ``.6`` file is erased.
-
-Obviously this example sets the log length much much too small as an extreme
-example.  You would want to set *maxBytes* to an appropriate value.
-
-Another useful feature of the logging API is the ability to produce different
-messages at different log levels.  This allows you to instrument your code with
-debug messages, for example, but turning the log level down so that those debug
-messages are not written for your production system.  The default levels are
-``NOTSET``, ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` and ``CRITICAL``.
-
-The logger, handler, and log message call each specify a level.  The log message
-is only emitted if the handler and logger are configured to emit messages of
-that level or lower.  For example, if a message is ``CRITICAL``, and the logger
-is set to ``ERROR``, the message is emitted.  If a message is a ``WARNING``, and
-the logger is set to produce only ``ERROR``\s, the message is not emitted::
-
-   import logging
-   import sys
-
-   LEVELS = {'debug': logging.DEBUG,
-             'info': logging.INFO,
-             'warning': logging.WARNING,
-             'error': logging.ERROR,
-             'critical': logging.CRITICAL}
-
-   if len(sys.argv) > 1:
-       level_name = sys.argv[1]
-       level = LEVELS.get(level_name, logging.NOTSET)
-       logging.basicConfig(level=level)
-
-   logging.debug('This is a debug message')
-   logging.info('This is an info message')
-   logging.warning('This is a warning message')
-   logging.error('This is an error message')
-   logging.critical('This is a critical error message')
-
-Run the script with an argument like 'debug' or 'warning' to see which messages
-show up at different levels::
-
-   $ python logging_level_example.py debug
-   DEBUG:root:This is a debug message
-   INFO:root:This is an info message
-   WARNING:root:This is a warning message
-   ERROR:root:This is an error message
-   CRITICAL:root:This is a critical error message
-
-   $ python logging_level_example.py info
-   INFO:root:This is an info message
-   WARNING:root:This is a warning message
-   ERROR:root:This is an error message
-   CRITICAL:root:This is a critical error message
-
-You will notice that these log messages all have ``root`` embedded in them.  The
-logging module supports a hierarchy of loggers with different names.  An easy
-way to tell where a specific log message comes from is to use a separate logger
-object for each of your modules.  Each new logger "inherits" the configuration
-of its parent, and log messages sent to a logger include the name of that
-logger.  Optionally, each logger can be configured differently, so that messages
-from different modules are handled in different ways.  Let's look at a simple
-example of how to log from different modules so it is easy to trace the source
-of the message::
-
-   import logging
-
-   logging.basicConfig(level=logging.WARNING)
-
-   logger1 = logging.getLogger('package1.module1')
-   logger2 = logging.getLogger('package2.module2')
-
-   logger1.warning('This message comes from one module')
-   logger2.warning('And this message comes from another module')
-
-And the output::
-
-   $ python logging_modules_example.py
-   WARNING:package1.module1:This message comes from one module
-   WARNING:package2.module2:And this message comes from another module
-
-There are many more options for configuring logging, including different log
-message formatting options, having messages delivered to multiple destinations,
-and changing the configuration of a long-running application on the fly using a
-socket interface.  All of these options are covered in depth in the library
-module documentation.
-
-Loggers
-^^^^^^^
-
-The logging library takes a modular approach and offers the several categories
-of components: loggers, handlers, filters, and formatters.  Loggers expose the
-interface that application code directly uses.  Handlers send the log records to
-the appropriate destination. Filters provide a finer grained facility for
-determining which log records to send on to a handler.  Formatters specify the
-layout of the resultant log record.
-
-:class:`Logger` objects have a threefold job.  First, they expose several
-methods to application code so that applications can log messages at runtime.
-Second, logger objects determine which log messages to act upon based upon
-severity (the default filtering facility) or filter objects.  Third, logger
-objects pass along relevant log messages to all interested log handlers.
-
-The most widely used methods on logger objects fall into two categories:
-configuration and message sending.
-
-* :meth:`Logger.setLevel` specifies the lowest-severity log message a logger
-  will handle, where debug is the lowest built-in severity level and critical is
-  the highest built-in severity.  For example, if the severity level is info,
-  the logger will handle only info, warning, error, and critical messages and
-  will ignore debug messages.
-
-* :meth:`Logger.addFilter` and :meth:`Logger.removeFilter` add and remove filter
-  objects from the logger object.  This tutorial does not address filters.
-
-With the logger object configured, the following methods create log messages:
-
-* :meth:`Logger.debug`, :meth:`Logger.info`, :meth:`Logger.warning`,
-  :meth:`Logger.error`, and :meth:`Logger.critical` all create log records with
-  a message and a level that corresponds to their respective method names. The
-  message is actually a format string, which may contain the standard string
-  substitution syntax of :const:`%s`, :const:`%d`, :const:`%f`, and so on.  The
-  rest of their arguments is a list of objects that correspond with the
-  substitution fields in the message.  With regard to :const:`**kwargs`, the
-  logging methods care only about a keyword of :const:`exc_info` and use it to
-  determine whether to log exception information.
-
-* :meth:`Logger.exception` creates a log message similar to
-  :meth:`Logger.error`.  The difference is that :meth:`Logger.exception` dumps a
-  stack trace along with it.  Call this method only from an exception handler.
-
-* :meth:`Logger.log` takes a log level as an explicit argument.  This is a
-  little more verbose for logging messages than using the log level convenience
-  methods listed above, but this is how to log at custom log levels.
-
-:func:`getLogger` returns a reference to a logger instance with the specified
-name if it is provided, or ``root`` if not.  The names are period-separated
-hierarchical structures.  Multiple calls to :func:`getLogger` with the same name
-will return a reference to the same logger object.  Loggers that are further
-down in the hierarchical list are children of loggers higher up in the list.
-For example, given a logger with a name of ``foo``, loggers with names of
-``foo.bar``, ``foo.bar.baz``, and ``foo.bam`` are all descendants of ``foo``.
-Child loggers propagate messages up to the handlers associated with their
-ancestor loggers.  Because of this, it is unnecessary to define and configure
-handlers for all the loggers an application uses. It is sufficient to
-configure handlers for a top-level logger and create child loggers as needed.
-
-
-Handlers
-^^^^^^^^
-
-:class:`Handler` objects are responsible for dispatching the appropriate log
-messages (based on the log messages' severity) to the handler's specified
-destination.  Logger objects can add zero or more handler objects to themselves
-with an :func:`addHandler` method.  As an example scenario, an application may
-want to send all log messages to a log file, all log messages of error or higher
-to stdout, and all messages of critical to an email address.  This scenario
-requires three individual handlers where each handler is responsible for sending
-messages of a specific severity to a specific location.
-
-The standard library includes quite a few handler types; this tutorial uses only
-:class:`StreamHandler` and :class:`FileHandler` in its examples.
-
-There are very few methods in a handler for application developers to concern
-themselves with.  The only handler methods that seem relevant for application
-developers who are using the built-in handler objects (that is, not creating
-custom handlers) are the following configuration methods:
-
-* The :meth:`Handler.setLevel` method, just as in logger objects, specifies the
-  lowest severity that will be dispatched to the appropriate destination.  Why
-  are there two :func:`setLevel` methods?  The level set in the logger
-  determines which severity of messages it will pass to its handlers.  The level
-  set in each handler determines which messages that handler will send on.
-
-* :func:`setFormatter` selects a Formatter object for this handler to use.
-
-* :func:`addFilter` and :func:`removeFilter` respectively configure and
-  deconfigure filter objects on handlers.
-
-Application code should not directly instantiate and use instances of
-:class:`Handler`.  Instead, the :class:`Handler` class is a base class that
-defines the interface that all handlers should have and establishes some
-default behavior that child classes can use (or override).
-
-
-Formatters
-^^^^^^^^^^
-
-Formatter objects configure the final order, structure, and contents of the log
-message.  Unlike the base :class:`logging.Handler` class, application code may
-instantiate formatter classes, although you could likely subclass the formatter
-if your application needs special behavior.  The constructor takes three
-optional arguments -- a message format string, a date format string and a style
-indicator.
-
-.. method:: logging.Formatter.__init__(fmt=None, datefmt=None, style='%')
-
-If there is no message format string, the default is to use the
-raw message.  If there is no date format string, the default date format is::
-
-    %Y-%m-%d %H:%M:%S
-
-with the milliseconds tacked on at the end. The ``style`` is one of `%`, '{'
-or '$'. If one of these is not specified, then '%' will be used.
-
-If the ``style`` is '%', the message format string uses
-``%()s`` styled string substitution; the possible keys are
-documented in :ref:`formatter-objects`. If the style is '{', the message format
-string is assumed to be compatible with :meth:`str.format` (using keyword
-arguments), while if the style is '$' then the message format string should
-conform to what is expected by :meth:`string.Template.substitute`.
-
-.. versionchanged:: 3.2
-   Added the ``style`` parameter.
+can include your own messages integrated with messages from third-party
+modules.
 
-The following message format string will log the time in a human-readable
-format, the severity of the message, and the contents of the message, in that
-order::
-
-    "%(asctime)s - %(levelname)s - %(message)s"
-
-Formatters use a user-configurable function to convert the creation time of a
-record to a tuple. By default, :func:`time.localtime` is used; to change this
-for a particular formatter instance, set the ``converter`` attribute of the
-instance to a function with the same signature as :func:`time.localtime` or
-:func:`time.gmtime`. To change it for all formatters, for example if you want
-all logging times to be shown in GMT, set the ``converter`` attribute in the
-Formatter class (to ``time.gmtime`` for GMT display).
-
-
-Configuring Logging
-^^^^^^^^^^^^^^^^^^^
-
-Programmers can configure logging in three ways:
-
-1. Creating loggers, handlers, and formatters explicitly using Python
-   code that calls the configuration methods listed above.
-2. Creating a logging config file and reading it using the :func:`fileConfig`
-   function.
-3. Creating a dictionary of configuration information and passing it
-   to the :func:`dictConfig` function.
-
-The following example configures a very simple logger, a console
-handler, and a simple formatter using Python code::
-
-    import logging
-
-    # create logger
-    logger = logging.getLogger("simple_example")
-    logger.setLevel(logging.DEBUG)
-
-    # create console handler and set level to debug
-    ch = logging.StreamHandler()
-    ch.setLevel(logging.DEBUG)
-
-    # create formatter
-    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
-
-    # add formatter to ch
-    ch.setFormatter(formatter)
-
-    # add ch to logger
-    logger.addHandler(ch)
-
-    # "application" code
-    logger.debug("debug message")
-    logger.info("info message")
-    logger.warn("warn message")
-    logger.error("error message")
-    logger.critical("critical message")
-
-Running this module from the command line produces the following output::
-
-    $ python simple_logging_module.py
-    2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message
-    2005-03-19 15:10:26,620 - simple_example - INFO - info message
-    2005-03-19 15:10:26,695 - simple_example - WARNING - warn message
-    2005-03-19 15:10:26,697 - simple_example - ERROR - error message
-    2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message
-
-The following Python module creates a logger, handler, and formatter nearly
-identical to those in the example listed above, with the only difference being
-the names of the objects::
-
-    import logging
-    import logging.config
-
-    logging.config.fileConfig("logging.conf")
-
-    # create logger
-    logger = logging.getLogger("simpleExample")
-
-    # "application" code
-    logger.debug("debug message")
-    logger.info("info message")
-    logger.warn("warn message")
-    logger.error("error message")
-    logger.critical("critical message")
-
-Here is the logging.conf file::
-
-    [loggers]
-    keys=root,simpleExample
-
-    [handlers]
-    keys=consoleHandler
-
-    [formatters]
-    keys=simpleFormatter
-
-    [logger_root]
-    level=DEBUG
-    handlers=consoleHandler
-
-    [logger_simpleExample]
-    level=DEBUG
-    handlers=consoleHandler
-    qualname=simpleExample
-    propagate=0
-
-    [handler_consoleHandler]
-    class=StreamHandler
-    level=DEBUG
-    formatter=simpleFormatter
-    args=(sys.stdout,)
-
-    [formatter_simpleFormatter]
-    format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
-    datefmt=
-
-The output is nearly identical to that of the non-config-file-based example::
-
-    $ python simple_logging_config.py
-    2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message
-    2005-03-19 15:38:55,979 - simpleExample - INFO - info message
-    2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message
-    2005-03-19 15:38:56,055 - simpleExample - ERROR - error message
-    2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message
-
-You can see that the config file approach has a few advantages over the Python
-code approach, mainly separation of configuration and code and the ability of
-noncoders to easily modify the logging properties.
-
-Note that the class names referenced in config files need to be either relative
-to the logging module, or absolute values which can be resolved using normal
-import mechanisms. Thus, you could use either
-:class:`handlers.WatchedFileHandler` (relative to the logging module) or
-``mypackage.mymodule.MyHandler`` (for a class defined in package ``mypackage``
-and module ``mymodule``, where ``mypackage`` is available on the Python import
-path).
-
-In Python 3.2, a new means of configuring logging has been introduced, using
-dictionaries to hold configuration information. This provides a superset of the
-functionality of the config-file-based approach outlined above, and is the
-recommended configuration method for new applications and deployments. Because
-a Python dictionary is used to hold configuration information, and since you
-can populate that dictionary using different means, you have more options for
-configuration. For example, you can use a configuration file in JSON format,
-or, if you have access to YAML processing functionality, a file in YAML
-format, to populate the configuration dictionary. Or, of course, you can
-construct the dictionary in Python code, receive it in pickled form over a
-socket, or use whatever approach makes sense for your application.
-
-Here's an example of the same configuration as above, in YAML format for
-the new dictionary-based approach::
-
-    version: 1
-    formatters:
-      simple:
-        format: format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
-    handlers:
-      console:
-        class: logging.StreamHandler
-        level: DEBUG
-        formatter: simple
-        stream: ext://sys.stdout
-    loggers:
-      simpleExample:
-        level: DEBUG
-        handlers: [console]
-        propagate: no
-    root:
-        level: DEBUG
-        handlers: [console]
-
-For more information about logging using a dictionary, see
-:ref:`logging-config-api`.
-
-.. _library-config:
-
-Configuring Logging for a Library
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-When developing a library which uses logging, some consideration needs to be
-given to its configuration. If the using application does not use logging, and
-library code makes logging calls, then a one-off message "No handlers could be
-found for logger X.Y.Z" is printed to the console. This message is intended
-to catch mistakes in logging configuration, but will confuse an application
-developer who is not aware of logging by the library.
-
-In addition to documenting how a library uses logging, a good way to configure
-library logging so that it does not cause a spurious message is to add a
-handler which does nothing. This avoids the message being printed, since a
-handler will be found: it just doesn't produce any output. If the library user
-configures logging for application use, presumably that configuration will add
-some handlers, and if levels are suitably configured then logging calls made
-in library code will send output to those handlers, as normal.
-
-A do-nothing handler can be simply defined as follows::
-
-    import logging
-
-    class NullHandler(logging.Handler):
-        def emit(self, record):
-            pass
-
-An instance of this handler should be added to the top-level logger of the
-logging namespace used by the library. If all logging by a library *foo* is
-done using loggers with names matching "foo.x.y", then the code::
-
-    import logging
-
-    h = NullHandler()
-    logging.getLogger("foo").addHandler(h)
-
-should have the desired effect. If an organisation produces a number of
-libraries, then the logger name specified can be "orgname.foo" rather than
-just "foo".
-
-**PLEASE NOTE:** It is strongly advised that you *do not add any handlers other
-than* :class:`NullHandler` *to your library's loggers*. This is because the
-configuration of handlers is the prerogative of the application developer who
-uses your library. The application developer knows their target audience and
-what handlers are most appropriate for their application: if you add handlers
-"under the hood", you might well interfere with their ability to carry out
-unit tests and deliver logs which suit their requirements.
-
-.. versionadded:: 3.1
-
-The :class:`NullHandler` class was not present in previous versions, but is
-now included, so that it need not be defined in library code.
+The module provides a lot of functionality and flexibility.  If you are
+unfamiliar with logging, the best way to get to grips with it is to see the
+tutorials (see the links on the right).
+
+The basic classes defined by the module, together with their functions, are
+listed below.
+
+* Loggers expose the interface that application code directly uses.
+* Handlers send the log records (created by loggers) to the appropriate
+  destination.
+* Filters provide a finer grained facility for determining which log records
+  to output.
+* Formatters specify the layout of log records in the final output.
 
 
+.. _logger:
 
-Logging Levels
+Logger Objects
 --------------
 
-The numeric values of logging levels are given in the following table. These are
-primarily of interest if you want to define your own levels, and need them to
-have specific values relative to the predefined levels. If you define a level
-with the same numeric value, it overwrites the predefined value; the predefined
-name is lost.
-
-+--------------+---------------+
-| Level        | Numeric value |
-+==============+===============+
-| ``CRITICAL`` | 50            |
-+--------------+---------------+
-| ``ERROR``    | 40            |
-+--------------+---------------+
-| ``WARNING``  | 30            |
-+--------------+---------------+
-| ``INFO``     | 20            |
-+--------------+---------------+
-| ``DEBUG``    | 10            |
-+--------------+---------------+
-| ``NOTSET``   | 0             |
-+--------------+---------------+
-
-Levels can also be associated with loggers, being set either by the developer or
-through loading a saved logging configuration. When a logging method is called
-on a logger, the logger compares its own level with the level associated with
-the method call. If the logger's level is higher than the method call's, no
-logging message is actually generated. This is the basic mechanism controlling
-the verbosity of logging output.
-
-Logging messages are encoded as instances of the :class:`LogRecord` class. When
-a logger decides to actually log an event, a :class:`LogRecord` instance is
-created from the logging message.
-
-Logging messages are subjected to a dispatch mechanism through the use of
-:dfn:`handlers`, which are instances of subclasses of the :class:`Handler`
-class. Handlers are responsible for ensuring that a logged message (in the form
-of a :class:`LogRecord`) ends up in a particular location (or set of locations)
-which is useful for the target audience for that message (such as end users,
-support desk staff, system administrators, developers). Handlers are passed
-:class:`LogRecord` instances intended for particular destinations. Each logger
-can have zero, one or more handlers associated with it (via the
-:meth:`addHandler` method of :class:`Logger`). In addition to any handlers
-directly associated with a logger, *all handlers associated with all ancestors
-of the logger* are called to dispatch the message (unless the *propagate* flag
-for a logger is set to a false value, at which point the passing to ancestor
-handlers stops).
-
-Just as for loggers, handlers can have levels associated with them. A handler's
-level acts as a filter in the same way as a logger's level does. If a handler
-decides to actually dispatch an event, the :meth:`emit` method is used to send
-the message to its destination. Most user-defined subclasses of :class:`Handler`
-will need to override this :meth:`emit`.
-
-.. _custom-levels:
-
-Custom Levels
-^^^^^^^^^^^^^
-
-Defining your own levels is possible, but should not be necessary, as the
-existing levels have been chosen on the basis of practical experience.
-However, if you are convinced that you need custom levels, great care should
-be exercised when doing this, and it is possibly *a very bad idea to define
-custom levels if you are developing a library*. That's because if multiple
-library authors all define their own custom levels, there is a chance that
-the logging output from such multiple libraries used together will be
-difficult for the using developer to control and/or interpret, because a
-given numeric value might mean different things for different libraries.
-
-
-Useful Handlers
----------------
-
-In addition to the base :class:`Handler` class, many useful subclasses are
-provided:
-
-#. :class:`StreamHandler` instances send messages to streams (file-like
-   objects).
-
-#. :class:`FileHandler` instances send messages to disk files.
-
-.. module:: logging.handlers
-
-#. :class:`BaseRotatingHandler` is the base class for handlers that
-   rotate log files at a certain point. It is not meant to be  instantiated
-   directly. Instead, use :class:`RotatingFileHandler` or
-   :class:`TimedRotatingFileHandler`.
-
-#. :class:`RotatingFileHandler` instances send messages to disk
-   files, with support for maximum log file sizes and log file rotation.
-
-#. :class:`TimedRotatingFileHandler` instances send messages to
-   disk files, rotating the log file at certain timed intervals.
-
-#. :class:`SocketHandler` instances send messages to TCP/IP
-   sockets.
-
-#. :class:`DatagramHandler` instances send messages to UDP
-   sockets.
+Loggers have the following attributes and methods. Note that Loggers are never
+instantiated directly, but always through the module-level function
+``logging.getLogger(name)``.
 
-#. :class:`SMTPHandler` instances send messages to a designated
-   email address.
+.. class:: Logger
 
-#. :class:`SysLogHandler` instances send messages to a Unix
-   syslog daemon, possibly on a remote machine.
+.. attribute:: Logger.propagate
 
-#. :class:`NTEventLogHandler` instances send messages to a
-   Windows NT/2000/XP event log.
+   If this evaluates to false, logging messages are not passed by this logger or by
+   its child loggers to the handlers of higher level (ancestor) loggers. The
+   constructor sets this attribute to 1.
 
-#. :class:`MemoryHandler` instances send messages to a buffer
-   in memory, which is flushed whenever specific criteria are met.
 
-#. :class:`HTTPHandler` instances send messages to an HTTP
-   server using either ``GET`` or ``POST`` semantics.
+.. method:: Logger.setLevel(lvl)
 
-#. :class:`WatchedFileHandler` instances watch the file they are
-   logging to. If the file changes, it is closed and reopened using the file
-   name. This handler is only useful on Unix-like systems; Windows does not
-   support the underlying mechanism used.
+   Sets the threshold for this logger to *lvl*. Logging messages which are less
+   severe than *lvl* will be ignored. When a logger is created, the level is set to
+   :const:`NOTSET` (which causes all messages to be processed when the logger is
+   the root logger, or delegation to the parent when the logger is a non-root
+   logger). Note that the root logger is created with level :const:`WARNING`.
 
-#. :class:`QueueHandler` instances send messages to a queue, such as
-   those implemented in the :mod:`queue` or :mod:`multiprocessing` modules.
+   The term 'delegation to the parent' means that if a logger has a level of
+   NOTSET, its chain of ancestor loggers is traversed until either an ancestor with
+   a level other than NOTSET is found, or the root is reached.
 
-.. currentmodule:: logging
+   If an ancestor is found with a level other than NOTSET, then that ancestor's
+   level is treated as the effective level of the logger where the ancestor search
+   began, and is used to determine how a logging event is handled.
 
-#. :class:`NullHandler` instances do nothing with error messages. They are used
-   by library developers who want to use logging, but want to avoid the "No
-   handlers could be found for logger XXX" message which can be displayed if
-   the library user has not configured logging. See :ref:`library-config` for
-   more information.
-
-.. versionadded:: 3.1
-
-The :class:`NullHandler` class was not present in previous versions.
-
-.. versionadded:: 3.2
-
-The :class:`QueueHandler` class was not present in previous versions.
-
-The :class:`NullHandler`, :class:`StreamHandler` and :class:`FileHandler`
-classes are defined in the core logging package. The other handlers are
-defined in a sub- module, :mod:`logging.handlers`. (There is also another
-sub-module, :mod:`logging.config`, for configuration functionality.)
-
-Logged messages are formatted for presentation through instances of the
-:class:`Formatter` class. They are initialized with a format string suitable for
-use with the % operator and a dictionary.
-
-For formatting multiple messages in a batch, instances of
-:class:`BufferingFormatter` can be used. In addition to the format string (which
-is applied to each message in the batch), there is provision for header and
-trailer format strings.
-
-When filtering based on logger level and/or handler level is not enough,
-instances of :class:`Filter` can be added to both :class:`Logger` and
-:class:`Handler` instances (through their :meth:`addFilter` method). Before
-deciding to process a message further, both loggers and handlers consult all
-their filters for permission. If any filter returns a false value, the message
-is not processed further.
-
-The basic :class:`Filter` functionality allows filtering by specific logger
-name. If this feature is used, messages sent to the named logger and its
-children are allowed through the filter, and all others dropped.
+   If the root is reached, and it has a level of NOTSET, then all messages will be
+   processed. Otherwise, the root's level will be used as the effective level.
 
-Module-Level Functions
-----------------------
 
-In addition to the classes described above, there are a number of module- level
-functions.
+.. method:: Logger.isEnabledFor(lvl)
 
+   Indicates if a message of severity *lvl* would be processed by this logger.
+   This method checks first the module-level level set by
+   ``logging.disable(lvl)`` and then the logger's effective level as determined
+   by :meth:`getEffectiveLevel`.
 
-.. function:: getLogger(name=None)
 
-   Return a logger with the specified name or, if name is ``None``, return a
-   logger which is the root logger of the hierarchy. If specified, the name is
-   typically a dot-separated hierarchical name like *"a"*, *"a.b"* or *"a.b.c.d"*.
-   Choice of these names is entirely up to the developer who is using logging.
+.. method:: Logger.getEffectiveLevel()
 
-   All calls to this function with a given name return the same logger instance.
-   This means that logger instances never need to be passed between different parts
-   of an application.
+   Indicates the effective level for this logger. If a value other than
+   :const:`NOTSET` has been set using :meth:`setLevel`, it is returned. Otherwise,
+   the hierarchy is traversed towards the root until a value other than
+   :const:`NOTSET` is found, and that value is returned.
 
 
-.. function:: getLoggerClass()
+.. method:: Logger.getChild(suffix)
 
-   Return either the standard :class:`Logger` class, or the last class passed to
-   :func:`setLoggerClass`. This function may be called from within a new class
-   definition, to ensure that installing a customised :class:`Logger` class will
-   not undo customisations already applied by other code. For example::
+   Returns a logger which is a descendant to this logger, as determined by the suffix.
+   Thus, ``logging.getLogger('abc').getChild('def.ghi')`` would return the same
+   logger as would be returned by ``logging.getLogger('abc.def.ghi')``. This is a
+   convenience method, useful when the parent logger is named using e.g. ``__name__``
+   rather than a literal string.
 
-      class MyLogger(logging.getLoggerClass()):
-          # ... override behaviour here
+   .. versionadded:: 3.2
 
 
-.. function:: debug(msg, *args, **kwargs)
+.. method:: Logger.debug(msg, *args, **kwargs)
 
-   Logs a message with level :const:`DEBUG` on the root logger. The *msg* is the
+   Logs a message with level :const:`DEBUG` on this logger. The *msg* is the
    message format string, and the *args* are the arguments which are merged into
    *msg* using the string formatting operator. (Note that this means that you can
    use keywords in the format string, together with a single dictionary argument.)
@@ -781,18 +140,19 @@
    This mimics the `Traceback (most recent call last):` which is used when
    displaying exception frames.
 
-   The third optional keyword argument is *extra* which can be used to pass a
+   The third keyword argument is *extra* which can be used to pass a
    dictionary which is used to populate the __dict__ of the LogRecord created for
    the logging event with user-defined attributes. These custom attributes can then
    be used as you like. For example, they could be incorporated into logged
    messages. For example::
 
-      FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s"
+      FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
       logging.basicConfig(format=FORMAT)
-      d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
-      logging.warning("Protocol problem: %s", "connection reset", extra=d)
+      d = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' }
+      logger = logging.getLogger('tcpserver')
+      logger.warning('Protocol problem: %s', 'connection reset', extra=d)
 
-   would print something like::
+   would print something like  ::
 
       2006-02-08 22:20:02,165 192.168.0.1 fbloggs  Protocol problem: connection reset
 
@@ -817,1211 +177,101 @@
    .. versionadded:: 3.2
       The *stack_info* parameter was added.
 
-.. function:: info(msg, *args, **kwargs)
 
-   Logs a message with level :const:`INFO` on the root logger. The arguments are
-   interpreted as for :func:`debug`.
+.. method:: Logger.info(msg, *args, **kwargs)
 
+   Logs a message with level :const:`INFO` on this logger. The arguments are
+   interpreted as for :meth:`debug`.
 
-.. function:: warning(msg, *args, **kwargs)
 
-   Logs a message with level :const:`WARNING` on the root logger. The arguments are
-   interpreted as for :func:`debug`.
+.. method:: Logger.warning(msg, *args, **kwargs)
 
+   Logs a message with level :const:`WARNING` on this logger. The arguments are
+   interpreted as for :meth:`debug`.
 
-.. function:: error(msg, *args, **kwargs)
 
-   Logs a message with level :const:`ERROR` on the root logger. The arguments are
-   interpreted as for :func:`debug`.
+.. method:: Logger.error(msg, *args, **kwargs)
 
+   Logs a message with level :const:`ERROR` on this logger. The arguments are
+   interpreted as for :meth:`debug`.
 
-.. function:: critical(msg, *args, **kwargs)
 
-   Logs a message with level :const:`CRITICAL` on the root logger. The arguments
-   are interpreted as for :func:`debug`.
+.. method:: Logger.critical(msg, *args, **kwargs)
 
+   Logs a message with level :const:`CRITICAL` on this logger. The arguments are
+   interpreted as for :meth:`debug`.
 
-.. function:: exception(msg, *args)
 
-   Logs a message with level :const:`ERROR` on the root logger. The arguments are
-   interpreted as for :func:`debug`. Exception info is added to the logging
-   message. This function should only be called from an exception handler.
+.. method:: Logger.log(lvl, msg, *args, **kwargs)
 
-.. function:: log(level, msg, *args, **kwargs)
+   Logs a message with integer level *lvl* on this logger. The other arguments are
+   interpreted as for :meth:`debug`.
 
-   Logs a message with level *level* on the root logger. The other arguments are
-   interpreted as for :func:`debug`.
 
-   PLEASE NOTE: The above module-level functions which delegate to the root
-   logger should *not* be used in threads, in versions of Python earlier than
-   2.7.1 and 3.2, unless at least one handler has been added to the root
-   logger *before* the threads are started. These convenience functions call
-   :func:`basicConfig` to ensure that at least one handler is available; in
-   earlier versions of Python, this can (under rare circumstances) lead to
-   handlers being added multiple times to the root logger, which can in turn
-   lead to multiple messages for the same event.
+.. method:: Logger.exception(msg, *args)
 
-.. function:: disable(lvl)
+   Logs a message with level :const:`ERROR` on this logger. The arguments are
+   interpreted as for :meth:`debug`. Exception info is added to the logging
+   message. This method should only be called from an exception handler.
 
-   Provides an overriding level *lvl* for all loggers which takes precedence over
-   the logger's own level. When the need arises to temporarily throttle logging
-   output down across the whole application, this function can be useful. Its
-   effect is to disable all logging calls of severity *lvl* and below, so that
-   if you call it with a value of INFO, then all INFO and DEBUG events would be
-   discarded, whereas those of severity WARNING and above would be processed
-   according to the logger's effective level.
 
+.. method:: Logger.addFilter(filt)
 
-.. function:: addLevelName(lvl, levelName)
+   Adds the specified filter *filt* to this logger.
 
-   Associates level *lvl* with text *levelName* in an internal dictionary, which is
-   used to map numeric levels to a textual representation, for example when a
-   :class:`Formatter` formats a message. This function can also be used to define
-   your own levels. The only constraints are that all levels used must be
-   registered using this function, levels should be positive integers and they
-   should increase in increasing order of severity.
 
-   NOTE: If you are thinking of defining your own levels, please see the section
-   on :ref:`custom-levels`.
+.. method:: Logger.removeFilter(filt)
 
-.. function:: getLevelName(lvl)
+   Removes the specified filter *filt* from this logger.
 
-   Returns the textual representation of logging level *lvl*. If the level is one
-   of the predefined levels :const:`CRITICAL`, :const:`ERROR`, :const:`WARNING`,
-   :const:`INFO` or :const:`DEBUG` then you get the corresponding string. If you
-   have associated levels with names using :func:`addLevelName` then the name you
-   have associated with *lvl* is returned. If a numeric value corresponding to one
-   of the defined levels is passed in, the corresponding string representation is
-   returned. Otherwise, the string "Level %s" % lvl is returned.
 
+.. method:: Logger.filter(record)
 
-.. function:: makeLogRecord(attrdict)
+   Applies this logger's filters to the record and returns a true value if the
+   record is to be processed.
 
-   Creates and returns a new :class:`LogRecord` instance whose attributes are
-   defined by *attrdict*. This function is useful for taking a pickled
-   :class:`LogRecord` attribute dictionary, sent over a socket, and reconstituting
-   it as a :class:`LogRecord` instance at the receiving end.
 
+.. method:: Logger.addHandler(hdlr)
 
-.. function:: basicConfig(**kwargs)
+   Adds the specified handler *hdlr* to this logger.
 
-   Does basic configuration for the logging system by creating a
-   :class:`StreamHandler` with a default :class:`Formatter` and adding it to the
-   root logger. The functions :func:`debug`, :func:`info`, :func:`warning`,
-   :func:`error` and :func:`critical` will call :func:`basicConfig` automatically
-   if no handlers are defined for the root logger.
 
-   This function does nothing if the root logger already has handlers
-   configured for it.
+.. method:: Logger.removeHandler(hdlr)
 
-   PLEASE NOTE: This function should be called from the main thread
-   before other threads are started. In versions of Python prior to
-   2.7.1 and 3.2, if this function is called from multiple threads,
-   it is possible (in rare circumstances) that a handler will be added
-   to the root logger more than once, leading to unexpected results
-   such as messages being duplicated in the log.
+   Removes the specified handler *hdlr* from this logger.
 
-   The following keyword arguments are supported.
 
-   +--------------+---------------------------------------------+
-   | Format       | Description                                 |
-   +==============+=============================================+
-   | ``filename`` | Specifies that a FileHandler be created,    |
-   |              | using the specified filename, rather than a |
-   |              | StreamHandler.                              |
-   +--------------+---------------------------------------------+
-   | ``filemode`` | Specifies the mode to open the file, if     |
-   |              | filename is specified (if filemode is       |
-   |              | unspecified, it defaults to 'a').           |
-   +--------------+---------------------------------------------+
-   | ``format``   | Use the specified format string for the     |
-   |              | handler.                                    |
-   +--------------+---------------------------------------------+
-   | ``datefmt``  | Use the specified date/time format.         |
-   +--------------+---------------------------------------------+
-   | ``style``    | If ``format`` is specified, use this style  |
-   |              | for the format string. One of '%', '{' or   |
-   |              | '$' for %-formatting, :meth:`str.format` or |
-   |              | :class:`string.Template` respectively, and  |
-   |              | defaulting to '%' if not specified.         |
-   +--------------+---------------------------------------------+
-   | ``level``    | Set the root logger level to the specified  |
-   |              | level.                                      |
-   +--------------+---------------------------------------------+
-   | ``stream``   | Use the specified stream to initialize the  |
-   |              | StreamHandler. Note that this argument is   |
-   |              | incompatible with 'filename' - if both are  |
-   |              | present, 'stream' is ignored.               |
-   +--------------+---------------------------------------------+
+.. method:: Logger.findCaller(stack_info=False)
 
-   .. versionchanged:: 3.2
-      The ``style`` argument was added.
+   Finds the caller's source filename and line number. Returns the filename, line
+   number, function name and stack information as a 4-element tuple. The stack
+   information is returned as *None* unless *stack_info* is *True*.
 
 
-.. function:: shutdown()
+.. method:: Logger.handle(record)
 
-   Informs the logging system to perform an orderly shutdown by flushing and
-   closing all handlers. This should be called at application exit and no
-   further use of the logging system should be made after this call.
+   Handles a record by passing it to all handlers associated with this logger and
+   its ancestors (until a false value of *propagate* is found). This method is used
+   for unpickled records received from a socket, as well as those created locally.
+   Logger-level filtering is applied using :meth:`~Logger.filter`.
 
 
-.. function:: setLoggerClass(klass)
+.. method:: Logger.makeRecord(name, lvl, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None)
 
-   Tells the logging system to use the class *klass* when instantiating a logger.
-   The class should define :meth:`__init__` such that only a name argument is
-   required, and the :meth:`__init__` should call :meth:`Logger.__init__`. This
-   function is typically called before any loggers are instantiated by applications
-   which need to use custom logger behavior.
+   This is a factory method which can be overridden in subclasses to create
+   specialized :class:`LogRecord` instances.
 
+.. method:: Logger.hasHandlers()
 
-.. seealso::
+   Checks to see if this logger has any handlers configured. This is done by
+   looking for handlers in this logger and its parents in the logger hierarchy.
+   Returns True if a handler was found, else False. The method stops searching
+   up the hierarchy whenever a logger with the 'propagate' attribute set to
+   False is found - that will be the last logger which is checked for the
+   existence of handlers.
 
-   :pep:`282` - A Logging System
-      The proposal which described this feature for inclusion in the Python standard
-      library.
+   .. versionadded:: 3.2
 
-   `Original Python logging package `_
-      This is the original source for the :mod:`logging` package.  The version of the
-      package available from this site is suitable for use with Python 1.5.2, 2.1.x
-      and 2.2.x, which do not include the :mod:`logging` package in the standard
-      library.
-
-.. _logger:
-
-Logger Objects
---------------
-
-Loggers have the following attributes and methods. Note that Loggers are never
-instantiated directly, but always through the module-level function
-``logging.getLogger(name)``.
-
-.. class:: Logger
-
-.. attribute:: Logger.propagate
-
-   If this evaluates to false, logging messages are not passed by this logger or by
-   its child loggers to the handlers of higher level (ancestor) loggers. The
-   constructor sets this attribute to 1.
-
-
-.. method:: Logger.setLevel(lvl)
-
-   Sets the threshold for this logger to *lvl*. Logging messages which are less
-   severe than *lvl* will be ignored. When a logger is created, the level is set to
-   :const:`NOTSET` (which causes all messages to be processed when the logger is
-   the root logger, or delegation to the parent when the logger is a non-root
-   logger). Note that the root logger is created with level :const:`WARNING`.
-
-   The term "delegation to the parent" means that if a logger has a level of
-   NOTSET, its chain of ancestor loggers is traversed until either an ancestor with
-   a level other than NOTSET is found, or the root is reached.
-
-   If an ancestor is found with a level other than NOTSET, then that ancestor's
-   level is treated as the effective level of the logger where the ancestor search
-   began, and is used to determine how a logging event is handled.
-
-   If the root is reached, and it has a level of NOTSET, then all messages will be
-   processed. Otherwise, the root's level will be used as the effective level.
-
-
-.. method:: Logger.isEnabledFor(lvl)
-
-   Indicates if a message of severity *lvl* would be processed by this logger.
-   This method checks first the module-level level set by
-   ``logging.disable(lvl)`` and then the logger's effective level as determined
-   by :meth:`getEffectiveLevel`.
-
-
-.. method:: Logger.getEffectiveLevel()
-
-   Indicates the effective level for this logger. If a value other than
-   :const:`NOTSET` has been set using :meth:`setLevel`, it is returned. Otherwise,
-   the hierarchy is traversed towards the root until a value other than
-   :const:`NOTSET` is found, and that value is returned.
-
-
-.. method:: Logger.getChild(suffix)
-
-   Returns a logger which is a descendant to this logger, as determined by the suffix.
-   Thus, ``logging.getLogger('abc').getChild('def.ghi')`` would return the same
-   logger as would be returned by ``logging.getLogger('abc.def.ghi')``. This is a
-   convenience method, useful when the parent logger is named using e.g. ``__name__``
-   rather than a literal string.
-
-   .. versionadded:: 3.2
-
-
-.. method:: Logger.debug(msg, *args, **kwargs)
-
-   Logs a message with level :const:`DEBUG` on this logger. The *msg* is the
-   message format string, and the *args* are the arguments which are merged into
-   *msg* using the string formatting operator. (Note that this means that you can
-   use keywords in the format string, together with a single dictionary argument.)
-
-   There are three keyword arguments in *kwargs* which are inspected: *exc_info*
-   which, if it does not evaluate as false, causes exception information to be
-   added to the logging message. If an exception tuple (in the format returned by
-   :func:`sys.exc_info`) is provided, it is used; otherwise, :func:`sys.exc_info`
-   is called to get the exception information.
-
-   The second optional keyword argument is *stack_info*, which defaults to
-   False. If specified as True, stack information is added to the logging
-   message, including the actual logging call. Note that this is not the same
-   stack information as that displayed through specifying *exc_info*: The
-   former is stack frames from the bottom of the stack up to the logging call
-   in the current thread, whereas the latter is information about stack frames
-   which have been unwound, following an exception, while searching for
-   exception handlers.
-
-   You can specify *stack_info* independently of *exc_info*, e.g. to just show
-   how you got to a certain point in your code, even when no exceptions were
-   raised. The stack frames are printed following a header line which says::
-
-       Stack (most recent call last):
-
-   This mimics the `Traceback (most recent call last):` which is used when
-   displaying exception frames.
-
-   The third keyword argument is *extra* which can be used to pass a
-   dictionary which is used to populate the __dict__ of the LogRecord created for
-   the logging event with user-defined attributes. These custom attributes can then
-   be used as you like. For example, they could be incorporated into logged
-   messages. For example::
-
-      FORMAT = "%(asctime)-15s %(clientip)s %(user)-8s %(message)s"
-      logging.basicConfig(format=FORMAT)
-      d = { 'clientip' : '192.168.0.1', 'user' : 'fbloggs' }
-      logger = logging.getLogger("tcpserver")
-      logger.warning("Protocol problem: %s", "connection reset", extra=d)
-
-   would print something like  ::
-
-      2006-02-08 22:20:02,165 192.168.0.1 fbloggs  Protocol problem: connection reset
-
-   The keys in the dictionary passed in *extra* should not clash with the keys used
-   by the logging system. (See the :class:`Formatter` documentation for more
-   information on which keys are used by the logging system.)
-
-   If you choose to use these attributes in logged messages, you need to exercise
-   some care. In the above example, for instance, the :class:`Formatter` has been
-   set up with a format string which expects 'clientip' and 'user' in the attribute
-   dictionary of the LogRecord. If these are missing, the message will not be
-   logged because a string formatting exception will occur. So in this case, you
-   always need to pass the *extra* dictionary with these keys.
-
-   While this might be annoying, this feature is intended for use in specialized
-   circumstances, such as multi-threaded servers where the same code executes in
-   many contexts, and interesting conditions which arise are dependent on this
-   context (such as remote client IP address and authenticated user name, in the
-   above example). In such circumstances, it is likely that specialized
-   :class:`Formatter`\ s would be used with particular :class:`Handler`\ s.
-
-   .. versionadded:: 3.2
-      The *stack_info* parameter was added.
-
-
-.. method:: Logger.info(msg, *args, **kwargs)
-
-   Logs a message with level :const:`INFO` on this logger. The arguments are
-   interpreted as for :meth:`debug`.
-
-
-.. method:: Logger.warning(msg, *args, **kwargs)
-
-   Logs a message with level :const:`WARNING` on this logger. The arguments are
-   interpreted as for :meth:`debug`.
-
-
-.. method:: Logger.error(msg, *args, **kwargs)
-
-   Logs a message with level :const:`ERROR` on this logger. The arguments are
-   interpreted as for :meth:`debug`.
-
-
-.. method:: Logger.critical(msg, *args, **kwargs)
-
-   Logs a message with level :const:`CRITICAL` on this logger. The arguments are
-   interpreted as for :meth:`debug`.
-
-
-.. method:: Logger.log(lvl, msg, *args, **kwargs)
-
-   Logs a message with integer level *lvl* on this logger. The other arguments are
-   interpreted as for :meth:`debug`.
-
-
-.. method:: Logger.exception(msg, *args)
-
-   Logs a message with level :const:`ERROR` on this logger. The arguments are
-   interpreted as for :meth:`debug`. Exception info is added to the logging
-   message. This method should only be called from an exception handler.
-
-
-.. method:: Logger.addFilter(filt)
-
-   Adds the specified filter *filt* to this logger.
-
-
-.. method:: Logger.removeFilter(filt)
-
-   Removes the specified filter *filt* from this logger.
-
-
-.. method:: Logger.filter(record)
-
-   Applies this logger's filters to the record and returns a true value if the
-   record is to be processed.
-
-
-.. method:: Logger.addHandler(hdlr)
-
-   Adds the specified handler *hdlr* to this logger.
-
-
-.. method:: Logger.removeHandler(hdlr)
-
-   Removes the specified handler *hdlr* from this logger.
-
-
-.. method:: Logger.findCaller(stack_info=False)
-
-   Finds the caller's source filename and line number. Returns the filename, line
-   number, function name and stack information as a 4-element tuple. The stack
-   information is returned as *None* unless *stack_info* is *True*.
-
-
-.. method:: Logger.handle(record)
-
-   Handles a record by passing it to all handlers associated with this logger and
-   its ancestors (until a false value of *propagate* is found). This method is used
-   for unpickled records received from a socket, as well as those created locally.
-   Logger-level filtering is applied using :meth:`~Logger.filter`.
-
-
-.. method:: Logger.makeRecord(name, lvl, fn, lno, msg, args, exc_info, func=None, extra=None, sinfo=None)
-
-   This is a factory method which can be overridden in subclasses to create
-   specialized :class:`LogRecord` instances.
-
-.. method:: Logger.hasHandlers()
-
-   Checks to see if this logger has any handlers configured. This is done by
-   looking for handlers in this logger and its parents in the logger hierarchy.
-   Returns True if a handler was found, else False. The method stops searching
-   up the hierarchy whenever a logger with the "propagate" attribute set to
-   False is found - that will be the last logger which is checked for the
-   existence of handlers.
-
-.. versionadded:: 3.2
-
-The :meth:`hasHandlers` method was not present in previous versions.
-
-.. _minimal-example:
-
-Basic example
--------------
-
-The :mod:`logging` package provides a lot of flexibility, and its configuration
-can appear daunting.  This section demonstrates that simple use of the logging
-package is possible.
-
-The simplest example shows logging to the console::
-
-   import logging
-
-   logging.debug('A debug message')
-   logging.info('Some information')
-   logging.warning('A shot across the bows')
-
-If you run the above script, you'll see this::
-
-   WARNING:root:A shot across the bows
-
-Because no particular logger was specified, the system used the root logger. The
-debug and info messages didn't appear because by default, the root logger is
-configured to only handle messages with a severity of WARNING or above. The
-message format is also a configuration default, as is the output destination of
-the messages - ``sys.stderr``. The severity level, the message format and
-destination can be easily changed, as shown in the example below::
-
-   import logging
-
-   logging.basicConfig(level=logging.DEBUG,
-                       format='%(asctime)s %(levelname)s %(message)s',
-                       filename='myapp.log',
-                       filemode='w')
-   logging.debug('A debug message')
-   logging.info('Some information')
-   logging.warning('A shot across the bows')
-
-The :meth:`basicConfig` method is used to change the configuration defaults,
-which results in output (written to ``myapp.log``) which should look
-something like the following::
-
-   2004-07-02 13:00:08,743 DEBUG A debug message
-   2004-07-02 13:00:08,743 INFO Some information
-   2004-07-02 13:00:08,743 WARNING A shot across the bows
-
-This time, all messages with a severity of DEBUG or above were handled, and the
-format of the messages was also changed, and output went to the specified file
-rather than the console.
-
-.. XXX logging should probably be updated for new string formatting!
-
-Formatting uses the old Python string formatting - see section
-:ref:`old-string-formatting`. The format string takes the following common
-specifiers. For a complete list of specifiers, consult the :class:`Formatter`
-documentation.
-
-+-------------------+-----------------------------------------------+
-| Format            | Description                                   |
-+===================+===============================================+
-| ``%(name)s``      | Name of the logger (logging channel).         |
-+-------------------+-----------------------------------------------+
-| ``%(levelname)s`` | Text logging level for the message            |
-|                   | (``'DEBUG'``, ``'INFO'``, ``'WARNING'``,      |
-|                   | ``'ERROR'``, ``'CRITICAL'``).                 |
-+-------------------+-----------------------------------------------+
-| ``%(asctime)s``   | Human-readable time when the                  |
-|                   | :class:`LogRecord` was created.  By default   |
-|                   | this is of the form "2003-07-08 16:49:45,896" |
-|                   | (the numbers after the comma are millisecond  |
-|                   | portion of the time).                         |
-+-------------------+-----------------------------------------------+
-| ``%(message)s``   | The logged message.                           |
-+-------------------+-----------------------------------------------+
-
-To change the date/time format, you can pass an additional keyword parameter,
-*datefmt*, as in the following::
-
-   import logging
-
-   logging.basicConfig(level=logging.DEBUG,
-                       format='%(asctime)s %(levelname)-8s %(message)s',
-                       datefmt='%a, %d %b %Y %H:%M:%S',
-                       filename='/temp/myapp.log',
-                       filemode='w')
-   logging.debug('A debug message')
-   logging.info('Some information')
-   logging.warning('A shot across the bows')
-
-which would result in output like ::
-
-   Fri, 02 Jul 2004 13:06:18 DEBUG    A debug message
-   Fri, 02 Jul 2004 13:06:18 INFO     Some information
-   Fri, 02 Jul 2004 13:06:18 WARNING  A shot across the bows
-
-The date format string follows the requirements of :func:`strftime` - see the
-documentation for the :mod:`time` module.
-
-If, instead of sending logging output to the console or a file, you'd rather use
-a file-like object which you have created separately, you can pass it to
-:func:`basicConfig` using the *stream* keyword argument. Note that if both
-*stream* and *filename* keyword arguments are passed, the *stream* argument is
-ignored.
-
-Of course, you can put variable information in your output. To do this, simply
-have the message be a format string and pass in additional arguments containing
-the variable information, as in the following example::
-
-   import logging
-
-   logging.basicConfig(level=logging.DEBUG,
-                       format='%(asctime)s %(levelname)-8s %(message)s',
-                       datefmt='%a, %d %b %Y %H:%M:%S',
-                       filename='/temp/myapp.log',
-                       filemode='w')
-   logging.error('Pack my box with %d dozen %s', 5, 'liquor jugs')
-
-which would result in ::
-
-   Wed, 21 Jul 2004 15:35:16 ERROR    Pack my box with 5 dozen liquor jugs
-
-
-.. _multiple-destinations:
-
-Logging to multiple destinations
---------------------------------
-
-Let's say you want to log to console and file with different message formats and
-in differing circumstances. Say you want to log messages with levels of DEBUG
-and higher to file, and those messages at level INFO and higher to the console.
-Let's also assume that the file should contain timestamps, but the console
-messages should not. Here's how you can achieve this::
-
-   import logging
-
-   # set up logging to file - see previous section for more details
-   logging.basicConfig(level=logging.DEBUG,
-                       format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
-                       datefmt='%m-%d %H:%M',
-                       filename='/temp/myapp.log',
-                       filemode='w')
-   # define a Handler which writes INFO messages or higher to the sys.stderr
-   console = logging.StreamHandler()
-   console.setLevel(logging.INFO)
-   # set a format which is simpler for console use
-   formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s')
-   # tell the handler to use this format
-   console.setFormatter(formatter)
-   # add the handler to the root logger
-   logging.getLogger('').addHandler(console)
-
-   # Now, we can log to the root logger, or any other logger. First the root...
-   logging.info('Jackdaws love my big sphinx of quartz.')
-
-   # Now, define a couple of other loggers which might represent areas in your
-   # application:
-
-   logger1 = logging.getLogger('myapp.area1')
-   logger2 = logging.getLogger('myapp.area2')
-
-   logger1.debug('Quick zephyrs blow, vexing daft Jim.')
-   logger1.info('How quickly daft jumping zebras vex.')
-   logger2.warning('Jail zesty vixen who grabbed pay from quack.')
-   logger2.error('The five boxing wizards jump quickly.')
-
-When you run this, on the console you will see ::
-
-   root        : INFO     Jackdaws love my big sphinx of quartz.
-   myapp.area1 : INFO     How quickly daft jumping zebras vex.
-   myapp.area2 : WARNING  Jail zesty vixen who grabbed pay from quack.
-   myapp.area2 : ERROR    The five boxing wizards jump quickly.
-
-and in the file you will see something like ::
-
-   10-22 22:19 root         INFO     Jackdaws love my big sphinx of quartz.
-   10-22 22:19 myapp.area1  DEBUG    Quick zephyrs blow, vexing daft Jim.
-   10-22 22:19 myapp.area1  INFO     How quickly daft jumping zebras vex.
-   10-22 22:19 myapp.area2  WARNING  Jail zesty vixen who grabbed pay from quack.
-   10-22 22:19 myapp.area2  ERROR    The five boxing wizards jump quickly.
-
-As you can see, the DEBUG message only shows up in the file. The other messages
-are sent to both destinations.
-
-This example uses console and file handlers, but you can use any number and
-combination of handlers you choose.
-
-.. _logging-exceptions:
-
-Exceptions raised during logging
---------------------------------
-
-The logging package is designed to swallow exceptions which occur while logging
-in production. This is so that errors which occur while handling logging events
-- such as logging misconfiguration, network or other similar errors - do not
-cause the application using logging to terminate prematurely.
-
-:class:`SystemExit` and :class:`KeyboardInterrupt` exceptions are never
-swallowed. Other exceptions which occur during the :meth:`emit` method of a
-:class:`Handler` subclass are passed to its :meth:`handleError` method.
-
-The default implementation of :meth:`handleError` in :class:`Handler` checks
-to see if a module-level variable, :data:`raiseExceptions`, is set. If set, a
-traceback is printed to :data:`sys.stderr`. If not set, the exception is swallowed.
-
-**Note:** The default value of :data:`raiseExceptions` is ``True``. This is because
-during development, you typically want to be notified of any exceptions that
-occur. It's advised that you set :data:`raiseExceptions` to ``False`` for production
-usage.
-
-.. _context-info:
-
-Adding contextual information to your logging output
-----------------------------------------------------
-
-Sometimes you want logging output to contain contextual information in
-addition to the parameters passed to the logging call. For example, in a
-networked application, it may be desirable to log client-specific information
-in the log (e.g. remote client's username, or IP address). Although you could
-use the *extra* parameter to achieve this, it's not always convenient to pass
-the information in this way. While it might be tempting to create
-:class:`Logger` instances on a per-connection basis, this is not a good idea
-because these instances are not garbage collected. While this is not a problem
-in practice, when the number of :class:`Logger` instances is dependent on the
-level of granularity you want to use in logging an application, it could
-be hard to manage if the number of :class:`Logger` instances becomes
-effectively unbounded.
-
-
-Using LoggerAdapters to impart contextual information
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-An easy way in which you can pass contextual information to be output along
-with logging event information is to use the :class:`LoggerAdapter` class.
-This class is designed to look like a :class:`Logger`, so that you can call
-:meth:`debug`, :meth:`info`, :meth:`warning`, :meth:`error`,
-:meth:`exception`, :meth:`critical` and :meth:`log`. These methods have the
-same signatures as their counterparts in :class:`Logger`, so you can use the
-two types of instances interchangeably.
-
-When you create an instance of :class:`LoggerAdapter`, you pass it a
-:class:`Logger` instance and a dict-like object which contains your contextual
-information. When you call one of the logging methods on an instance of
-:class:`LoggerAdapter`, it delegates the call to the underlying instance of
-:class:`Logger` passed to its constructor, and arranges to pass the contextual
-information in the delegated call. Here's a snippet from the code of
-:class:`LoggerAdapter`::
-
-    def debug(self, msg, *args, **kwargs):
-        """
-        Delegate a debug call to the underlying logger, after adding
-        contextual information from this adapter instance.
-        """
-        msg, kwargs = self.process(msg, kwargs)
-        self.logger.debug(msg, *args, **kwargs)
-
-The :meth:`process` method of :class:`LoggerAdapter` is where the contextual
-information is added to the logging output. It's passed the message and
-keyword arguments of the logging call, and it passes back (potentially)
-modified versions of these to use in the call to the underlying logger. The
-default implementation of this method leaves the message alone, but inserts
-an "extra" key in the keyword argument whose value is the dict-like object
-passed to the constructor. Of course, if you had passed an "extra" keyword
-argument in the call to the adapter, it will be silently overwritten.
-
-The advantage of using "extra" is that the values in the dict-like object are
-merged into the :class:`LogRecord` instance's __dict__, allowing you to use
-customized strings with your :class:`Formatter` instances which know about
-the keys of the dict-like object. If you need a different method, e.g. if you
-want to prepend or append the contextual information to the message string,
-you just need to subclass :class:`LoggerAdapter` and override :meth:`process`
-to do what you need. Here's an example script which uses this class, which
-also illustrates what dict-like behaviour is needed from an arbitrary
-"dict-like" object for use in the constructor::
-
-   import logging
-
-   class ConnInfo:
-       """
-       An example class which shows how an arbitrary class can be used as
-       the 'extra' context information repository passed to a LoggerAdapter.
-       """
-
-       def __getitem__(self, name):
-           """
-           To allow this instance to look like a dict.
-           """
-           from random import choice
-           if name == "ip":
-               result = choice(["127.0.0.1", "192.168.0.1"])
-           elif name == "user":
-               result = choice(["jim", "fred", "sheila"])
-           else:
-               result = self.__dict__.get(name, "?")
-           return result
-
-       def __iter__(self):
-           """
-           To allow iteration over keys, which will be merged into
-           the LogRecord dict before formatting and output.
-           """
-           keys = ["ip", "user"]
-           keys.extend(self.__dict__.keys())
-           return keys.__iter__()
-
-   if __name__ == "__main__":
-       from random import choice
-       levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
-       a1 = logging.LoggerAdapter(logging.getLogger("a.b.c"),
-                                  { "ip" : "123.231.231.123", "user" : "sheila" })
-       logging.basicConfig(level=logging.DEBUG,
-                           format="%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s")
-       a1.debug("A debug message")
-       a1.info("An info message with %s", "some parameters")
-       a2 = logging.LoggerAdapter(logging.getLogger("d.e.f"), ConnInfo())
-       for x in range(10):
-           lvl = choice(levels)
-           lvlname = logging.getLevelName(lvl)
-           a2.log(lvl, "A message at %s level with %d %s", lvlname, 2, "parameters")
-
-When this script is run, the output should look something like this::
-
-   2008-01-18 14:49:54,023 a.b.c DEBUG    IP: 123.231.231.123 User: sheila   A debug message
-   2008-01-18 14:49:54,023 a.b.c INFO     IP: 123.231.231.123 User: sheila   An info message with some parameters
-   2008-01-18 14:49:54,023 d.e.f CRITICAL IP: 192.168.0.1     User: jim      A message at CRITICAL level with 2 parameters
-   2008-01-18 14:49:54,033 d.e.f INFO     IP: 192.168.0.1     User: jim      A message at INFO level with 2 parameters
-   2008-01-18 14:49:54,033 d.e.f WARNING  IP: 192.168.0.1     User: sheila   A message at WARNING level with 2 parameters
-   2008-01-18 14:49:54,033 d.e.f ERROR    IP: 127.0.0.1       User: fred     A message at ERROR level with 2 parameters
-   2008-01-18 14:49:54,033 d.e.f ERROR    IP: 127.0.0.1       User: sheila   A message at ERROR level with 2 parameters
-   2008-01-18 14:49:54,033 d.e.f WARNING  IP: 192.168.0.1     User: sheila   A message at WARNING level with 2 parameters
-   2008-01-18 14:49:54,033 d.e.f WARNING  IP: 192.168.0.1     User: jim      A message at WARNING level with 2 parameters
-   2008-01-18 14:49:54,033 d.e.f INFO     IP: 192.168.0.1     User: fred     A message at INFO level with 2 parameters
-   2008-01-18 14:49:54,033 d.e.f WARNING  IP: 192.168.0.1     User: sheila   A message at WARNING level with 2 parameters
-   2008-01-18 14:49:54,033 d.e.f WARNING  IP: 127.0.0.1       User: jim      A message at WARNING level with 2 parameters
-
-
-.. _filters-contextual:
-
-Using Filters to impart contextual information
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-You can also add contextual information to log output using a user-defined
-:class:`Filter`. ``Filter`` instances are allowed to modify the ``LogRecords``
-passed to them, including adding additional attributes which can then be output
-using a suitable format string, or if needed a custom :class:`Formatter`.
-
-For example in a web application, the request being processed (or at least,
-the interesting parts of it) can be stored in a threadlocal
-(:class:`threading.local`) variable, and then accessed from a ``Filter`` to
-add, say, information from the request - say, the remote IP address and remote
-user's username - to the ``LogRecord``, using the attribute names 'ip' and
-'user' as in the ``LoggerAdapter`` example above. In that case, the same format
-string can be used to get similar output to that shown above. Here's an example
-script::
-
-    import logging
-    from random import choice
-
-    class ContextFilter(logging.Filter):
-        """
-        This is a filter which injects contextual information into the log.
-
-        Rather than use actual contextual information, we just use random
-        data in this demo.
-        """
-
-        USERS = ['jim', 'fred', 'sheila']
-        IPS = ['123.231.231.123', '127.0.0.1', '192.168.0.1']
-
-        def filter(self, record):
-
-            record.ip = choice(ContextFilter.IPS)
-            record.user = choice(ContextFilter.USERS)
-            return True
-
-    if __name__ == "__main__":
-       levels = (logging.DEBUG, logging.INFO, logging.WARNING, logging.ERROR, logging.CRITICAL)
-       a1 = logging.LoggerAdapter(logging.getLogger("a.b.c"),
-                                  { "ip" : "123.231.231.123", "user" : "sheila" })
-       logging.basicConfig(level=logging.DEBUG,
-                           format="%(asctime)-15s %(name)-5s %(levelname)-8s IP: %(ip)-15s User: %(user)-8s %(message)s")
-       a1 = logging.getLogger("a.b.c")
-       a2 = logging.getLogger("d.e.f")
-
-       f = ContextFilter()
-       a1.addFilter(f)
-       a2.addFilter(f)
-       a1.debug("A debug message")
-       a1.info("An info message with %s", "some parameters")
-       for x in range(10):
-           lvl = choice(levels)
-           lvlname = logging.getLevelName(lvl)
-           a2.log(lvl, "A message at %s level with %d %s", lvlname, 2, "parameters")
-
-which, when run, produces something like::
-
-    2010-09-06 22:38:15,292 a.b.c DEBUG    IP: 123.231.231.123 User: fred     A debug message
-    2010-09-06 22:38:15,300 a.b.c INFO     IP: 192.168.0.1     User: sheila   An info message with some parameters
-    2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 127.0.0.1       User: sheila   A message at CRITICAL level with 2 parameters
-    2010-09-06 22:38:15,300 d.e.f ERROR    IP: 127.0.0.1       User: jim      A message at ERROR level with 2 parameters
-    2010-09-06 22:38:15,300 d.e.f DEBUG    IP: 127.0.0.1       User: sheila   A message at DEBUG level with 2 parameters
-    2010-09-06 22:38:15,300 d.e.f ERROR    IP: 123.231.231.123 User: fred     A message at ERROR level with 2 parameters
-    2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 192.168.0.1     User: jim      A message at CRITICAL level with 2 parameters
-    2010-09-06 22:38:15,300 d.e.f CRITICAL IP: 127.0.0.1       User: sheila   A message at CRITICAL level with 2 parameters
-    2010-09-06 22:38:15,300 d.e.f DEBUG    IP: 192.168.0.1     User: jim      A message at DEBUG level with 2 parameters
-    2010-09-06 22:38:15,301 d.e.f ERROR    IP: 127.0.0.1       User: sheila   A message at ERROR level with 2 parameters
-    2010-09-06 22:38:15,301 d.e.f DEBUG    IP: 123.231.231.123 User: fred     A message at DEBUG level with 2 parameters
-    2010-09-06 22:38:15,301 d.e.f INFO     IP: 123.231.231.123 User: fred     A message at INFO level with 2 parameters
-
-
-.. _multiple-processes:
-
-Logging to a single file from multiple processes
-------------------------------------------------
-
-Although logging is thread-safe, and logging to a single file from multiple
-threads in a single process *is* supported, logging to a single file from
-*multiple processes* is *not* supported, because there is no standard way to
-serialize access to a single file across multiple processes in Python. If you
-need to log to a single file from multiple processes, one way of doing this is
-to have all the processes log to a :class:`SocketHandler`, and have a separate
-process which implements a socket server which reads from the socket and logs
-to file. (If you prefer, you can dedicate one thread in one of the existing
-processes to perform this function.) The following section documents this
-approach in more detail and includes a working socket receiver which can be
-used as a starting point for you to adapt in your own applications.
-
-If you are using a recent version of Python which includes the
-:mod:`multiprocessing` module, you could write your own handler which uses the
-:class:`Lock` class from this module to serialize access to the file from
-your processes. The existing :class:`FileHandler` and subclasses do not make
-use of :mod:`multiprocessing` at present, though they may do so in the future.
-Note that at present, the :mod:`multiprocessing` module does not provide
-working lock functionality on all platforms (see
-http://bugs.python.org/issue3770).
-
-.. currentmodule:: logging.handlers
-
-Alternatively, you can use a ``Queue`` and a :class:`QueueHandler` to send
-all logging events to one of the processes in your multi-process application.
-The following example script demonstrates how you can do this; in the example
-a separate listener process listens for events sent by other processes and logs
-them according to its own logging configuration. Although the example only
-demonstrates one way of doing it (for example, you may want to use a listener
-thread rather than a separate listener process - the implementation would be
-analogous) it does allow for completely different logging configurations for
-the listener and the other processes in your application, and can be used as
-the basis for code meeting your own specific requirements::
-
-    # You'll need these imports in your own code
-    import logging
-    import logging.handlers
-    import multiprocessing
-
-    # Next two import lines for this demo only
-    from random import choice, random
-    import time
-
-    #
-    # Because you'll want to define the logging configurations for listener and workers, the
-    # listener and worker process functions take a configurer parameter which is a callable
-    # for configuring logging for that process. These functions are also passed the queue,
-    # which they use for communication.
-    #
-    # In practice, you can configure the listener however you want, but note that in this
-    # simple example, the listener does not apply level or filter logic to received records.
-    # In practice, you would probably want to do ths logic in the worker processes, to avoid
-    # sending events which would be filtered out between processes.
-    #
-    # The size of the rotated files is made small so you can see the results easily.
-    def listener_configurer():
-        root = logging.getLogger()
-        h = logging.handlers.RotatingFileHandler('/tmp/mptest.log', 'a', 300, 10)
-        f = logging.Formatter('%(asctime)s %(processName)-10s %(name)s %(levelname)-8s %(message)s')
-        h.setFormatter(f)
-        root.addHandler(h)
-
-    # This is the listener process top-level loop: wait for logging events
-    # (LogRecords)on the queue and handle them, quit when you get a None for a
-    # LogRecord.
-    def listener_process(queue, configurer):
-        configurer()
-        while True:
-            try:
-                record = queue.get()
-                if record is None: # We send this as a sentinel to tell the listener to quit.
-                    break
-                logger = logging.getLogger(record.name)
-                logger.handle(record) # No level or filter logic applied - just do it!
-            except (KeyboardInterrupt, SystemExit):
-                raise
-            except:
-                import sys, traceback
-                print >> sys.stderr, 'Whoops! Problem:'
-                traceback.print_exc(file=sys.stderr)
-
-    # Arrays used for random selections in this demo
-
-    LEVELS = [logging.DEBUG, logging.INFO, logging.WARNING,
-              logging.ERROR, logging.CRITICAL]
-
-    LOGGERS = ['a.b.c', 'd.e.f']
-
-    MESSAGES = [
-        'Random message #1',
-        'Random message #2',
-        'Random message #3',
-    ]
-
-    # The worker configuration is done at the start of the worker process run.
-    # Note that on Windows you can't rely on fork semantics, so each process
-    # will run the logging configuration code when it starts.
-    def worker_configurer(queue):
-        h = logging.handlers.QueueHandler(queue) # Just the one handler needed
-        root = logging.getLogger()
-        root.addHandler(h)
-        root.setLevel(logging.DEBUG) # send all messages, for demo; no other level or filter logic applied.
-
-    # This is the worker process top-level loop, which just logs ten events with
-    # random intervening delays before terminating.
-    # The print messages are just so you know it's doing something!
-    def worker_process(queue, configurer):
-        configurer(queue)
-        name = multiprocessing.current_process().name
-        print('Worker started: %s' % name)
-        for i in range(10):
-            time.sleep(random())
-            logger = logging.getLogger(choice(LOGGERS))
-            level = choice(LEVELS)
-            message = choice(MESSAGES)
-            logger.log(level, message)
-        print('Worker finished: %s' % name)
-
-    # Here's where the demo gets orchestrated. Create the queue, create and start
-    # the listener, create ten workers and start them, wait for them to finish,
-    # then send a None to the queue to tell the listener to finish.
-    def main():
-        queue = multiprocessing.Queue(-1)
-        listener = multiprocessing.Process(target=listener_process,
-                                           args=(queue, listener_configurer))
-        listener.start()
-        workers = []
-        for i in range(10):
-            worker = multiprocessing.Process(target=worker_process,
-                                           args=(queue, worker_configurer))
-            workers.append(worker)
-            worker.start()
-        for w in workers:
-            w.join()
-        queue.put_nowait(None)
-        listener.join()
-
-    if __name__ == '__main__':
-        main()
-
-
-.. currentmodule:: logging
-
-
-.. _network-logging:
-
-Sending and receiving logging events across a network
------------------------------------------------------
-
-Let's say you want to send logging events across a network, and handle them at
-the receiving end. A simple way of doing this is attaching a
-:class:`SocketHandler` instance to the root logger at the sending end::
-
-   import logging, logging.handlers
-
-   rootLogger = logging.getLogger('')
-   rootLogger.setLevel(logging.DEBUG)
-   socketHandler = logging.handlers.SocketHandler('localhost',
-                       logging.handlers.DEFAULT_TCP_LOGGING_PORT)
-   # don't bother with a formatter, since a socket handler sends the event as
-   # an unformatted pickle
-   rootLogger.addHandler(socketHandler)
-
-   # Now, we can log to the root logger, or any other logger. First the root...
-   logging.info('Jackdaws love my big sphinx of quartz.')
-
-   # Now, define a couple of other loggers which might represent areas in your
-   # application:
-
-   logger1 = logging.getLogger('myapp.area1')
-   logger2 = logging.getLogger('myapp.area2')
-
-   logger1.debug('Quick zephyrs blow, vexing daft Jim.')
-   logger1.info('How quickly daft jumping zebras vex.')
-   logger2.warning('Jail zesty vixen who grabbed pay from quack.')
-   logger2.error('The five boxing wizards jump quickly.')
-
-At the receiving end, you can set up a receiver using the :mod:`socketserver`
-module. Here is a basic working example::
-
-   import pickle
-   import logging
-   import logging.handlers
-   import socketserver
-   import struct
-
-
-   class LogRecordStreamHandler(socketserver.StreamRequestHandler):
-       """Handler for a streaming logging request.
-
-       This basically logs the record using whatever logging policy is
-       configured locally.
-       """
-
-       def handle(self):
-           """
-           Handle multiple requests - each expected to be a 4-byte length,
-           followed by the LogRecord in pickle format. Logs the record
-           according to whatever policy is configured locally.
-           """
-           while True:
-               chunk = self.connection.recv(4)
-               if len(chunk) < 4:
-                   break
-               slen = struct.unpack(">L", chunk)[0]
-               chunk = self.connection.recv(slen)
-               while len(chunk) < slen:
-                   chunk = chunk + self.connection.recv(slen - len(chunk))
-               obj = self.unPickle(chunk)
-               record = logging.makeLogRecord(obj)
-               self.handleLogRecord(record)
-
-       def unPickle(self, data):
-           return pickle.loads(data)
-
-       def handleLogRecord(self, record):
-           # if a name is specified, we use the named logger rather than the one
-           # implied by the record.
-           if self.server.logname is not None:
-               name = self.server.logname
-           else:
-               name = record.name
-           logger = logging.getLogger(name)
-           # N.B. EVERY record gets logged. This is because Logger.handle
-           # is normally called AFTER logger-level filtering. If you want
-           # to do filtering, do it at the client end to save wasting
-           # cycles and network bandwidth!
-           logger.handle(record)
-
-   class LogRecordSocketReceiver(socketserver.ThreadingTCPServer):
-       """simple TCP socket-based logging receiver suitable for testing.
-       """
-
-       allow_reuse_address = 1
-
-       def __init__(self, host='localhost',
-                    port=logging.handlers.DEFAULT_TCP_LOGGING_PORT,
-                    handler=LogRecordStreamHandler):
-           socketserver.ThreadingTCPServer.__init__(self, (host, port), handler)
-           self.abort = 0
-           self.timeout = 1
-           self.logname = None
-
-       def serve_until_stopped(self):
-           import select
-           abort = 0
-           while not abort:
-               rd, wr, ex = select.select([self.socket.fileno()],
-                                          [], [],
-                                          self.timeout)
-               if rd:
-                   self.handle_request()
-               abort = self.abort
-
-   def main():
-       logging.basicConfig(
-           format="%(relativeCreated)5d %(name)-15s %(levelname)-8s %(message)s")
-       tcpserver = LogRecordSocketReceiver()
-       print("About to start TCP server...")
-       tcpserver.serve_until_stopped()
-
-   if __name__ == "__main__":
-       main()
-
-First run the server, and then the client. On the client side, nothing is
-printed on the console; on the server side, you should see something like::
-
-   About to start TCP server...
-      59 root            INFO     Jackdaws love my big sphinx of quartz.
-      59 myapp.area1     DEBUG    Quick zephyrs blow, vexing daft Jim.
-      69 myapp.area1     INFO     How quickly daft jumping zebras vex.
-      69 myapp.area2     WARNING  Jail zesty vixen who grabbed pay from quack.
-      69 myapp.area2     ERROR    The five boxing wizards jump quickly.
-
-Note that there are some security issues with pickle in some scenarios. If
-these affect you, you can use an alternative serialization scheme by overriding
-the :meth:`makePickle` method and implementing your alternative there, as
-well as adapting the above script to use your alternative serialization.
-
-.. _arbitrary-object-messages:
-
-Using arbitrary objects as messages
------------------------------------
-
-In the preceding sections and examples, it has been assumed that the message
-passed when logging the event is a string. However, this is not the only
-possibility. You can pass an arbitrary object as a message, and its
-:meth:`__str__` method will be called when the logging system needs to convert
-it to a string representation. In fact, if you want to, you can avoid
-computing a string representation altogether - for example, the
-:class:`SocketHandler` emits an event by pickling it and sending it over the
-wire.
-
-Dealing with handlers that block
---------------------------------
-
-.. currentmodule:: logging.handlers
-
-Sometimes you have to get your logging handlers to do their work without
-blocking the thread you???re logging from. This is common in Web applications,
-though of course it also occurs in other scenarios.
-
-A common culprit which demonstrates sluggish behaviour is the
-:class:`SMTPHandler`: sending emails can take a long time, for a
-number of reasons outside the developer???s control (for example, a poorly
-performing mail or network infrastructure). But almost any network-based
-handler can block: Even a :class:`SocketHandler` operation may do a
-DNS query under the hood which is too slow (and this query can be deep in the
-socket library code, below the Python layer, and outside your control).
-
-One solution is to use a two-part approach. For the first part, attach only a
-:class:`QueueHandler` to those loggers which are accessed from
-performance-critical threads. They simply write to their queue, which can be
-sized to a large enough capacity or initialized with no upper bound to their
-size. The write to the queue will typically be accepted quickly, though you
-will probably need to catch the :ref:`queue.Full` exception as a precaution
-in your code. If you are a library developer who has performance-critical
-threads in their code, be sure to document this (together with a suggestion to
-attach only ``QueueHandlers`` to your loggers) for the benefit of other
-developers who will use your code.
-
-The second part of the solution is :class:`QueueListener`, which has been
-designed as the counterpart to :class:`QueueHandler`.  A
-:class:`QueueListener` is very simple: it???s passed a queue and some handlers,
-and it fires up an internal thread which listens to its queue for LogRecords
-sent from ``QueueHandlers`` (or any other source of ``LogRecords``, for that
-matter). The ``LogRecords`` are removed from the queue and passed to the
-handlers for processing.
-
-The advantage of having a separate :class:`QueueListener` class is that you
-can use the same instance to service multiple ``QueueHandlers``. This is more
-resource-friendly than, say, having threaded versions of the existing handler
-classes, which would eat up one thread per handler for no particular benefit.
-
-An example of using these two classes follows (imports omitted)::
-
-    que = queue.Queue(-1) # no limit on size
-    queue_handler = QueueHandler(que)
-    handler = logging.StreamHandler()
-    listener = QueueListener(que, handler)
-    root = logging.getLogger()
-    root.addHandler(queue_handler)
-    formatter = logging.Formatter('%(threadName)s: %(message)s')
-    handler.setFormatter(formatter)
-    listener.start()
-    # The log output will display the thread which generated
-    # the event (the main thread) rather than the internal
-    # thread which monitors the internal queue. This is what
-    # you want to happen.
-    root.warning('Look out!')
-    listener.stop()
-
-which, when run, will produce::
-
-    MainThread: Look out!
-
-
-Optimization
-------------
-
-Formatting of message arguments is deferred until it cannot be avoided.
-However, computing the arguments passed to the logging method can also be
-expensive, and you may want to avoid doing it if the logger will just throw
-away your event. To decide what to do, you can call the :meth:`isEnabledFor`
-method which takes a level argument and returns true if the event would be
-created by the Logger for that level of call. You can write code like this::
-
-    if logger.isEnabledFor(logging.DEBUG):
-        logger.debug("Message with %s, %s", expensive_func1(),
-                                            expensive_func2())
-
-so that if the logger's threshold is set above ``DEBUG``, the calls to
-:func:`expensive_func1` and :func:`expensive_func2` are never made.
-
-There are other optimizations which can be made for specific applications which
-need more precise control over what logging information is collected. Here's a
-list of things you can do to avoid processing during logging which you don't
-need:
-
-+-----------------------------------------------+----------------------------------------+
-| What you don't want to collect                | How to avoid collecting it             |
-+===============================================+========================================+
-| Information about where calls were made from. | Set ``logging._srcfile`` to ``None``.  |
-+-----------------------------------------------+----------------------------------------+
-| Threading information.                        | Set ``logging.logThreads`` to ``0``.   |
-+-----------------------------------------------+----------------------------------------+
-| Process information.                          | Set ``logging.logProcesses`` to ``0``. |
-+-----------------------------------------------+----------------------------------------+
-
-Also note that the core logging module only includes the basic handlers. If
-you don't import :mod:`logging.handlers` and :mod:`logging.config`, they won't
-take up any memory.
 
 .. _handler:
 
@@ -2129,1171 +379,653 @@
    is intended to be implemented by subclasses and so raises a
    :exc:`NotImplementedError`.
 
+For a list of handlers included as standard, see :mod:`logging.handlers`.
 
-.. _stream-handler:
-
-StreamHandler
-^^^^^^^^^^^^^
-
-The :class:`StreamHandler` class, located in the core :mod:`logging` package,
-sends logging output to streams such as *sys.stdout*, *sys.stderr* or any
-file-like object (or, more precisely, any object which supports :meth:`write`
-and :meth:`flush` methods).
+.. _formatter-objects:
 
+Formatter Objects
+-----------------
 
 .. currentmodule:: logging
 
-.. class:: StreamHandler(stream=None)
-
-   Returns a new instance of the :class:`StreamHandler` class. If *stream* is
-   specified, the instance will use it for logging output; otherwise, *sys.stderr*
-   will be used.
-
-
-   .. method:: emit(record)
+:class:`Formatter` objects have the following attributes and methods. They are
+responsible for converting a :class:`LogRecord` to (usually) a string which can
+be interpreted by either a human or an external system. The base
+:class:`Formatter` allows a formatting string to be specified. If none is
+supplied, the default value of ``'%(message)s'`` is used.
 
-      If a formatter is specified, it is used to format the record. The record
-      is then written to the stream with a trailing newline. If exception
-      information is present, it is formatted using
-      :func:`traceback.print_exception` and appended to the stream.
+A Formatter can be initialized with a format string which makes use of knowledge
+of the :class:`LogRecord` attributes - such as the default value mentioned above
+making use of the fact that the user's message and arguments are pre-formatted
+into a :class:`LogRecord`'s *message* attribute.  This format string contains
+standard Python %-style mapping keys. See section :ref:`old-string-formatting`
+for more information on string formatting.
 
+The useful mapping keys in a :class:`LogRecord` are given in the section on
+:ref:`logrecord-attributes`.
 
-   .. method:: flush()
 
-      Flushes the stream by calling its :meth:`flush` method. Note that the
-      :meth:`close` method is inherited from :class:`Handler` and so does
-      no output, so an explicit :meth:`flush` call may be needed at times.
+.. class:: Formatter(fmt=None, datefmt=None)
 
-.. versionchanged:: 3.2
-   The ``StreamHandler`` class now has a ``terminator`` attribute, default
-   value ``"\n"``, which is used as the terminator when writing a formatted
-   record to a stream. If you don't want this newline termination, you can
-   set the handler instance's ``terminator`` attribute to the empty string.
-
-.. _file-handler:
-
-FileHandler
-^^^^^^^^^^^
-
-The :class:`FileHandler` class, located in the core :mod:`logging` package,
-sends logging output to a disk file.  It inherits the output functionality from
-:class:`StreamHandler`.
+   Returns a new instance of the :class:`Formatter` class.  The instance is
+   initialized with a format string for the message as a whole, as well as a
+   format string for the date/time portion of a message.  If no *fmt* is
+   specified, ``'%(message)s'`` is used.  If no *datefmt* is specified, the
+   ISO8601 date format is used.
 
+   .. method:: format(record)
 
-.. class:: FileHandler(filename, mode='a', encoding=None, delay=False)
+      The record's attribute dictionary is used as the operand to a string
+      formatting operation. Returns the resulting string. Before formatting the
+      dictionary, a couple of preparatory steps are carried out. The *message*
+      attribute of the record is computed using *msg* % *args*. If the
+      formatting string contains ``'(asctime)'``, :meth:`formatTime` is called
+      to format the event time. If there is exception information, it is
+      formatted using :meth:`formatException` and appended to the message. Note
+      that the formatted exception information is cached in attribute
+      *exc_text*. This is useful because the exception information can be
+      pickled and sent across the wire, but you should be careful if you have
+      more than one :class:`Formatter` subclass which customizes the formatting
+      of exception information. In this case, you will have to clear the cached
+      value after a formatter has done its formatting, so that the next
+      formatter to handle the event doesn't use the cached value but
+      recalculates it afresh.
 
-   Returns a new instance of the :class:`FileHandler` class. The specified file is
-   opened and used as the stream for logging. If *mode* is not specified,
-   :const:`'a'` is used.  If *encoding* is not *None*, it is used to open the file
-   with that encoding.  If *delay* is true, then file opening is deferred until the
-   first call to :meth:`emit`. By default, the file grows indefinitely.
+      If stack information is available, it's appended after the exception
+      information, using :meth:`formatStack` to transform it if necessary.
 
 
-   .. method:: close()
+   .. method:: formatTime(record, datefmt=None)
 
-      Closes the file.
+      This method should be called from :meth:`format` by a formatter which
+      wants to make use of a formatted time. This method can be overridden in
+      formatters to provide for any specific requirement, but the basic behavior
+      is as follows: if *datefmt* (a string) is specified, it is used with
+      :func:`time.strftime` to format the creation time of the
+      record. Otherwise, the ISO8601 format is used.  The resulting string is
+      returned.
 
 
-   .. method:: emit(record)
+   .. method:: formatException(exc_info)
 
-      Outputs the record to the file.
+      Formats the specified exception information (a standard exception tuple as
+      returned by :func:`sys.exc_info`) as a string. This default implementation
+      just uses :func:`traceback.print_exception`. The resulting string is
+      returned.
 
-.. _null-handler:
+   .. method:: formatStack(stack_info)
 
-NullHandler
-^^^^^^^^^^^
+      Formats the specified stack information (a string as returned by
+      :func:`traceback.print_stack`, but with the last newline removed) as a
+      string. This default implementation just returns the input value.
 
-.. versionadded:: 3.1
+.. _filter:
 
-The :class:`NullHandler` class, located in the core :mod:`logging` package,
-does not do any formatting or output. It is essentially a "no-op" handler
-for use by library developers.
+Filter Objects
+--------------
 
+``Filters`` can be used by ``Handlers`` and ``Loggers`` for more sophisticated
+filtering than is provided by levels. The base filter class only allows events
+which are below a certain point in the logger hierarchy. For example, a filter
+initialized with 'A.B' will allow events logged by loggers 'A.B', 'A.B.C',
+'A.B.C.D', 'A.B.D' etc. but not 'A.BB', 'B.A.B' etc. If initialized with the
+empty string, all events are passed.
 
-.. class:: NullHandler()
 
-   Returns a new instance of the :class:`NullHandler` class.
+.. class:: Filter(name='')
 
+   Returns an instance of the :class:`Filter` class. If *name* is specified, it
+   names a logger which, together with its children, will have its events allowed
+   through the filter. If *name* is the empty string, allows every event.
 
-   .. method:: emit(record)
 
-      This method does nothing.
+   .. method:: filter(record)
 
-   .. method:: handle(record)
+      Is the specified record to be logged? Returns zero for no, nonzero for
+      yes. If deemed appropriate, the record may be modified in-place by this
+      method.
 
-      This method does nothing.
+Note that filters attached to handlers are consulted whenever an event is
+emitted by the handler, whereas filters attached to loggers are consulted
+whenever an event is logged to the handler (using :meth:`debug`, :meth:`info`,
+etc.) This means that events which have been generated by descendant loggers
+will not be filtered by a logger's filter setting, unless the filter has also
+been applied to those descendant loggers.
 
-   .. method:: createLock()
+You don't actually need to subclass ``Filter``: you can pass any instance
+which has a ``filter`` method with the same semantics.
 
-      This method returns ``None`` for the lock, since there is no
-      underlying I/O to which access needs to be serialized.
+.. versionchanged:: 3.2
+   You don't need to create specialized ``Filter`` classes, or use other
+   classes with a ``filter`` method: you can use a function (or other
+   callable) as a filter. The filtering logic will check to see if the filter
+   object has a ``filter`` attribute: if it does, it's assumed to be a
+   ``Filter`` and its :meth:`~Filter.filter` method is called. Otherwise, it's
+   assumed to be a callable and called with the record as the single
+   parameter. The returned value should conform to that returned by
+   :meth:`~Filter.filter`.
 
+Although filters are used primarily to filter records based on more
+sophisticated criteria than levels, they get to see every record which is
+processed by the handler or logger they're attached to: this can be useful if
+you want to do things like counting how many records were processed by a
+particular logger or handler, or adding, changing or removing attributes in
+the LogRecord being processed. Obviously changing the LogRecord needs to be
+done with some care, but it does allow the injection of contextual information
+into logs (see :ref:`filters-contextual`).
 
-See :ref:`library-config` for more information on how to use
-:class:`NullHandler`.
+.. _log-record:
 
-.. _watched-file-handler:
+LogRecord Objects
+-----------------
 
-WatchedFileHandler
-^^^^^^^^^^^^^^^^^^
+:class:`LogRecord` instances are created automatically by the :class:`Logger`
+every time something is logged, and can be created manually via
+:func:`makeLogRecord` (for example, from a pickled event received over the
+wire).
 
-.. currentmodule:: logging.handlers
 
-The :class:`WatchedFileHandler` class, located in the :mod:`logging.handlers`
-module, is a :class:`FileHandler` which watches the file it is logging to. If
-the file changes, it is closed and reopened using the file name.
+.. class:: LogRecord(name, level, pathname, lineno, msg, args, exc_info, func=None, sinfo=None)
 
-A file change can happen because of usage of programs such as *newsyslog* and
-*logrotate* which perform log file rotation. This handler, intended for use
-under Unix/Linux, watches the file to see if it has changed since the last emit.
-(A file is deemed to have changed if its device or inode have changed.) If the
-file has changed, the old file stream is closed, and the file opened to get a
-new stream.
+   Contains all the information pertinent to the event being logged.
 
-This handler is not appropriate for use under Windows, because under Windows
-open log files cannot be moved or renamed - logging opens the files with
-exclusive locks - and so there is no need for such a handler. Furthermore,
-*ST_INO* is not supported under Windows; :func:`stat` always returns zero for
-this value.
+   The primary information is passed in :attr:`msg` and :attr:`args`, which
+   are combined using ``msg % args`` to create the :attr:`message` field of the
+   record.
 
+   :param name:  The name of the logger used to log the event represented by
+                 this LogRecord.
+   :param level: The numeric level of the logging event (one of DEBUG, INFO etc.)
+   :param pathname: The full pathname of the source file where the logging call
+                    was made.
+   :param lineno: The line number in the source file where the logging call was
+                  made.
+   :param msg: The event description message, possibly a format string with
+               placeholders for variable data.
+   :param args: Variable data to merge into the *msg* argument to obtain the
+                event description.
+   :param exc_info: An exception tuple with the current exception information,
+                    or *None* if no exception information is available.
+   :param func: The name of the function or method from which the logging call
+                was invoked.
+   :param sinfo: A text string representing stack information from the base of
+                 the stack in the current thread, up to the logging call.
 
-.. class:: WatchedFileHandler(filename[,mode[, encoding[, delay]]])
+   .. method:: getMessage()
 
-   Returns a new instance of the :class:`WatchedFileHandler` class. The specified
-   file is opened and used as the stream for logging. If *mode* is not specified,
-   :const:`'a'` is used.  If *encoding* is not *None*, it is used to open the file
-   with that encoding.  If *delay* is true, then file opening is deferred until the
-   first call to :meth:`emit`.  By default, the file grows indefinitely.
+      Returns the message for this :class:`LogRecord` instance after merging any
+      user-supplied arguments with the message. If the user-supplied message
+      argument to the logging call is not a string, :func:`str` is called on it to
+      convert it to a string. This allows use of user-defined classes as
+      messages, whose ``__str__`` method can return the actual format string to
+      be used.
 
+   .. versionchanged:: 3.2
+      The creation of a ``LogRecord`` has been made more configurable by
+      providing a factory which is used to create the record. The factory can be
+      set using :func:`getLogRecordFactory` and :func:`setLogRecordFactory`
+      (see this for the factory's signature).
+
+   This functionality can be used to inject your own values into a
+   LogRecord at creation time. You can use the following pattern::
+
+      old_factory = logging.getLogRecordFactory()
+
+      def record_factory(*args, **kwargs):
+          record = old_factory(*args, **kwargs)
+          record.custom_attribute = 0xdecafbad
+          return record
+
+      logging.setLogRecordFactory(record_factory)
+
+   With this pattern, multiple factories could be chained, and as long
+   as they don't overwrite each other's attributes or unintentionally
+   overwrite the standard attributes listed above, there should be no
+   surprises.
+
+
+.. _logrecord-attributes:
+
+LogRecord attributes
+--------------------
+
+The LogRecord has a number of attributes, most of which are derived from the
+parameters to the constructor. (Note that the names do not always correspond
+exactly between the LogRecord constructor parameters and the LogRecord
+attributes.) These attributes can be used to merge data from the record into
+the format string. The following table lists (in alphabetical order) the
+attribute names, their meanings and the corresponding placeholder in a %-style
+format string.
+
+If you are using {}-formatting (:func:`str.format`), you can use
+``{attrname}`` as the placeholder in the format string. If you are using
+$-formatting (:class:`string.Template`), use the form ``${attrname}``. In
+both cases, of course, replace ``attrname`` with the actual attribute name
+you want to use.
+
+In the case of {}-formatting, you can specify formatting flags by placing them
+after the attribute name, separated from it with a colon. For example: a
+placeholder of ``{msecs:03d}`` would format a millisecond value of ``4`` as
+``004``. Refer to the :meth:`str.format` documentation for full details on
+the options available to you.
+
++----------------+-------------------------+-----------------------------------------------+
+| Attribute name | Format                  | Description                                   |
++================+=========================+===============================================+
+| args           | You shouldn't need to   | The tuple of arguments merged into ``msg`` to |
+|                | format this yourself.   | produce ``message``.                          |
++----------------+-------------------------+-----------------------------------------------+
+| asctime        | ``%(asctime)s``         | Human-readable time when the                  |
+|                |                         | :class:`LogRecord` was created.  By default   |
+|                |                         | this is of the form '2003-07-08 16:49:45,896' |
+|                |                         | (the numbers after the comma are millisecond  |
+|                |                         | portion of the time).                         |
++----------------+-------------------------+-----------------------------------------------+
+| created        | ``%(created)f``         | Time when the :class:`LogRecord` was created  |
+|                |                         | (as returned by :func:`time.time`).           |
++----------------+-------------------------+-----------------------------------------------+
+| exc_info       | You shouldn't need to   | Exception tuple (?? la ``sys.exc_info``) or,   |
+|                | format this yourself.   | if no exception has occurred, *None*.         |
++----------------+-------------------------+-----------------------------------------------+
+| filename       | ``%(filename)s``        | Filename portion of ``pathname``.             |
++----------------+-------------------------+-----------------------------------------------+
+| funcName       | ``%(funcName)s``        | Name of function containing the logging call. |
++----------------+-------------------------+-----------------------------------------------+
+| levelname      | ``%(levelname)s``       | Text logging level for the message            |
+|                |                         | (``'DEBUG'``, ``'INFO'``, ``'WARNING'``,      |
+|                |                         | ``'ERROR'``, ``'CRITICAL'``).                 |
++----------------+-------------------------+-----------------------------------------------+
+| levelno        | ``%(levelno)s``         | Numeric logging level for the message         |
+|                |                         | (:const:`DEBUG`, :const:`INFO`,               |
+|                |                         | :const:`WARNING`, :const:`ERROR`,             |
+|                |                         | :const:`CRITICAL`).                           |
++----------------+-------------------------+-----------------------------------------------+
+| lineno         | ``%(lineno)d``          | Source line number where the logging call was |
+|                |                         | issued (if available).                        |
++----------------+-------------------------+-----------------------------------------------+
+| module         | ``%(module)s``          | Module (name portion of ``filename``).        |
++----------------+-------------------------+-----------------------------------------------+
+| msecs          | ``%(msecs)d``           | Millisecond portion of the time when the      |
+|                |                         | :class:`LogRecord` was created.               |
++----------------+-------------------------+-----------------------------------------------+
+| message        | ``%(message)s``         | The logged message, computed as ``msg %       |
+|                |                         | args``. This is set when                      |
+|                |                         | :meth:`Formatter.format` is invoked.          |
++----------------+-------------------------+-----------------------------------------------+
+| msg            | You shouldn't need to   | The format string passed in the original      |
+|                | format this yourself.   | logging call. Merged with ``args`` to         |
+|                |                         | produce ``message``, or an arbitrary object   |
+|                |                         | (see :ref:`arbitrary-object-messages`).       |
++----------------+-------------------------+-----------------------------------------------+
+| name           | ``%(name)s``            | Name of the logger used to log the call.      |
++----------------+-------------------------+-----------------------------------------------+
+| pathname       | ``%(pathname)s``        | Full pathname of the source file where the    |
+|                |                         | logging call was issued (if available).       |
++----------------+-------------------------+-----------------------------------------------+
+| process        | ``%(process)d``         | Process ID (if available).                    |
++----------------+-------------------------+-----------------------------------------------+
+| processName    | ``%(processName)s``     | Process name (if available).                  |
++----------------+-------------------------+-----------------------------------------------+
+| relativeCreated| ``%(relativeCreated)d`` | Time in milliseconds when the LogRecord was   |
+|                |                         | created, relative to the time the logging     |
+|                |                         | module was loaded.                            |
++----------------+-------------------------+-----------------------------------------------+
+| stack_info     | You shouldn't need to   | Stack frame information (where available)     |
+|                | format this yourself.   | from the bottom of the stack in the current   |
+|                |                         | thread, up to and including the stack frame   |
+|                |                         | of the logging call which resulted in the     |
+|                |                         | creation of this record.                      |
++----------------+-------------------------+-----------------------------------------------+
+| thread         | ``%(thread)d``          | Thread ID (if available).                     |
++----------------+-------------------------+-----------------------------------------------+
+| threadName     | ``%(threadName)s``      | Thread name (if available).                   |
++----------------+-------------------------+-----------------------------------------------+
 
-   .. method:: emit(record)
 
-      Outputs the record to the file, but first checks to see if the file has
-      changed.  If it has, the existing stream is flushed and closed and the
-      file opened again, before outputting the record to the file.
+.. _logger-adapter:
 
-.. _rotating-file-handler:
+LoggerAdapter Objects
+---------------------
 
-RotatingFileHandler
-^^^^^^^^^^^^^^^^^^^
+:class:`LoggerAdapter` instances are used to conveniently pass contextual
+information into logging calls. For a usage example , see the section on
+:ref:`adding contextual information to your logging output `.
 
-The :class:`RotatingFileHandler` class, located in the :mod:`logging.handlers`
-module, supports rotation of disk log files.
 
+.. class:: LoggerAdapter(logger, extra)
 
-.. class:: RotatingFileHandler(filename, mode='a', maxBytes=0, backupCount=0, encoding=None, delay=0)
+   Returns an instance of :class:`LoggerAdapter` initialized with an
+   underlying :class:`Logger` instance and a dict-like object.
 
-   Returns a new instance of the :class:`RotatingFileHandler` class. The specified
-   file is opened and used as the stream for logging. If *mode* is not specified,
-   ``'a'`` is used.  If *encoding* is not *None*, it is used to open the file
-   with that encoding.  If *delay* is true, then file opening is deferred until the
-   first call to :meth:`emit`.  By default, the file grows indefinitely.
+   .. method:: process(msg, kwargs)
 
-   You can use the *maxBytes* and *backupCount* values to allow the file to
-   :dfn:`rollover` at a predetermined size. When the size is about to be exceeded,
-   the file is closed and a new file is silently opened for output. Rollover occurs
-   whenever the current log file is nearly *maxBytes* in length; if *maxBytes* is
-   zero, rollover never occurs.  If *backupCount* is non-zero, the system will save
-   old log files by appending the extensions ".1", ".2" etc., to the filename. For
-   example, with a *backupCount* of 5 and a base file name of :file:`app.log`, you
-   would get :file:`app.log`, :file:`app.log.1`, :file:`app.log.2`, up to
-   :file:`app.log.5`. The file being written to is always :file:`app.log`.  When
-   this file is filled, it is closed and renamed to :file:`app.log.1`, and if files
-   :file:`app.log.1`, :file:`app.log.2`, etc.  exist, then they are renamed to
-   :file:`app.log.2`, :file:`app.log.3` etc.  respectively.
+      Modifies the message and/or keyword arguments passed to a logging call in
+      order to insert contextual information. This implementation takes the object
+      passed as *extra* to the constructor and adds it to *kwargs* using key
+      'extra'. The return value is a (*msg*, *kwargs*) tuple which has the
+      (possibly modified) versions of the arguments passed in.
 
+In addition to the above, :class:`LoggerAdapter` supports the following
+methods of :class:`Logger`, i.e. :meth:`debug`, :meth:`info`, :meth:`warning`,
+:meth:`error`, :meth:`exception`, :meth:`critical`, :meth:`log`,
+:meth:`isEnabledFor`, :meth:`getEffectiveLevel`, :meth:`setLevel`,
+:meth:`hasHandlers`. These methods have the same signatures as their
+counterparts in :class:`Logger`, so you can use the two types of instances
+interchangeably.
 
-   .. method:: doRollover()
+.. versionchanged:: 3.2
+   The :meth:`isEnabledFor`, :meth:`getEffectiveLevel`, :meth:`setLevel` and
+   :meth:`hasHandlers` methods were added to :class:`LoggerAdapter`.  These
+   methods delegate to the underlying logger.
 
-      Does a rollover, as described above.
 
+Thread Safety
+-------------
 
-   .. method:: emit(record)
+The logging module is intended to be thread-safe without any special work
+needing to be done by its clients. It achieves this though using threading
+locks; there is one lock to serialize access to the module's shared data, and
+each handler also creates a lock to serialize access to its underlying I/O.
 
-      Outputs the record to the file, catering for rollover as described
-      previously.
+If you are implementing asynchronous signal handlers using the :mod:`signal`
+module, you may not be able to use logging from within such handlers. This is
+because lock implementations in the :mod:`threading` module are not always
+re-entrant, and so cannot be invoked from such signal handlers.
 
-.. _timed-rotating-file-handler:
 
-TimedRotatingFileHandler
-^^^^^^^^^^^^^^^^^^^^^^^^
+Module-Level Functions
+----------------------
 
-The :class:`TimedRotatingFileHandler` class, located in the
-:mod:`logging.handlers` module, supports rotation of disk log files at certain
-timed intervals.
+In addition to the classes described above, there are a number of module- level
+functions.
 
 
-.. class:: TimedRotatingFileHandler(filename, when='h', interval=1, backupCount=0, encoding=None, delay=False, utc=False)
+.. function:: getLogger(name=None)
 
-   Returns a new instance of the :class:`TimedRotatingFileHandler` class. The
-   specified file is opened and used as the stream for logging. On rotating it also
-   sets the filename suffix. Rotating happens based on the product of *when* and
-   *interval*.
+   Return a logger with the specified name or, if name is ``None``, return a
+   logger which is the root logger of the hierarchy. If specified, the name is
+   typically a dot-separated hierarchical name like *'a'*, *'a.b'* or *'a.b.c.d'*.
+   Choice of these names is entirely up to the developer who is using logging.
 
-   You can use the *when* to specify the type of *interval*. The list of possible
-   values is below.  Note that they are not case sensitive.
+   All calls to this function with a given name return the same logger instance.
+   This means that logger instances never need to be passed between different parts
+   of an application.
 
-   +----------------+-----------------------+
-   | Value          | Type of interval      |
-   +================+=======================+
-   | ``'S'``        | Seconds               |
-   +----------------+-----------------------+
-   | ``'M'``        | Minutes               |
-   +----------------+-----------------------+
-   | ``'H'``        | Hours                 |
-   +----------------+-----------------------+
-   | ``'D'``        | Days                  |
-   +----------------+-----------------------+
-   | ``'W'``        | Week day (0=Monday)   |
-   +----------------+-----------------------+
-   | ``'midnight'`` | Roll over at midnight |
-   +----------------+-----------------------+
 
-   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.
+.. function:: getLoggerClass()
 
-   When computing the next rollover time for the first time (when the handler
-   is created), the last modification time of an existing log file, or else
-   the current time, is used to compute when the next rotation will occur.
+   Return either the standard :class:`Logger` class, or the last class passed to
+   :func:`setLoggerClass`. This function may be called from within a new class
+   definition, to ensure that installing a customised :class:`Logger` class will
+   not undo customisations already applied by other code. For example::
 
-   If the *utc* argument is true, times in UTC will be used; otherwise
-   local time is used.
+      class MyLogger(logging.getLoggerClass()):
+          # ... override behaviour here
 
-   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.
 
-   If *delay* is true, then file opening is deferred until the first call to
-   :meth:`emit`.
+.. function:: getLogRecordFactory()
 
+   Return a callable which is used to create a :class:`LogRecord`.
 
-   .. method:: doRollover()
+   .. versionadded:: 3.2
+      This function has been provided, along with :func:`setLogRecordFactory`,
+      to allow developers more control over how the :class:`LogRecord`
+      representing a logging event is constructed.
 
-      Does a rollover, as described above.
+   See :func:`setLogRecordFactory` for more information about the how the
+   factory is called.
 
+.. function:: debug(msg, *args, **kwargs)
 
-   .. method:: emit(record)
+   Logs a message with level :const:`DEBUG` on the root logger. The *msg* is the
+   message format string, and the *args* are the arguments which are merged into
+   *msg* using the string formatting operator. (Note that this means that you can
+   use keywords in the format string, together with a single dictionary argument.)
 
-      Outputs the record to the file, catering for rollover as described above.
+   There are three keyword arguments in *kwargs* which are inspected: *exc_info*
+   which, if it does not evaluate as false, causes exception information to be
+   added to the logging message. If an exception tuple (in the format returned by
+   :func:`sys.exc_info`) is provided, it is used; otherwise, :func:`sys.exc_info`
+   is called to get the exception information.
 
+   The second optional keyword argument is *stack_info*, which defaults to
+   False. If specified as True, stack information is added to the logging
+   message, including the actual logging call. Note that this is not the same
+   stack information as that displayed through specifying *exc_info*: The
+   former is stack frames from the bottom of the stack up to the logging call
+   in the current thread, whereas the latter is information about stack frames
+   which have been unwound, following an exception, while searching for
+   exception handlers.
 
-.. _socket-handler:
+   You can specify *stack_info* independently of *exc_info*, e.g. to just show
+   how you got to a certain point in your code, even when no exceptions were
+   raised. The stack frames are printed following a header line which says::
 
-SocketHandler
-^^^^^^^^^^^^^
+       Stack (most recent call last):
 
-The :class:`SocketHandler` class, located in the :mod:`logging.handlers` module,
-sends logging output to a network socket. The base class uses a TCP socket.
+   This mimics the `Traceback (most recent call last):` which is used when
+   displaying exception frames.
 
+   The third optional keyword argument is *extra* which can be used to pass a
+   dictionary which is used to populate the __dict__ of the LogRecord created for
+   the logging event with user-defined attributes. These custom attributes can then
+   be used as you like. For example, they could be incorporated into logged
+   messages. For example::
 
-.. class:: SocketHandler(host, port)
+      FORMAT = '%(asctime)-15s %(clientip)s %(user)-8s %(message)s'
+      logging.basicConfig(format=FORMAT)
+      d = {'clientip': '192.168.0.1', 'user': 'fbloggs'}
+      logging.warning('Protocol problem: %s', 'connection reset', extra=d)
 
-   Returns a new instance of the :class:`SocketHandler` class intended to
-   communicate with a remote machine whose address is given by *host* and *port*.
+   would print something like::
 
+      2006-02-08 22:20:02,165 192.168.0.1 fbloggs  Protocol problem: connection reset
 
-   .. method:: close()
+   The keys in the dictionary passed in *extra* should not clash with the keys used
+   by the logging system. (See the :class:`Formatter` documentation for more
+   information on which keys are used by the logging system.)
 
-      Closes the socket.
+   If you choose to use these attributes in logged messages, you need to exercise
+   some care. In the above example, for instance, the :class:`Formatter` has been
+   set up with a format string which expects 'clientip' and 'user' in the attribute
+   dictionary of the LogRecord. If these are missing, the message will not be
+   logged because a string formatting exception will occur. So in this case, you
+   always need to pass the *extra* dictionary with these keys.
 
+   While this might be annoying, this feature is intended for use in specialized
+   circumstances, such as multi-threaded servers where the same code executes in
+   many contexts, and interesting conditions which arise are dependent on this
+   context (such as remote client IP address and authenticated user name, in the
+   above example). In such circumstances, it is likely that specialized
+   :class:`Formatter`\ s would be used with particular :class:`Handler`\ s.
 
-   .. method:: emit()
+   .. versionadded:: 3.2
+      The *stack_info* parameter was added.
 
-      Pickles the record's attribute dictionary and writes it to the socket in
-      binary format. If there is an error with the socket, silently drops the
-      packet. If the connection was previously lost, re-establishes the
-      connection. To unpickle the record at the receiving end into a
-      :class:`LogRecord`, use the :func:`makeLogRecord` function.
+.. function:: info(msg, *args, **kwargs)
 
+   Logs a message with level :const:`INFO` on the root logger. The arguments are
+   interpreted as for :func:`debug`.
 
-   .. method:: handleError()
 
-      Handles an error which has occurred during :meth:`emit`. The most likely
-      cause is a lost connection. Closes the socket so that we can retry on the
-      next event.
+.. function:: warning(msg, *args, **kwargs)
 
+   Logs a message with level :const:`WARNING` on the root logger. The arguments are
+   interpreted as for :func:`debug`.
 
-   .. method:: makeSocket()
 
-      This is a factory method which allows subclasses to define the precise
-      type of socket they want. The default implementation creates a TCP socket
-      (:const:`socket.SOCK_STREAM`).
+.. function:: error(msg, *args, **kwargs)
 
+   Logs a message with level :const:`ERROR` on the root logger. The arguments are
+   interpreted as for :func:`debug`.
 
-   .. method:: makePickle(record)
 
-      Pickles the record's attribute dictionary in binary format with a length
-      prefix, and returns it ready for transmission across the socket.
+.. function:: critical(msg, *args, **kwargs)
 
-      Note that pickles aren't completely secure. If you are concerned about
-      security, you may want to override this method to implement a more secure
-      mechanism. For example, you can sign pickles using HMAC and then verify
-      them on the receiving end, or alternatively you can disable unpickling of
-      global objects on the receiving end.
+   Logs a message with level :const:`CRITICAL` on the root logger. The arguments
+   are interpreted as for :func:`debug`.
 
-   .. method:: send(packet)
 
-      Send a pickled string *packet* to the socket. This function allows for
-      partial sends which can happen when the network is busy.
+.. function:: exception(msg, *args)
 
+   Logs a message with level :const:`ERROR` on the root logger. The arguments are
+   interpreted as for :func:`debug`. Exception info is added to the logging
+   message. This function should only be called from an exception handler.
 
-.. _datagram-handler:
+.. function:: log(level, msg, *args, **kwargs)
 
-DatagramHandler
-^^^^^^^^^^^^^^^
+   Logs a message with level *level* on the root logger. The other arguments are
+   interpreted as for :func:`debug`.
 
-The :class:`DatagramHandler` class, located in the :mod:`logging.handlers`
-module, inherits from :class:`SocketHandler` to support sending logging messages
-over UDP sockets.
+   PLEASE NOTE: The above module-level functions which delegate to the root
+   logger should *not* be used in threads, in versions of Python earlier than
+   2.7.1 and 3.2, unless at least one handler has been added to the root
+   logger *before* the threads are started. These convenience functions call
+   :func:`basicConfig` to ensure that at least one handler is available; in
+   earlier versions of Python, this can (under rare circumstances) lead to
+   handlers being added multiple times to the root logger, which can in turn
+   lead to multiple messages for the same event.
 
+.. function:: disable(lvl)
 
-.. class:: DatagramHandler(host, port)
+   Provides an overriding level *lvl* for all loggers which takes precedence over
+   the logger's own level. When the need arises to temporarily throttle logging
+   output down across the whole application, this function can be useful. Its
+   effect is to disable all logging calls of severity *lvl* and below, so that
+   if you call it with a value of INFO, then all INFO and DEBUG events would be
+   discarded, whereas those of severity WARNING and above would be processed
+   according to the logger's effective level.
 
-   Returns a new instance of the :class:`DatagramHandler` class intended to
-   communicate with a remote machine whose address is given by *host* and *port*.
 
+.. function:: addLevelName(lvl, levelName)
 
-   .. method:: emit()
+   Associates level *lvl* with text *levelName* in an internal dictionary, which is
+   used to map numeric levels to a textual representation, for example when a
+   :class:`Formatter` formats a message. This function can also be used to define
+   your own levels. The only constraints are that all levels used must be
+   registered using this function, levels should be positive integers and they
+   should increase in increasing order of severity.
 
-      Pickles the record's attribute dictionary and writes it to the socket in
-      binary format. If there is an error with the socket, silently drops the
-      packet. To unpickle the record at the receiving end into a
-      :class:`LogRecord`, use the :func:`makeLogRecord` function.
+   NOTE: If you are thinking of defining your own levels, please see the section
+   on :ref:`custom-levels`.
 
+.. function:: getLevelName(lvl)
 
-   .. method:: makeSocket()
+   Returns the textual representation of logging level *lvl*. If the level is one
+   of the predefined levels :const:`CRITICAL`, :const:`ERROR`, :const:`WARNING`,
+   :const:`INFO` or :const:`DEBUG` then you get the corresponding string. If you
+   have associated levels with names using :func:`addLevelName` then the name you
+   have associated with *lvl* is returned. If a numeric value corresponding to one
+   of the defined levels is passed in, the corresponding string representation is
+   returned. Otherwise, the string 'Level %s' % lvl is returned.
 
-      The factory method of :class:`SocketHandler` is here overridden to create
-      a UDP socket (:const:`socket.SOCK_DGRAM`).
 
+.. function:: makeLogRecord(attrdict)
 
-   .. method:: send(s)
+   Creates and returns a new :class:`LogRecord` instance whose attributes are
+   defined by *attrdict*. This function is useful for taking a pickled
+   :class:`LogRecord` attribute dictionary, sent over a socket, and reconstituting
+   it as a :class:`LogRecord` instance at the receiving end.
 
-      Send a pickled string to a socket.
 
+.. function:: basicConfig(**kwargs)
 
-.. _syslog-handler:
-
-SysLogHandler
-^^^^^^^^^^^^^
-
-The :class:`SysLogHandler` class, located in the :mod:`logging.handlers` module,
-supports sending logging messages to a remote or local Unix syslog.
+   Does basic configuration for the logging system by creating a
+   :class:`StreamHandler` with a default :class:`Formatter` and adding it to the
+   root logger. The functions :func:`debug`, :func:`info`, :func:`warning`,
+   :func:`error` and :func:`critical` will call :func:`basicConfig` automatically
+   if no handlers are defined for the root logger.
 
+   This function does nothing if the root logger already has handlers
+   configured for it.
 
-.. class:: SysLogHandler(address=('localhost', SYSLOG_UDP_PORT), facility=LOG_USER, socktype=socket.SOCK_DGRAM)
+   PLEASE NOTE: This function should be called from the main thread
+   before other threads are started. In versions of Python prior to
+   2.7.1 and 3.2, if this function is called from multiple threads,
+   it is possible (in rare circumstances) that a handler will be added
+   to the root logger more than once, leading to unexpected results
+   such as messages being duplicated in the log.
 
-   Returns a new instance of the :class:`SysLogHandler` class intended to
-   communicate with a remote Unix machine whose address is given by *address* in
-   the form of a ``(host, port)`` tuple.  If *address* is not specified,
-   ``('localhost', 514)`` is used.  The address is used to open a socket.  An
-   alternative to providing a ``(host, port)`` tuple is providing an address as a
-   string, for example "/dev/log". In this case, a Unix domain socket is used to
-   send the message to the syslog. If *facility* is not specified,
-   :const:`LOG_USER` is used. The type of socket opened depends on the
-   *socktype* argument, which defaults to :const:`socket.SOCK_DGRAM` and thus
-   opens a UDP socket. To open a TCP socket (for use with the newer syslog
-   daemons such as rsyslog), specify a value of :const:`socket.SOCK_STREAM`.
+   The following keyword arguments are supported.
 
-   Note that if your server is not listening on UDP port 514,
-   :class:`SysLogHandler` may appear not to work. In that case, check what
-   address you should be using for a domain socket - it's system dependent.
-   For example, on Linux it's usually "/dev/log" but on OS/X it's
-   "/var/run/syslog". You'll need to check your platform and use the
-   appropriate address (you may need to do this check at runtime if your
-   application needs to run on several platforms). On Windows, you pretty
-   much have to use the UDP option.
+   +--------------+---------------------------------------------+
+   | Format       | Description                                 |
+   +==============+=============================================+
+   | ``filename`` | Specifies that a FileHandler be created,    |
+   |              | using the specified filename, rather than a |
+   |              | StreamHandler.                              |
+   +--------------+---------------------------------------------+
+   | ``filemode`` | Specifies the mode to open the file, if     |
+   |              | filename is specified (if filemode is       |
+   |              | unspecified, it defaults to 'a').           |
+   +--------------+---------------------------------------------+
+   | ``format``   | Use the specified format string for the     |
+   |              | handler.                                    |
+   +--------------+---------------------------------------------+
+   | ``datefmt``  | Use the specified date/time format.         |
+   +--------------+---------------------------------------------+
+   | ``style``    | If ``format`` is specified, use this style  |
+   |              | for the format string. One of '%', '{' or   |
+   |              | '$' for %-formatting, :meth:`str.format` or |
+   |              | :class:`string.Template` respectively, and  |
+   |              | defaulting to '%' if not specified.         |
+   +--------------+---------------------------------------------+
+   | ``level``    | Set the root logger level to the specified  |
+   |              | level.                                      |
+   +--------------+---------------------------------------------+
+   | ``stream``   | Use the specified stream to initialize the  |
+   |              | StreamHandler. Note that this argument is   |
+   |              | incompatible with 'filename' - if both are  |
+   |              | present, 'stream' is ignored.               |
+   +--------------+---------------------------------------------+
 
    .. versionchanged:: 3.2
-      *socktype* was added.
-
-
-   .. method:: close()
-
-      Closes the socket to the remote host.
-
-
-   .. method:: emit(record)
-
-      The record is formatted, and then sent to the syslog server. If exception
-      information is present, it is *not* sent to the server.
-
-
-   .. method:: encodePriority(facility, priority)
-
-      Encodes the facility and priority into an integer. You can pass in strings
-      or integers - if strings are passed, internal mapping dictionaries are
-      used to convert them to integers.
-
-      The symbolic ``LOG_`` values are defined in :class:`SysLogHandler` and
-      mirror the values defined in the ``sys/syslog.h`` header file.
-
-      **Priorities**
-
-      +--------------------------+---------------+
-      | Name (string)            | Symbolic value|
-      +==========================+===============+
-      | ``alert``                | LOG_ALERT     |
-      +--------------------------+---------------+
-      | ``crit`` or ``critical`` | LOG_CRIT      |
-      +--------------------------+---------------+
-      | ``debug``                | LOG_DEBUG     |
-      +--------------------------+---------------+
-      | ``emerg`` or ``panic``   | LOG_EMERG     |
-      +--------------------------+---------------+
-      | ``err`` or ``error``     | LOG_ERR       |
-      +--------------------------+---------------+
-      | ``info``                 | LOG_INFO      |
-      +--------------------------+---------------+
-      | ``notice``               | LOG_NOTICE    |
-      +--------------------------+---------------+
-      | ``warn`` or ``warning``  | LOG_WARNING   |
-      +--------------------------+---------------+
-
-      **Facilities**
-
-      +---------------+---------------+
-      | Name (string) | Symbolic value|
-      +===============+===============+
-      | ``auth``      | LOG_AUTH      |
-      +---------------+---------------+
-      | ``authpriv``  | LOG_AUTHPRIV  |
-      +---------------+---------------+
-      | ``cron``      | LOG_CRON      |
-      +---------------+---------------+
-      | ``daemon``    | LOG_DAEMON    |
-      +---------------+---------------+
-      | ``ftp``       | LOG_FTP       |
-      +---------------+---------------+
-      | ``kern``      | LOG_KERN      |
-      +---------------+---------------+
-      | ``lpr``       | LOG_LPR       |
-      +---------------+---------------+
-      | ``mail``      | LOG_MAIL      |
-      +---------------+---------------+
-      | ``news``      | LOG_NEWS      |
-      +---------------+---------------+
-      | ``syslog``    | LOG_SYSLOG    |
-      +---------------+---------------+
-      | ``user``      | LOG_USER      |
-      +---------------+---------------+
-      | ``uucp``      | LOG_UUCP      |
-      +---------------+---------------+
-      | ``local0``    | LOG_LOCAL0    |
-      +---------------+---------------+
-      | ``local1``    | LOG_LOCAL1    |
-      +---------------+---------------+
-      | ``local2``    | LOG_LOCAL2    |
-      +---------------+---------------+
-      | ``local3``    | LOG_LOCAL3    |
-      +---------------+---------------+
-      | ``local4``    | LOG_LOCAL4    |
-      +---------------+---------------+
-      | ``local5``    | LOG_LOCAL5    |
-      +---------------+---------------+
-      | ``local6``    | LOG_LOCAL6    |
-      +---------------+---------------+
-      | ``local7``    | LOG_LOCAL7    |
-      +---------------+---------------+
-
-   .. method:: mapPriority(levelname)
-
-      Maps a logging level name to a syslog priority name.
-      You may need to override this if you are using custom levels, or
-      if the default algorithm is not suitable for your needs. The
-      default algorithm maps ``DEBUG``, ``INFO``, ``WARNING``, ``ERROR`` and
-      ``CRITICAL`` to the equivalent syslog names, and all other level
-      names to "warning".
-
-.. _nt-eventlog-handler:
-
-NTEventLogHandler
-^^^^^^^^^^^^^^^^^
-
-The :class:`NTEventLogHandler` class, located in the :mod:`logging.handlers`
-module, supports sending logging messages to a local Windows NT, Windows 2000 or
-Windows XP event log. Before you can use it, you need Mark Hammond's Win32
-extensions for Python installed.
-
-
-.. class:: NTEventLogHandler(appname, dllname=None, logtype='Application')
-
-   Returns a new instance of the :class:`NTEventLogHandler` class. The *appname* is
-   used to define the application name as it appears in the event log. An
-   appropriate registry entry is created using this name. The *dllname* should give
-   the fully qualified pathname of a .dll or .exe which contains message
-   definitions to hold in the log (if not specified, ``'win32service.pyd'`` is used
-   - this is installed with the Win32 extensions and contains some basic
-   placeholder message definitions. Note that use of these placeholders will make
-   your event logs big, as the entire message source is held in the log. If you
-   want slimmer logs, you have to pass in the name of your own .dll or .exe which
-   contains the message definitions you want to use in the event log). The
-   *logtype* is one of ``'Application'``, ``'System'`` or ``'Security'``, and
-   defaults to ``'Application'``.
-
-
-   .. method:: close()
-
-      At this point, you can remove the application name from the registry as a
-      source of event log entries. However, if you do this, you will not be able
-      to see the events as you intended in the Event Log Viewer - it needs to be
-      able to access the registry to get the .dll name. The current version does
-      not do this.
-
-
-   .. method:: emit(record)
-
-      Determines the message ID, event category and event type, and then logs
-      the message in the NT event log.
-
-
-   .. method:: getEventCategory(record)
-
-      Returns the event category for the record. Override this if you want to
-      specify your own categories. This version returns 0.
-
-
-   .. method:: getEventType(record)
-
-      Returns the event type for the record. Override this if you want to
-      specify your own types. This version does a mapping using the handler's
-      typemap attribute, which is set up in :meth:`__init__` to a dictionary
-      which contains mappings for :const:`DEBUG`, :const:`INFO`,
-      :const:`WARNING`, :const:`ERROR` and :const:`CRITICAL`. If you are using
-      your own levels, you will either need to override this method or place a
-      suitable dictionary in the handler's *typemap* attribute.
-
-
-   .. method:: getMessageID(record)
-
-      Returns the message ID for the record. If you are using your own messages,
-      you could do this by having the *msg* passed to the logger being an ID
-      rather than a format string. Then, in here, you could use a dictionary
-      lookup to get the message ID. This version returns 1, which is the base
-      message ID in :file:`win32service.pyd`.
-
-.. _smtp-handler:
-
-SMTPHandler
-^^^^^^^^^^^
-
-The :class:`SMTPHandler` class, located in the :mod:`logging.handlers` module,
-supports sending logging messages to an email address via SMTP.
-
-
-.. class:: SMTPHandler(mailhost, fromaddr, toaddrs, subject, credentials=None)
-
-   Returns a new instance of the :class:`SMTPHandler` class. The instance is
-   initialized with the from and to addresses and subject line of the email. The
-   *toaddrs* should be a list of strings. To specify a non-standard SMTP port, use
-   the (host, port) tuple format for the *mailhost* argument. If you use a string,
-   the standard SMTP port is used. If your SMTP server requires authentication, you
-   can specify a (username, password) tuple for the *credentials* argument.
-
-
-   .. method:: emit(record)
-
-      Formats the record and sends it to the specified addressees.
-
-
-   .. method:: getSubject(record)
-
-      If you want to specify a subject line which is record-dependent, override
-      this method.
-
-.. _memory-handler:
-
-MemoryHandler
-^^^^^^^^^^^^^
-
-The :class:`MemoryHandler` class, located in the :mod:`logging.handlers` module,
-supports buffering of logging records in memory, periodically flushing them to a
-:dfn:`target` handler. Flushing occurs whenever the buffer is full, or when an
-event of a certain severity or greater is seen.
-
-:class:`MemoryHandler` is a subclass of the more general
-:class:`BufferingHandler`, which is an abstract class. This buffers logging
-records in memory. Whenever each record is added to the buffer, a check is made
-by calling :meth:`shouldFlush` to see if the buffer should be flushed.  If it
-should, then :meth:`flush` is expected to do the needful.
-
-
-.. class:: BufferingHandler(capacity)
-
-   Initializes the handler with a buffer of the specified capacity.
-
-
-   .. method:: emit(record)
-
-      Appends the record to the buffer. If :meth:`shouldFlush` returns true,
-      calls :meth:`flush` to process the buffer.
-
-
-   .. method:: flush()
-
-      You can override this to implement custom flushing behavior. This version
-      just zaps the buffer to empty.
-
-
-   .. method:: shouldFlush(record)
-
-      Returns true if the buffer is up to capacity. This method can be
-      overridden to implement custom flushing strategies.
-
-
-.. class:: MemoryHandler(capacity, flushLevel=ERROR, target=None)
-
-   Returns a new instance of the :class:`MemoryHandler` class. The instance is
-   initialized with a buffer size of *capacity*. If *flushLevel* is not specified,
-   :const:`ERROR` is used. If no *target* is specified, the target will need to be
-   set using :meth:`setTarget` before this handler does anything useful.
-
-
-   .. method:: close()
-
-      Calls :meth:`flush`, sets the target to :const:`None` and clears the
-      buffer.
-
-
-   .. method:: flush()
-
-      For a :class:`MemoryHandler`, flushing means just sending the buffered
-      records to the target, if there is one. The buffer is also cleared when
-      this happens. Override if you want different behavior.
-
-
-   .. method:: setTarget(target)
-
-      Sets the target handler for this handler.
-
-
-   .. method:: shouldFlush(record)
-
-      Checks for buffer full or a record at the *flushLevel* or higher.
-
-
-.. _http-handler:
-
-HTTPHandler
-^^^^^^^^^^^
-
-The :class:`HTTPHandler` class, located in the :mod:`logging.handlers` module,
-supports sending logging messages to a Web server, using either ``GET`` or
-``POST`` semantics.
-
-
-.. class:: HTTPHandler(host, url, method='GET', secure=False, credentials=None)
-
-   Returns a new instance of the :class:`HTTPHandler` class. The *host* can be
-   of the form ``host:port``, should you need to use a specific port number.
-   If no *method* is specified, ``GET`` is used. If *secure* is True, an HTTPS
-   connection will be used. If *credentials* is specified, it should be a
-   2-tuple consisting of userid and password, which will be placed in an HTTP
-   'Authorization' header using Basic authentication. If you specify
-   credentials, you should also specify secure=True so that your userid and
-   password are not passed in cleartext across the wire.
-
-
-   .. method:: emit(record)
-
-      Sends the record to the Web server as a percent-encoded dictionary.
-
-
-.. _queue-handler:
-
-
-QueueHandler
-^^^^^^^^^^^^
-
-The :class:`QueueHandler` class, located in the :mod:`logging.handlers` module,
-supports sending logging messages to a queue, such as those implemented in the
-:mod:`queue` or :mod:`multiprocessing` modules.
-
-Along with the :class:`QueueListener` class, :class:`QueueHandler` can be used
-to let handlers do their work on a separate thread from the one which does the
-logging. This is important in Web applications and also other service
-applications where threads servicing clients need to respond as quickly as
-possible, while any potentially slow operations (such as sending an email via
-:class:`SMTPHandler`) are done on a separate thread.
-
-.. class:: QueueHandler(queue)
-
-   Returns a new instance of the :class:`QueueHandler` class. The instance is
-   initialized with the queue to send messages to. The queue can be any queue-
-   like object; it's used as-is by the :meth:`enqueue` method, which needs
-   to know how to send messages to it.
-
-
-   .. method:: emit(record)
-
-      Enqueues the result of preparing the LogRecord.
-
-   .. method:: prepare(record)
-
-      Prepares a record for queuing. The object returned by this
-      method is enqueued.
-
-      The base implementation formats the record to merge the message
-      and arguments, and removes unpickleable items from the record
-      in-place.
-
-      You might want to override this method if you want to convert
-      the record to a dict or JSON string, or send a modified copy
-      of the record while leaving the original intact.
-
-   .. method:: enqueue(record)
-
-      Enqueues the record on the queue using ``put_nowait()``; you may
-      want to override this if you want to use blocking behaviour, or a
-      timeout, or a customised queue implementation.
-
-
-.. versionadded:: 3.2
-
-The :class:`QueueHandler` class was not present in previous versions.
-
-.. queue-listener:
-
-QueueListener
-^^^^^^^^^^^^^
-
-The :class:`QueueListener` class, located in the :mod:`logging.handlers`
-module, supports receiving logging messages from a queue, such as those
-implemented in the :mod:`queue` or :mod:`multiprocessing` modules. The
-messages are received from a queue in an internal thread and passed, on
-the same thread, to one or more handlers for processing.
-
-Along with the :class:`QueueHandler` class, :class:`QueueListener` can be used
-to let handlers do their work on a separate thread from the one which does the
-logging. This is important in Web applications and also other service
-applications where threads servicing clients need to respond as quickly as
-possible, while any potentially slow operations (such as sending an email via
-:class:`SMTPHandler`) are done on a separate thread.
-
-.. class:: QueueListener(queue, *handlers)
-
-   Returns a new instance of the :class:`QueueListener` class. The instance is
-   initialized with the queue to send messages to and a list of handlers which
-   will handle entries placed on the queue. The queue can be any queue-
-   like object; it's passed as-is to the :meth:`dequeue` method, which needs
-   to know how to get messages from it.
-
-   .. method:: dequeue(block)
-
-      Dequeues a record and return it, optionally blocking.
-
-      The base implementation uses ``get()``. You may want to override this
-      method if you want to use timeouts or work with custom queue
-      implementations.
-
-   .. method:: prepare(record)
-
-      Prepare a record for handling.
-
-      This implementation just returns the passed-in record. You may want to
-      override this method if you need to do any custom marshalling or
-      manipulation of the record before passing it to the handlers.
-
-   .. method:: handle(record)
-
-      Handle a record.
-
-      This just loops through the handlers offering them the record
-      to handle. The actual object passed to the handlers is that which
-      is returned from :meth:`prepare`.
-
-   .. method:: start()
-
-      Starts the listener.
-
-      This starts up a background thread to monitor the queue for
-      LogRecords to process.
-
-   .. method:: stop()
-
-      Stops the listener.
-
-      This asks the thread to terminate, and then waits for it to do so.
-      Note that if you don't call this before your application exits, there
-      may be some records still left on the queue, which won't be processed.
-
-.. versionadded:: 3.2
-
-The :class:`QueueListener` class was not present in previous versions.
-
-.. _zeromq-handlers:
-
-Subclassing QueueHandler
-^^^^^^^^^^^^^^^^^^^^^^^^
-
-You can use a :class:`QueueHandler` subclass to send messages to other kinds
-of queues, for example a ZeroMQ "publish" socket. In the example below,the
-socket is created separately and passed to the handler (as its 'queue')::
-
-    import zmq # using pyzmq, the Python binding for ZeroMQ
-    import json # for serializing records portably
-
-    ctx = zmq.Context()
-    sock = zmq.Socket(ctx, zmq.PUB) # or zmq.PUSH, or other suitable value
-    sock.bind('tcp://*:5556') # or wherever
-
-    class ZeroMQSocketHandler(QueueHandler):
-        def enqueue(self, record):
-            data = json.dumps(record.__dict__)
-            self.queue.send(data)
-
-    handler = ZeroMQSocketHandler(sock)
-
-
-Of course there are other ways of organizing this, for example passing in the
-data needed by the handler to create the socket::
-
-    class ZeroMQSocketHandler(QueueHandler):
-        def __init__(self, uri, socktype=zmq.PUB, ctx=None):
-            self.ctx = ctx or zmq.Context()
-            socket = zmq.Socket(self.ctx, socktype)
-            socket.bind(uri)
-            QueueHandler.__init__(self, socket)
-
-        def enqueue(self, record):
-            data = json.dumps(record.__dict__)
-            self.queue.send(data)
-
-        def close(self):
-            self.queue.close()
-
-Subclassing QueueListener
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-You can also subclass :class:`QueueListener` to get messages from other kinds
-of queues, for example a ZeroMQ "subscribe" socket. Here's an example::
-
-    class ZeroMQSocketListener(QueueListener):
-        def __init__(self, uri, *handlers, **kwargs):
-            self.ctx = kwargs.get('ctx') or zmq.Context()
-            socket = zmq.Socket(self.ctx, zmq.SUB)
-            socket.setsockopt(zmq.SUBSCRIBE, '') # subscribe to everything
-            socket.connect(uri)
-
-        def dequeue(self):
-            msg = self.queue.recv()
-            return logging.makeLogRecord(json.loads(msg))
-
-.. _formatter-objects:
-
-Formatter Objects
------------------
-
-.. currentmodule:: logging
-
-:class:`Formatter`\ s have the following attributes and methods. They are
-responsible for converting a :class:`LogRecord` to (usually) a string which can
-be interpreted by either a human or an external system. The base
-:class:`Formatter` allows a formatting string to be specified. If none is
-supplied, the default value of ``'%(message)s'`` is used.
-
-A Formatter can be initialized with a format string which makes use of knowledge
-of the :class:`LogRecord` attributes - such as the default value mentioned above
-making use of the fact that the user's message and arguments are pre-formatted
-into a :class:`LogRecord`'s *message* attribute.  This format string contains
-standard Python %-style mapping keys. See section :ref:`old-string-formatting`
-for more information on string formatting.
-
-Currently, the useful mapping keys in a :class:`LogRecord` are:
-
-+-------------------------+-----------------------------------------------+
-| Format                  | Description                                   |
-+=========================+===============================================+
-| ``%(name)s``            | Name of the logger (logging channel).         |
-+-------------------------+-----------------------------------------------+
-| ``%(levelno)s``         | Numeric logging level for the message         |
-|                         | (:const:`DEBUG`, :const:`INFO`,               |
-|                         | :const:`WARNING`, :const:`ERROR`,             |
-|                         | :const:`CRITICAL`).                           |
-+-------------------------+-----------------------------------------------+
-| ``%(levelname)s``       | Text logging level for the message            |
-|                         | (``'DEBUG'``, ``'INFO'``, ``'WARNING'``,      |
-|                         | ``'ERROR'``, ``'CRITICAL'``).                 |
-+-------------------------+-----------------------------------------------+
-| ``%(pathname)s``        | Full pathname of the source file where the    |
-|                         | logging call was issued (if available).       |
-+-------------------------+-----------------------------------------------+
-| ``%(filename)s``        | Filename portion of pathname.                 |
-+-------------------------+-----------------------------------------------+
-| ``%(module)s``          | Module (name portion of filename).            |
-+-------------------------+-----------------------------------------------+
-| ``%(funcName)s``        | Name of function containing the logging call. |
-+-------------------------+-----------------------------------------------+
-| ``%(lineno)d``          | Source line number where the logging call was |
-|                         | issued (if available).                        |
-+-------------------------+-----------------------------------------------+
-| ``%(created)f``         | Time when the :class:`LogRecord` was created  |
-|                         | (as returned by :func:`time.time`).           |
-+-------------------------+-----------------------------------------------+
-| ``%(relativeCreated)d`` | Time in milliseconds when the LogRecord was   |
-|                         | created, relative to the time the logging     |
-|                         | module was loaded.                            |
-+-------------------------+-----------------------------------------------+
-| ``%(asctime)s``         | Human-readable time when the                  |
-|                         | :class:`LogRecord` was created.  By default   |
-|                         | this is of the form "2003-07-08 16:49:45,896" |
-|                         | (the numbers after the comma are millisecond  |
-|                         | portion of the time).                         |
-+-------------------------+-----------------------------------------------+
-| ``%(msecs)d``           | Millisecond portion of the time when the      |
-|                         | :class:`LogRecord` was created.               |
-+-------------------------+-----------------------------------------------+
-| ``%(thread)d``          | Thread ID (if available).                     |
-+-------------------------+-----------------------------------------------+
-| ``%(threadName)s``      | Thread name (if available).                   |
-+-------------------------+-----------------------------------------------+
-| ``%(process)d``         | Process ID (if available).                    |
-+-------------------------+-----------------------------------------------+
-| ``%(processName)s``     | Process name (if available).                  |
-+-------------------------+-----------------------------------------------+
-| ``%(message)s``         | The logged message, computed as ``msg %       |
-|                         | args``.                                       |
-+-------------------------+-----------------------------------------------+
-
-
-.. class:: Formatter(fmt=None, datefmt=None)
-
-   Returns a new instance of the :class:`Formatter` class.  The instance is
-   initialized with a format string for the message as a whole, as well as a
-   format string for the date/time portion of a message.  If no *fmt* is
-   specified, ``'%(message)s'`` is used.  If no *datefmt* is specified, the
-   ISO8601 date format is used.
-
-   .. method:: format(record)
-
-      The record's attribute dictionary is used as the operand to a string
-      formatting operation. Returns the resulting string. Before formatting the
-      dictionary, a couple of preparatory steps are carried out. The *message*
-      attribute of the record is computed using *msg* % *args*. If the
-      formatting string contains ``'(asctime)'``, :meth:`formatTime` is called
-      to format the event time. If there is exception information, it is
-      formatted using :meth:`formatException` and appended to the message. Note
-      that the formatted exception information is cached in attribute
-      *exc_text*. This is useful because the exception information can be
-      pickled and sent across the wire, but you should be careful if you have
-      more than one :class:`Formatter` subclass which customizes the formatting
-      of exception information. In this case, you will have to clear the cached
-      value after a formatter has done its formatting, so that the next
-      formatter to handle the event doesn't use the cached value but
-      recalculates it afresh.
-
-      If stack information is available, it's appended after the exception
-      information, using :meth:`formatStack` to transform it if necessary.
-
-
-   .. method:: formatTime(record, datefmt=None)
-
-      This method should be called from :meth:`format` by a formatter which
-      wants to make use of a formatted time. This method can be overridden in
-      formatters to provide for any specific requirement, but the basic behavior
-      is as follows: if *datefmt* (a string) is specified, it is used with
-      :func:`time.strftime` to format the creation time of the
-      record. Otherwise, the ISO8601 format is used.  The resulting string is
-      returned.
-
-
-   .. method:: formatException(exc_info)
-
-      Formats the specified exception information (a standard exception tuple as
-      returned by :func:`sys.exc_info`) as a string. This default implementation
-      just uses :func:`traceback.print_exception`. The resulting string is
-      returned.
-
-   .. method:: formatStack(stack_info)
-
-      Formats the specified stack information (a string as returned by
-      :func:`traceback.print_stack`, but with the last newline removed) as a
-      string. This default implementation just returns the input value.
-
-.. _filter:
-
-Filter Objects
---------------
-
-``Filters`` can be used by ``Handlers`` and ``Loggers`` for more sophisticated
-filtering than is provided by levels. The base filter class only allows events
-which are below a certain point in the logger hierarchy. For example, a filter
-initialized with "A.B" will allow events logged by loggers "A.B", "A.B.C",
-"A.B.C.D", "A.B.D" etc. but not "A.BB", "B.A.B" etc. If initialized with the
-empty string, all events are passed.
-
-
-.. class:: Filter(name='')
-
-   Returns an instance of the :class:`Filter` class. If *name* is specified, it
-   names a logger which, together with its children, will have its events allowed
-   through the filter. If *name* is the empty string, allows every event.
-
-
-   .. method:: filter(record)
-
-      Is the specified record to be logged? Returns zero for no, nonzero for
-      yes. If deemed appropriate, the record may be modified in-place by this
-      method.
-
-Note that filters attached to handlers are consulted whenever an event is
-emitted by the handler, whereas filters attached to loggers are consulted
-whenever an event is logged to the handler (using :meth:`debug`, :meth:`info`,
-etc.) This means that events which have been generated by descendant loggers
-will not be filtered by a logger's filter setting, unless the filter has also
-been applied to those descendant loggers.
-
-You don't actually need to subclass ``Filter``: you can pass any instance
-which has a ``filter`` method with the same semantics.
-
-.. versionchanged:: 3.2
-   You don't need to create specialized ``Filter`` classes, or use other
-   classes with a ``filter`` method: you can use a function (or other
-   callable) as a filter. The filtering logic will check to see if the filter
-   object has a ``filter`` attribute: if it does, it's assumed to be a
-   ``Filter`` and its :meth:`~Filter.filter` method is called. Otherwise, it's
-   assumed to be a callable and called with the record as the single
-   parameter. The returned value should conform to that returned by
-   :meth:`~Filter.filter`.
-
-Other uses for filters
-^^^^^^^^^^^^^^^^^^^^^^
-
-Although filters are used primarily to filter records based on more
-sophisticated criteria than levels, they get to see every record which is
-processed by the handler or logger they're attached to: this can be useful if
-you want to do things like counting how many records were processed by a
-particular logger or handler, or adding, changing or removing attributes in
-the LogRecord being processed. Obviously changing the LogRecord needs to be
-done with some care, but it does allow the injection of contextual information
-into logs (see :ref:`filters-contextual`).
-
-.. _log-record:
-
-LogRecord Objects
------------------
-
-:class:`LogRecord` instances are created automatically by the :class:`Logger`
-every time something is logged, and can be created manually via
-:func:`makeLogRecord` (for example, from a pickled event received over the
-wire).
-
-
-.. class:: LogRecord(name, lvl, pathname, lineno, msg, args, exc_info, func=None, sinfo=None)
-
-   Contains all the information pertinent to the event being logged.
-
-   The primary information is passed in :attr:`msg` and :attr:`args`, which
-   are combined using ``msg % args`` to create the :attr:`message` field of the
-   record.
-
-   .. attribute:: args
-
-      Tuple of arguments to be used in formatting :attr:`msg`.
-
-   .. attribute:: exc_info
-
-      Exception tuple (?? la :func:`sys.exc_info`) or ``None`` if no exception
-      information is available.
-
-   .. attribute:: func
-
-      Name of the function of origin (i.e. in which the logging call was made).
-
-   .. attribute:: lineno
-
-      Line number in the source file of origin.
-
-   .. attribute:: lvl
-
-      Numeric logging level.
-
-   .. attribute:: message
-
-      Bound to the result of :meth:`getMessage` when
-      :meth:`Formatter.format(record)` is invoked.
-
-   .. attribute:: msg
-
-      User-supplied :ref:`format string` or arbitrary object
-      (see :ref:`arbitrary-object-messages`) used in :meth:`getMessage`.
-
-   .. attribute:: name
-
-      Name of the logger that emitted the record.
-
-   .. attribute:: pathname
-
-      Absolute pathname of the source file of origin.
-
-   .. attribute:: stack_info
-
-      Stack frame information (where available) from the bottom of the stack
-      in the current thread, up to and including the stack frame of the
-      logging call which resulted in the creation of this record.
-
-   .. method:: getMessage()
-
-      Returns the message for this :class:`LogRecord` instance after merging any
-      user-supplied arguments with the message. If the user-supplied message
-      argument to the logging call is not a string, :func:`str` is called on it to
-      convert it to a string. This allows use of user-defined classes as
-      messages, whose ``__str__`` method can return the actual format string to
-      be used.
-
-.. _logger-adapter:
-
-LoggerAdapter Objects
----------------------
+      The ``style`` argument was added.
 
-:class:`LoggerAdapter` instances are used to conveniently pass contextual
-information into logging calls. For a usage example , see the section on
-`adding contextual information to your logging output`__.
 
-__ context-info_
+.. function:: shutdown()
 
-.. class:: LoggerAdapter(logger, extra)
+   Informs the logging system to perform an orderly shutdown by flushing and
+   closing all handlers. This should be called at application exit and no
+   further use of the logging system should be made after this call.
 
-  Returns an instance of :class:`LoggerAdapter` initialized with an
-  underlying :class:`Logger` instance and a dict-like object.
 
-  .. method:: process(msg, kwargs)
+.. function:: setLoggerClass(klass)
 
-    Modifies the message and/or keyword arguments passed to a logging call in
-    order to insert contextual information. This implementation takes the object
-    passed as *extra* to the constructor and adds it to *kwargs* using key
-    'extra'. The return value is a (*msg*, *kwargs*) tuple which has the
-    (possibly modified) versions of the arguments passed in.
+   Tells the logging system to use the class *klass* when instantiating a logger.
+   The class should define :meth:`__init__` such that only a name argument is
+   required, and the :meth:`__init__` should call :meth:`Logger.__init__`. This
+   function is typically called before any loggers are instantiated by applications
+   which need to use custom logger behavior.
 
-In addition to the above, :class:`LoggerAdapter` supports the following
-methods of :class:`Logger`, i.e. :meth:`debug`, :meth:`info`, :meth:`warning`,
-:meth:`error`, :meth:`exception`, :meth:`critical`, :meth:`log`,
-:meth:`isEnabledFor`, :meth:`getEffectiveLevel`, :meth:`setLevel`,
-:meth:`hasHandlers`. These methods have the same signatures as their
-counterparts in :class:`Logger`, so you can use the two types of instances
-interchangeably.
 
-.. versionchanged:: 3.2
-   The :meth:`isEnabledFor`, :meth:`getEffectiveLevel`, :meth:`setLevel` and
-   :meth:`hasHandlers` methods were added to :class:`LoggerAdapter`.  These
-   methods delegate to the underlying logger.
+.. function:: setLogRecordFactory(factory)
 
+   Set a callable which is used to create a :class:`LogRecord`.
 
-Thread Safety
--------------
+   :param factory: The factory callable to be used to instantiate a log record.
 
-The logging module is intended to be thread-safe without any special work
-needing to be done by its clients. It achieves this though using threading
-locks; there is one lock to serialize access to the module's shared data, and
-each handler also creates a lock to serialize access to its underlying I/O.
-
-If you are implementing asynchronous signal handlers using the :mod:`signal`
-module, you may not be able to use logging from within such handlers. This is
-because lock implementations in the :mod:`threading` module are not always
-re-entrant, and so cannot be invoked from such signal handlers.
+   .. versionadded:: 3.2
+      This function has been provided, along with :func:`getLogRecordFactory`, to
+      allow developers more control over how the :class:`LogRecord` representing
+      a logging event is constructed.
+
+   The factory has the following signature:
+
+   ``factory(name, level, fn, lno, msg, args, exc_info, func=None, sinfo=None, **kwargs)``
+
+      :name: The logger name.
+      :level: The logging level (numeric).
+      :fn: The full pathname of the file where the logging call was made.
+      :lno: The line number in the file where the logging call was made.
+      :msg: The logging message.
+      :args: The arguments for the logging message.
+      :exc_info: An exception tuple, or None.
+      :func: The name of the function or method which invoked the logging
+             call.
+      :sinfo: A stack traceback such as is provided by
+              :func:`traceback.print_stack`, showing the call hierarchy.
+      :kwargs: Additional keyword arguments.
 
 
 Integration with the warnings module
@@ -3310,842 +1042,28 @@
    If *capture* is ``True``, warnings issued by the :mod:`warnings` module will
    be redirected to the logging system. Specifically, a warning will be
    formatted using :func:`warnings.formatwarning` and the resulting string
-   logged to a logger named "py.warnings" with a severity of `WARNING`.
+   logged to a logger named 'py.warnings' with a severity of `WARNING`.
 
    If *capture* is ``False``, the redirection of warnings to the logging system
    will stop, and warnings will be redirected to their original destinations
    (i.e. those in effect before `captureWarnings(True)` was called).
 
 
-Configuration
--------------
-
-
-.. _logging-config-api:
-
-Configuration functions
-^^^^^^^^^^^^^^^^^^^^^^^
+.. seealso::
 
-The following functions configure the logging module. They are located in the
-:mod:`logging.config` module.  Their use is optional --- you can configure the
-logging module using these functions or by making calls to the main API (defined
-in :mod:`logging` itself) and defining handlers which are declared either in
-:mod:`logging` or :mod:`logging.handlers`.
-
-.. function:: dictConfig(config)
-
-    Takes the logging configuration from a dictionary.  The contents of
-    this dictionary are described in :ref:`logging-config-dictschema`
-    below.
-
-    If an error is encountered during configuration, this function will
-    raise a :exc:`ValueError`, :exc:`TypeError`, :exc:`AttributeError`
-    or :exc:`ImportError` with a suitably descriptive message.  The
-    following is a (possibly incomplete) list of conditions which will
-    raise an error:
-
-    * A ``level`` which is not a string or which is a string not
-      corresponding to an actual logging level.
-    * A ``propagate`` value which is not a boolean.
-    * An id which does not have a corresponding destination.
-    * A non-existent handler id found during an incremental call.
-    * An invalid logger name.
-    * Inability to resolve to an internal or external object.
-
-    Parsing is performed by the :class:`DictConfigurator` class, whose
-    constructor is passed the dictionary used for configuration, and
-    has a :meth:`configure` method.  The :mod:`logging.config` module
-    has a callable attribute :attr:`dictConfigClass`
-    which is initially set to :class:`DictConfigurator`.
-    You can replace the value of :attr:`dictConfigClass` with a
-    suitable implementation of your own.
-
-    :func:`dictConfig` calls :attr:`dictConfigClass` passing
-    the specified dictionary, and then calls the :meth:`configure` method on
-    the returned object to put the configuration into effect::
-
-          def dictConfig(config):
-              dictConfigClass(config).configure()
-
-    For example, a subclass of :class:`DictConfigurator` could call
-    ``DictConfigurator.__init__()`` in its own :meth:`__init__()`, then
-    set up custom prefixes which would be usable in the subsequent
-    :meth:`configure` call. :attr:`dictConfigClass` would be bound to
-    this new subclass, and then :func:`dictConfig` could be called exactly as
-    in the default, uncustomized state.
-
-.. function:: fileConfig(fname[, defaults])
-
-   Reads the logging configuration from a :mod:`configparser`\-format file named
-   *fname*. This function can be called several times from an application,
-   allowing an end user to select from various pre-canned
-   configurations (if the developer provides a mechanism to present the choices
-   and load the chosen configuration). Defaults to be passed to the ConfigParser
-   can be specified in the *defaults* argument.
-
-
-.. function:: listen(port=DEFAULT_LOGGING_CONFIG_PORT)
-
-   Starts up a socket server on the specified port, and listens for new
-   configurations. If no port is specified, the module's default
-   :const:`DEFAULT_LOGGING_CONFIG_PORT` is used. Logging configurations will be
-   sent as a file suitable for processing by :func:`fileConfig`. Returns a
-   :class:`Thread` instance on which you can call :meth:`start` to start the
-   server, and which you can :meth:`join` when appropriate. To stop the server,
-   call :func:`stopListening`.
-
-   To send a configuration to the socket, read in the configuration file and
-   send it to the socket as a string of bytes preceded by a four-byte length
-   string packed in binary using ``struct.pack('>L', n)``.
-
-
-.. function:: stopListening()
-
-   Stops the listening server which was created with a call to :func:`listen`.
-   This is typically called before calling :meth:`join` on the return value from
-   :func:`listen`.
-
-
-.. _logging-config-dictschema:
-
-Configuration dictionary schema
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Describing a logging configuration requires listing the various
-objects to create and the connections between them; for example, you
-may create a handler named "console" and then say that the logger
-named "startup" will send its messages to the "console" handler.
-These objects aren't limited to those provided by the :mod:`logging`
-module because you might write your own formatter or handler class.
-The parameters to these classes may also need to include external
-objects such as ``sys.stderr``.  The syntax for describing these
-objects and connections is defined in :ref:`logging-config-dict-connections`
-below.
-
-Dictionary Schema Details
-"""""""""""""""""""""""""
-
-The dictionary passed to :func:`dictConfig` must contain the following
-keys:
-
-* *version* - to be set to an integer value representing the schema
-  version.  The only valid value at present is 1, but having this key
-  allows the schema to evolve while still preserving backwards
-  compatibility.
-
-All other keys are optional, but if present they will be interpreted
-as described below.  In all cases below where a 'configuring dict' is
-mentioned, it will be checked for the special ``'()'`` key to see if a
-custom instantiation is required.  If so, the mechanism described in
-:ref:`logging-config-dict-userdef` below is used to create an instance;
-otherwise, the context is used to determine what to instantiate.
-
-* *formatters* - the corresponding value will be a dict in which each
-  key is a formatter id and each value is a dict describing how to
-  configure the corresponding Formatter instance.
-
-  The configuring dict is searched for keys ``format`` and ``datefmt``
-  (with defaults of ``None``) and these are used to construct a
-  :class:`logging.Formatter` instance.
-
-* *filters* - the corresponding value will be a dict in which each key
-  is a filter id and each value is a dict describing how to configure
-  the corresponding Filter instance.
-
-  The configuring dict is searched for the key ``name`` (defaulting to the
-  empty string) and this is used to construct a :class:`logging.Filter`
-  instance.
-
-* *handlers* - the corresponding value will be a dict in which each
-  key is a handler id and each value is a dict describing how to
-  configure the corresponding Handler instance.
-
-  The configuring dict is searched for the following keys:
-
-  * ``class`` (mandatory).  This is the fully qualified name of the
-    handler class.
-
-  * ``level`` (optional).  The level of the handler.
-
-  * ``formatter`` (optional).  The id of the formatter for this
-    handler.
-
-  * ``filters`` (optional).  A list of ids of the filters for this
-    handler.
-
-  All *other* keys are passed through as keyword arguments to the
-  handler's constructor.  For example, given the snippet::
-
-      handlers:
-        console:
-          class : logging.StreamHandler
-          formatter: brief
-          level   : INFO
-          filters: [allow_foo]
-          stream  : ext://sys.stdout
-        file:
-          class : logging.handlers.RotatingFileHandler
-          formatter: precise
-          filename: logconfig.log
-          maxBytes: 1024
-          backupCount: 3
-
-  the handler with id ``console`` is instantiated as a
-  :class:`logging.StreamHandler`, using ``sys.stdout`` as the underlying
-  stream.  The handler with id ``file`` is instantiated as a
-  :class:`logging.handlers.RotatingFileHandler` with the keyword arguments
-  ``filename='logconfig.log', maxBytes=1024, backupCount=3``.
-
-* *loggers* - the corresponding value will be a dict in which each key
-  is a logger name and each value is a dict describing how to
-  configure the corresponding Logger instance.
-
-  The configuring dict is searched for the following keys:
-
-  * ``level`` (optional).  The level of the logger.
-
-  * ``propagate`` (optional).  The propagation setting of the logger.
-
-  * ``filters`` (optional).  A list of ids of the filters for this
-    logger.
-
-  * ``handlers`` (optional).  A list of ids of the handlers for this
-    logger.
-
-  The specified loggers will be configured according to the level,
-  propagation, filters and handlers specified.
-
-* *root* - this will be the configuration for the root logger.
-  Processing of the configuration will be as for any logger, except
-  that the ``propagate`` setting will not be applicable.
-
-* *incremental* - whether the configuration is to be interpreted as
-  incremental to the existing configuration.  This value defaults to
-  ``False``, which means that the specified configuration replaces the
-  existing configuration with the same semantics as used by the
-  existing :func:`fileConfig` API.
-
-  If the specified value is ``True``, the configuration is processed
-  as described in the section on :ref:`logging-config-dict-incremental`.
-
-* *disable_existing_loggers* - whether any existing loggers are to be
-  disabled. This setting mirrors the parameter of the same name in
-  :func:`fileConfig`. If absent, this parameter defaults to ``True``.
-  This value is ignored if *incremental* is ``True``.
-
-.. _logging-config-dict-incremental:
-
-Incremental Configuration
-"""""""""""""""""""""""""
-
-It is difficult to provide complete flexibility for incremental
-configuration.  For example, because objects such as filters
-and formatters are anonymous, once a configuration is set up, it is
-not possible to refer to such anonymous objects when augmenting a
-configuration.
-
-Furthermore, there is not a compelling case for arbitrarily altering
-the object graph of loggers, handlers, filters, formatters at
-run-time, once a configuration is set up; the verbosity of loggers and
-handlers can be controlled just by setting levels (and, in the case of
-loggers, propagation flags).  Changing the object graph arbitrarily in
-a safe way is problematic in a multi-threaded environment; while not
-impossible, the benefits are not worth the complexity it adds to the
-implementation.
-
-Thus, when the ``incremental`` key of a configuration dict is present
-and is ``True``, the system will completely ignore any ``formatters`` and
-``filters`` entries, and process only the ``level``
-settings in the ``handlers`` entries, and the ``level`` and
-``propagate`` settings in the ``loggers`` and ``root`` entries.
-
-Using a value in the configuration dict lets configurations to be sent
-over the wire as pickled dicts to a socket listener. Thus, the logging
-verbosity of a long-running application can be altered over time with
-no need to stop and restart the application.
-
-.. _logging-config-dict-connections:
-
-Object connections
-""""""""""""""""""
-
-The schema describes a set of logging objects - loggers,
-handlers, formatters, filters - which are connected to each other in
-an object graph.  Thus, the schema needs to represent connections
-between the objects.  For example, say that, once configured, a
-particular logger has attached to it a particular handler.  For the
-purposes of this discussion, we can say that the logger represents the
-source, and the handler the destination, of a connection between the
-two.  Of course in the configured objects this is represented by the
-logger holding a reference to the handler.  In the configuration dict,
-this is done by giving each destination object an id which identifies
-it unambiguously, and then using the id in the source object's
-configuration to indicate that a connection exists between the source
-and the destination object with that id.
-
-So, for example, consider the following YAML snippet::
-
-    formatters:
-      brief:
-        # configuration for formatter with id 'brief' goes here
-      precise:
-        # configuration for formatter with id 'precise' goes here
-    handlers:
-      h1: #This is an id
-       # configuration of handler with id 'h1' goes here
-       formatter: brief
-      h2: #This is another id
-       # configuration of handler with id 'h2' goes here
-       formatter: precise
-    loggers:
-      foo.bar.baz:
-        # other configuration for logger 'foo.bar.baz'
-        handlers: [h1, h2]
-
-(Note: YAML used here because it's a little more readable than the
-equivalent Python source form for the dictionary.)
-
-The ids for loggers are the logger names which would be used
-programmatically to obtain a reference to those loggers, e.g.
-``foo.bar.baz``.  The ids for Formatters and Filters can be any string
-value (such as ``brief``, ``precise`` above) and they are transient,
-in that they are only meaningful for processing the configuration
-dictionary and used to determine connections between objects, and are
-not persisted anywhere when the configuration call is complete.
-
-The above snippet indicates that logger named ``foo.bar.baz`` should
-have two handlers attached to it, which are described by the handler
-ids ``h1`` and ``h2``. The formatter for ``h1`` is that described by id
-``brief``, and the formatter for ``h2`` is that described by id
-``precise``.
-
-
-.. _logging-config-dict-userdef:
-
-User-defined objects
-""""""""""""""""""""
-
-The schema supports user-defined objects for handlers, filters and
-formatters.  (Loggers do not need to have different types for
-different instances, so there is no support in this configuration
-schema for user-defined logger classes.)
-
-Objects to be configured are described by dictionaries
-which detail their configuration.  In some places, the logging system
-will be able to infer from the context how an object is to be
-instantiated, but when a user-defined object is to be instantiated,
-the system will not know how to do this.  In order to provide complete
-flexibility for user-defined object instantiation, the user needs
-to provide a 'factory' - a callable which is called with a
-configuration dictionary and which returns the instantiated object.
-This is signalled by an absolute import path to the factory being
-made available under the special key ``'()'``.  Here's a concrete
-example::
-
-    formatters:
-      brief:
-        format: '%(message)s'
-      default:
-        format: '%(asctime)s %(levelname)-8s %(name)-15s %(message)s'
-        datefmt: '%Y-%m-%d %H:%M:%S'
-      custom:
-          (): my.package.customFormatterFactory
-          bar: baz
-          spam: 99.9
-          answer: 42
-
-The above YAML snippet defines three formatters.  The first, with id
-``brief``, is a standard :class:`logging.Formatter` instance with the
-specified format string.  The second, with id ``default``, has a
-longer format and also defines the time format explicitly, and will
-result in a :class:`logging.Formatter` initialized with those two format
-strings.  Shown in Python source form, the ``brief`` and ``default``
-formatters have configuration sub-dictionaries::
-
-    {
-      'format' : '%(message)s'
-    }
-
-and::
-
-    {
-      'format' : '%(asctime)s %(levelname)-8s %(name)-15s %(message)s',
-      'datefmt' : '%Y-%m-%d %H:%M:%S'
-    }
-
-respectively, and as these dictionaries do not contain the special key
-``'()'``, the instantiation is inferred from the context: as a result,
-standard :class:`logging.Formatter` instances are created.  The
-configuration sub-dictionary for the third formatter, with id
-``custom``, is::
-
-  {
-    '()' : 'my.package.customFormatterFactory',
-    'bar' : 'baz',
-    'spam' : 99.9,
-    'answer' : 42
-  }
-
-and this contains the special key ``'()'``, which means that
-user-defined instantiation is wanted.  In this case, the specified
-factory callable will be used. If it is an actual callable it will be
-used directly - otherwise, if you specify a string (as in the example)
-the actual callable will be located using normal import mechanisms.
-The callable will be called with the **remaining** items in the
-configuration sub-dictionary as keyword arguments.  In the above
-example, the formatter with id ``custom`` will be assumed to be
-returned by the call::
-
-    my.package.customFormatterFactory(bar='baz', spam=99.9, answer=42)
-
-The key ``'()'`` has been used as the special key because it is not a
-valid keyword parameter name, and so will not clash with the names of
-the keyword arguments used in the call.  The ``'()'`` also serves as a
-mnemonic that the corresponding value is a callable.
-
-
-.. _logging-config-dict-externalobj:
-
-Access to external objects
-""""""""""""""""""""""""""
-
-There are times where a configuration needs to refer to objects
-external to the configuration, for example ``sys.stderr``.  If the
-configuration dict is constructed using Python code, this is
-straightforward, but a problem arises when the configuration is
-provided via a text file (e.g. JSON, YAML).  In a text file, there is
-no standard way to distinguish ``sys.stderr`` from the literal string
-``'sys.stderr'``.  To facilitate this distinction, the configuration
-system looks for certain special prefixes in string values and
-treat them specially.  For example, if the literal string
-``'ext://sys.stderr'`` is provided as a value in the configuration,
-then the ``ext://`` will be stripped off and the remainder of the
-value processed using normal import mechanisms.
-
-The handling of such prefixes is done in a way analogous to protocol
-handling: there is a generic mechanism to look for prefixes which
-match the regular expression ``^(?P[a-z]+)://(?P.*)$``
-whereby, if the ``prefix`` is recognised, the ``suffix`` is processed
-in a prefix-dependent manner and the result of the processing replaces
-the string value.  If the prefix is not recognised, then the string
-value will be left as-is.
-
-
-.. _logging-config-dict-internalobj:
-
-Access to internal objects
-""""""""""""""""""""""""""
-
-As well as external objects, there is sometimes also a need to refer
-to objects in the configuration.  This will be done implicitly by the
-configuration system for things that it knows about.  For example, the
-string value ``'DEBUG'`` for a ``level`` in a logger or handler will
-automatically be converted to the value ``logging.DEBUG``, and the
-``handlers``, ``filters`` and ``formatter`` entries will take an
-object id and resolve to the appropriate destination object.
-
-However, a more generic mechanism is needed for user-defined
-objects which are not known to the :mod:`logging` module.  For
-example, consider :class:`logging.handlers.MemoryHandler`, which takes
-a ``target`` argument which is another handler to delegate to. Since
-the system already knows about this class, then in the configuration,
-the given ``target`` just needs to be the object id of the relevant
-target handler, and the system will resolve to the handler from the
-id.  If, however, a user defines a ``my.package.MyHandler`` which has
-an ``alternate`` handler, the configuration system would not know that
-the ``alternate`` referred to a handler.  To cater for this, a generic
-resolution system allows the user to specify::
-
-    handlers:
-      file:
-        # configuration of file handler goes here
-
-      custom:
-        (): my.package.MyHandler
-        alternate: cfg://handlers.file
-
-The literal string ``'cfg://handlers.file'`` will be resolved in an
-analogous way to strings with the ``ext://`` prefix, but looking
-in the configuration itself rather than the import namespace.  The
-mechanism allows access by dot or by index, in a similar way to
-that provided by ``str.format``.  Thus, given the following snippet::
-
-    handlers:
-      email:
-        class: logging.handlers.SMTPHandler
-        mailhost: localhost
-        fromaddr: my_app at domain.tld
-        toaddrs:
-          - support_team at domain.tld
-          - dev_team at domain.tld
-        subject: Houston, we have a problem.
-
-in the configuration, the string ``'cfg://handlers'`` would resolve to
-the dict with key ``handlers``, the string ``'cfg://handlers.email``
-would resolve to the dict with key ``email`` in the ``handlers`` dict,
-and so on.  The string ``'cfg://handlers.email.toaddrs[1]`` would
-resolve to ``'dev_team.domain.tld'`` and the string
-``'cfg://handlers.email.toaddrs[0]'`` would resolve to the value
-``'support_team at domain.tld'``. The ``subject`` value could be accessed
-using either ``'cfg://handlers.email.subject'`` or, equivalently,
-``'cfg://handlers.email[subject]'``.  The latter form only needs to be
-used if the key contains spaces or non-alphanumeric characters.  If an
-index value consists only of decimal digits, access will be attempted
-using the corresponding integer value, falling back to the string
-value if needed.
-
-Given a string ``cfg://handlers.myhandler.mykey.123``, this will
-resolve to ``config_dict['handlers']['myhandler']['mykey']['123']``.
-If the string is specified as ``cfg://handlers.myhandler.mykey[123]``,
-the system will attempt to retrieve the value from
-``config_dict['handlers']['myhandler']['mykey'][123]``, and fall back
-to ``config_dict['handlers']['myhandler']['mykey']['123']`` if that
-fails.
-
-.. _logging-config-fileformat:
-
-Configuration file format
-^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The configuration file format understood by :func:`fileConfig` is based on
-:mod:`configparser` functionality. The file must contain sections called
-``[loggers]``, ``[handlers]`` and ``[formatters]`` which identify by name the
-entities of each type which are defined in the file. For each such entity, there
-is a separate section which identifies how that entity is configured.  Thus, for
-a logger named ``log01`` in the ``[loggers]`` section, the relevant
-configuration details are held in a section ``[logger_log01]``. Similarly, a
-handler called ``hand01`` in the ``[handlers]`` section will have its
-configuration held in a section called ``[handler_hand01]``, while a formatter
-called ``form01`` in the ``[formatters]`` section will have its configuration
-specified in a section called ``[formatter_form01]``. The root logger
-configuration must be specified in a section called ``[logger_root]``.
-
-Examples of these sections in the file are given below. ::
-
-   [loggers]
-   keys=root,log02,log03,log04,log05,log06,log07
-
-   [handlers]
-   keys=hand01,hand02,hand03,hand04,hand05,hand06,hand07,hand08,hand09
-
-   [formatters]
-   keys=form01,form02,form03,form04,form05,form06,form07,form08,form09
-
-The root logger must specify a level and a list of handlers. An example of a
-root logger section is given below. ::
-
-   [logger_root]
-   level=NOTSET
-   handlers=hand01
-
-The ``level`` entry can be one of ``DEBUG, INFO, WARNING, ERROR, CRITICAL`` or
-``NOTSET``. For the root logger only, ``NOTSET`` means that all messages will be
-logged. Level values are :func:`eval`\ uated in the context of the ``logging``
-package's namespace.
-
-The ``handlers`` entry is a comma-separated list of handler names, which must
-appear in the ``[handlers]`` section. These names must appear in the
-``[handlers]`` section and have corresponding sections in the configuration
-file.
-
-For loggers other than the root logger, some additional information is required.
-This is illustrated by the following example. ::
-
-   [logger_parser]
-   level=DEBUG
-   handlers=hand01
-   propagate=1
-   qualname=compiler.parser
-
-The ``level`` and ``handlers`` entries are interpreted as for the root logger,
-except that if a non-root logger's level is specified as ``NOTSET``, the system
-consults loggers higher up the hierarchy to determine the effective level of the
-logger. The ``propagate`` entry is set to 1 to indicate that messages must
-propagate to handlers higher up the logger hierarchy from this logger, or 0 to
-indicate that messages are **not** propagated to handlers up the hierarchy. The
-``qualname`` entry is the hierarchical channel name of the logger, that is to
-say the name used by the application to get the logger.
-
-Sections which specify handler configuration are exemplified by the following.
-::
-
-   [handler_hand01]
-   class=StreamHandler
-   level=NOTSET
-   formatter=form01
-   args=(sys.stdout,)
-
-The ``class`` entry indicates the handler's class (as determined by :func:`eval`
-in the ``logging`` package's namespace). The ``level`` is interpreted as for
-loggers, and ``NOTSET`` is taken to mean "log everything".
-
-The ``formatter`` entry indicates the key name of the formatter for this
-handler. If blank, a default formatter (``logging._defaultFormatter``) is used.
-If a name is specified, it must appear in the ``[formatters]`` section and have
-a corresponding section in the configuration file.
-
-The ``args`` entry, when :func:`eval`\ uated in the context of the ``logging``
-package's namespace, is the list of arguments to the constructor for the handler
-class. Refer to the constructors for the relevant handlers, or to the examples
-below, to see how typical entries are constructed. ::
-
-   [handler_hand02]
-   class=FileHandler
-   level=DEBUG
-   formatter=form02
-   args=('python.log', 'w')
-
-   [handler_hand03]
-   class=handlers.SocketHandler
-   level=INFO
-   formatter=form03
-   args=('localhost', handlers.DEFAULT_TCP_LOGGING_PORT)
-
-   [handler_hand04]
-   class=handlers.DatagramHandler
-   level=WARN
-   formatter=form04
-   args=('localhost', handlers.DEFAULT_UDP_LOGGING_PORT)
-
-   [handler_hand05]
-   class=handlers.SysLogHandler
-   level=ERROR
-   formatter=form05
-   args=(('localhost', handlers.SYSLOG_UDP_PORT), handlers.SysLogHandler.LOG_USER)
-
-   [handler_hand06]
-   class=handlers.NTEventLogHandler
-   level=CRITICAL
-   formatter=form06
-   args=('Python Application', '', 'Application')
-
-   [handler_hand07]
-   class=handlers.SMTPHandler
-   level=WARN
-   formatter=form07
-   args=('localhost', 'from at abc', ['user1 at abc', 'user2 at xyz'], 'Logger Subject')
-
-   [handler_hand08]
-   class=handlers.MemoryHandler
-   level=NOTSET
-   formatter=form08
-   target=
-   args=(10, ERROR)
-
-   [handler_hand09]
-   class=handlers.HTTPHandler
-   level=NOTSET
-   formatter=form09
-   args=('localhost:9022', '/log', 'GET')
-
-Sections which specify formatter configuration are typified by the following. ::
-
-   [formatter_form01]
-   format=F1 %(asctime)s %(levelname)s %(message)s
-   datefmt=
-   class=logging.Formatter
-
-The ``format`` entry is the overall format string, and the ``datefmt`` entry is
-the :func:`strftime`\ -compatible date/time format string.  If empty, the
-package substitutes ISO8601 format date/times, which is almost equivalent to
-specifying the date format string ``"%Y-%m-%d %H:%M:%S"``.  The ISO8601 format
-also specifies milliseconds, which are appended to the result of using the above
-format string, with a comma separator.  An example time in ISO8601 format is
-``2003-01-23 00:29:50,411``.
-
-The ``class`` entry is optional.  It indicates the name of the formatter's class
-(as a dotted module and class name.)  This option is useful for instantiating a
-:class:`Formatter` subclass.  Subclasses of :class:`Formatter` can present
-exception tracebacks in an expanded or condensed format.
-
-
-Configuration server example
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Here is an example of a module using the logging configuration server::
-
-    import logging
-    import logging.config
-    import time
-    import os
-
-    # read initial config file
-    logging.config.fileConfig("logging.conf")
-
-    # create and start listener on port 9999
-    t = logging.config.listen(9999)
-    t.start()
-
-    logger = logging.getLogger("simpleExample")
-
-    try:
-        # loop through logging calls to see the difference
-        # new configurations make, until Ctrl+C is pressed
-        while True:
-            logger.debug("debug message")
-            logger.info("info message")
-            logger.warn("warn message")
-            logger.error("error message")
-            logger.critical("critical message")
-            time.sleep(5)
-    except KeyboardInterrupt:
-        # cleanup
-        logging.config.stopListening()
-        t.join()
-
-And here is a script that takes a filename and sends that file to the server,
-properly preceded with the binary-encoded length, as the new logging
-configuration::
-
-    #!/usr/bin/env python
-    import socket, sys, struct
-
-    data_to_send = open(sys.argv[1], "r").read()
-
-    HOST = 'localhost'
-    PORT = 9999
-    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-    print("connecting...")
-    s.connect((HOST, PORT))
-    print("sending config...")
-    s.send(struct.pack(">L", len(data_to_send)))
-    s.send(data_to_send)
-    s.close()
-    print("complete")
+   Module :mod:`logging.config`
+      Configuration API for the logging module.
 
+   Module :mod:`logging.handlers`
+      Useful handlers included with the logging module.
 
-More examples
--------------
-
-Multiple handlers and formatters
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   :pep:`282` - A Logging System
+      The proposal which described this feature for inclusion in the Python standard
+      library.
 
-Loggers are plain Python objects.  The :func:`addHandler` method has no minimum
-or maximum quota for the number of handlers you may add.  Sometimes it will be
-beneficial for an application to log all messages of all severities to a text
-file while simultaneously logging errors or above to the console.  To set this
-up, simply configure the appropriate handlers.  The logging calls in the
-application code will remain unchanged.  Here is a slight modification to the
-previous simple module-based configuration example::
-
-    import logging
-
-    logger = logging.getLogger("simple_example")
-    logger.setLevel(logging.DEBUG)
-    # create file handler which logs even debug messages
-    fh = logging.FileHandler("spam.log")
-    fh.setLevel(logging.DEBUG)
-    # create console handler with a higher log level
-    ch = logging.StreamHandler()
-    ch.setLevel(logging.ERROR)
-    # create formatter and add it to the handlers
-    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
-    ch.setFormatter(formatter)
-    fh.setFormatter(formatter)
-    # add the handlers to logger
-    logger.addHandler(ch)
-    logger.addHandler(fh)
-
-    # "application" code
-    logger.debug("debug message")
-    logger.info("info message")
-    logger.warn("warn message")
-    logger.error("error message")
-    logger.critical("critical message")
-
-Notice that the "application" code does not care about multiple handlers.  All
-that changed was the addition and configuration of a new handler named *fh*.
-
-The ability to create new handlers with higher- or lower-severity filters can be
-very helpful when writing and testing an application.  Instead of using many
-``print`` statements for debugging, use ``logger.debug``: Unlike the print
-statements, which you will have to delete or comment out later, the logger.debug
-statements can remain intact in the source code and remain dormant until you
-need them again.  At that time, the only change that needs to happen is to
-modify the severity level of the logger and/or handler to debug.
-
-
-Using logging in multiple modules
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-It was mentioned above that multiple calls to
-``logging.getLogger('someLogger')`` return a reference to the same logger
-object.  This is true not only within the same module, but also across modules
-as long as it is in the same Python interpreter process.  It is true for
-references to the same object; additionally, application code can define and
-configure a parent logger in one module and create (but not configure) a child
-logger in a separate module, and all logger calls to the child will pass up to
-the parent.  Here is a main module::
-
-    import logging
-    import auxiliary_module
-
-    # create logger with "spam_application"
-    logger = logging.getLogger("spam_application")
-    logger.setLevel(logging.DEBUG)
-    # create file handler which logs even debug messages
-    fh = logging.FileHandler("spam.log")
-    fh.setLevel(logging.DEBUG)
-    # create console handler with a higher log level
-    ch = logging.StreamHandler()
-    ch.setLevel(logging.ERROR)
-    # create formatter and add it to the handlers
-    formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
-    fh.setFormatter(formatter)
-    ch.setFormatter(formatter)
-    # add the handlers to the logger
-    logger.addHandler(fh)
-    logger.addHandler(ch)
-
-    logger.info("creating an instance of auxiliary_module.Auxiliary")
-    a = auxiliary_module.Auxiliary()
-    logger.info("created an instance of auxiliary_module.Auxiliary")
-    logger.info("calling auxiliary_module.Auxiliary.do_something")
-    a.do_something()
-    logger.info("finished auxiliary_module.Auxiliary.do_something")
-    logger.info("calling auxiliary_module.some_function()")
-    auxiliary_module.some_function()
-    logger.info("done with auxiliary_module.some_function()")
-
-Here is the auxiliary module::
-
-    import logging
-
-    # create logger
-    module_logger = logging.getLogger("spam_application.auxiliary")
-
-    class Auxiliary:
-        def __init__(self):
-            self.logger = logging.getLogger("spam_application.auxiliary.Auxiliary")
-            self.logger.info("creating an instance of Auxiliary")
-        def do_something(self):
-            self.logger.info("doing something")
-            a = 1 + 1
-            self.logger.info("done doing something")
-
-    def some_function():
-        module_logger.info("received a call to \"some_function\"")
-
-The output looks like this::
-
-    2005-03-23 23:47:11,663 - spam_application - INFO -
-       creating an instance of auxiliary_module.Auxiliary
-    2005-03-23 23:47:11,665 - spam_application.auxiliary.Auxiliary - INFO -
-       creating an instance of Auxiliary
-    2005-03-23 23:47:11,665 - spam_application - INFO -
-       created an instance of auxiliary_module.Auxiliary
-    2005-03-23 23:47:11,668 - spam_application - INFO -
-       calling auxiliary_module.Auxiliary.do_something
-    2005-03-23 23:47:11,668 - spam_application.auxiliary.Auxiliary - INFO -
-       doing something
-    2005-03-23 23:47:11,669 - spam_application.auxiliary.Auxiliary - INFO -
-       done doing something
-    2005-03-23 23:47:11,670 - spam_application - INFO -
-       finished auxiliary_module.Auxiliary.do_something
-    2005-03-23 23:47:11,671 - spam_application - INFO -
-       calling auxiliary_module.some_function()
-    2005-03-23 23:47:11,672 - spam_application.auxiliary - INFO -
-       received a call to "some_function"
-    2005-03-23 23:47:11,673 - spam_application - INFO -
-       done with auxiliary_module.some_function()
+   `Original Python logging package `_
+      This is the original source for the :mod:`logging` package.  The version of the
+      package available from this site is suitable for use with Python 1.5.2, 2.1.x
+      and 2.2.x, which do not include the :mod:`logging` package in the standard
+      library.
 

Modified: python/branches/py3k-cdecimal/Doc/library/msilib.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/msilib.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/msilib.rst	Sun Jan  2 13:18:37 2011
@@ -351,7 +351,7 @@
 -----------------
 
 
-.. class:: Directory(database, cab, basedir, physical,  logical, default, component, [componentflags])
+.. class:: Directory(database, cab, basedir, physical,  logical, default, [componentflags])
 
    Create a new directory in the Directory table. There is a current component at
    each point in time for the directory, which is either explicitly created through

Modified: python/branches/py3k-cdecimal/Doc/library/multiprocessing.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/multiprocessing.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/multiprocessing.rst	Sun Jan  2 13:18:37 2011
@@ -1,8 +1,8 @@
-:mod:`multiprocessing` --- Process-based "threading" interface
-==============================================================
+:mod:`multiprocessing` --- Process-based parallelism
+====================================================
 
 .. module:: multiprocessing
-   :synopsis: Process-based "threading" interface.
+   :synopsis: Process-based parallelism.
 
 
 Introduction

Modified: python/branches/py3k-cdecimal/Doc/library/os.path.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/os.path.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/os.path.rst	Sun Jan  2 13:18:37 2011
@@ -228,7 +228,7 @@
 
    *start* defaults to :attr:`os.curdir`.
 
-   Availability:  Windows, Unix.
+   Availability: Unix, Windows.
 
 
 .. function:: samefile(path1, path2)
@@ -241,7 +241,7 @@
    name using the Windows API call GetFinalPathNameByHandle. This function
    raises an exception if handles cannot be obtained to either file.
 
-   Availability: Windows, Unix.
+   Availability: Unix, Windows.
 
    .. versionchanged:: 3.2
       Added Windows support.

Modified: python/branches/py3k-cdecimal/Doc/library/os.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/os.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/os.rst	Sun Jan  2 13:18:37 2011
@@ -1058,7 +1058,10 @@
 
    Create a hard link pointing to *source* named *link_name*.
 
-   Availability: Unix.
+   Availability: Unix, Windows.
+
+   .. versionchanged:: 3.2
+      Added Windows support.
 
 
 .. function:: listdir(path='.')
@@ -1140,25 +1143,31 @@
    Availability: Unix, Windows.
 
 
-.. function:: makedirs(path[, mode])
+.. function:: makedirs(path, mode=0o777, exist_ok=False)
 
    .. index::
       single: directory; creating
       single: UNC paths; and os.makedirs()
 
    Recursive directory creation function.  Like :func:`mkdir`, but makes all
-   intermediate-level directories needed to contain the leaf directory.  Throws
-   an :exc:`error` exception if the leaf directory already exists or cannot be
-   created.  The default *mode* is ``0o777`` (octal).  On some systems, *mode*
-   is ignored. Where it is used, the current umask value is first masked out.
+   intermediate-level directories needed to contain the leaf directory.  If
+   the target directory with the same mode as specified already exists,
+   raises an :exc:`OSError` exception if *exist_ok* is False, otherwise no
+   exception is raised.  If the directory cannot be created in other cases,
+   raises an :exc:`OSError` exception.  The default *mode* is ``0o777`` (octal).
+   On some systems, *mode* is ignored.  Where it is used, the current umask
+   value is first masked out.
 
    .. note::
 
-      :func:`makedirs` will become confused if the path elements to create include
-      :data:`os.pardir`.
+      :func:`makedirs` will become confused if the path elements to create
+      include :data:`pardir`.
 
    This function handles UNC paths correctly.
 
+   .. versionadded:: 3.2
+      The *exist_ok* parameter.
+
 
 .. function:: pathconf(path, name)
 
@@ -1383,7 +1392,18 @@
 
    Symbolic link support was introduced in Windows 6.0 (Vista).  :func:`symlink`
    will raise a :exc:`NotImplementedError` on Windows versions earlier than 6.0.
-   The *SeCreateSymbolicLinkPrivilege* is required in order to create symlinks.
+
+   .. note::
+
+      The *SeCreateSymbolicLinkPrivilege* is required in order to successfully
+      create symlinks. This privilege is not typically granted to regular
+      users but is available to accounts which can escalate privileges to the
+      administrator level. Either obtaining the privilege or running your
+      application as an administrator are ways to successfully create symlinks.
+
+
+      :exc:`OSError` is raised when the function is called by an unprivileged
+      user.
 
    Availability: Unix, Windows.
 

Modified: python/branches/py3k-cdecimal/Doc/library/parser.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/parser.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/parser.rst	Sun Jan  2 13:18:37 2011
@@ -268,7 +268,7 @@
    will only need to be aware of the simple string values.
 
 Note that the functions :func:`compilest`, :func:`expr`, and :func:`suite` may
-raise exceptions which are normally thrown by the parsing and compilation
+raise exceptions which are normally raised by the parsing and compilation
 process.  These include the built in exceptions :exc:`MemoryError`,
 :exc:`OverflowError`, :exc:`SyntaxError`, and :exc:`SystemError`.  In these
 cases, these exceptions carry all the meaning normally associated with them.

Modified: python/branches/py3k-cdecimal/Doc/library/pdb.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/pdb.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/pdb.rst	Sun Jan  2 13:18:37 2011
@@ -135,7 +135,8 @@
 :class:`Pdb` class and calling the method of the same name.  If you want to
 access further features, you have to do this yourself:
 
-.. class:: Pdb(completekey='tab', stdin=None, stdout=None, skip=None)
+.. class:: Pdb(completekey='tab', stdin=None, stdout=None, skip=None, \
+               nosigint=False)
 
    :class:`Pdb` is the debugger class.
 
@@ -146,6 +147,11 @@
    patterns.  The debugger will not step into frames that originate in a module
    that matches one of these patterns. [1]_
 
+   By default, Pdb sets a handler for the SIGINT signal (which is sent when the
+   user presses Ctrl-C on the console) when you give a ``continue`` command.
+   This allows you to break into the debugger again by pressing Ctrl-C.  If you
+   want Pdb not to touch the SIGINT handler, set *nosigint* tot true.
+
    Example call to enable tracing with *skip*::
 
       import pdb; pdb.Pdb(skip=['django.*']).set_trace()
@@ -153,6 +159,10 @@
    .. versionadded:: 3.1
       The *skip* argument.
 
+   .. versionadded:: 3.2
+      The *nosigint* argument.  Previously, a SIGINT handler was never set by
+      Pdb.
+
    .. method:: run(statement, globals=None, locals=None)
                runeval(expression, globals=None, locals=None)
                runcall(function, *args, **kwds)
@@ -256,8 +266,9 @@
    Temporary breakpoint, which is removed automatically when it is first hit.
    The arguments are the same as for :pdbcmd:`break`.
 
-.. pdbcommand:: cl(ear) [bpnumber [bpnumber ...]]
+.. pdbcommand:: cl(ear) [filename:lineno | bpnumber [bpnumber ...]]
 
+   With a *filename:lineno* argument, clear all the breakpoints at this line.
    With a space separated list of breakpoint numbers, clear those breakpoints.
    Without argument, clear all breaks (but first ask confirmation).
 
@@ -406,6 +417,30 @@
 
    .. versionadded:: 3.2
 
+.. pdbcommand:: display [expression]
+
+   Display the value of the expression if it changed, each time execution stops
+   in the current frame.
+
+   Without expression, list all display expressions for the current frame.
+
+   .. versionadded:: 3.2
+
+.. pdbcommand:: undisplay [expression]
+
+   Do not display the expression any more in the current frame.  Without
+   expression, clear all display expressions for the current frame.
+
+   .. versionadded:: 3.2
+
+.. pdbcommand:: interact
+
+   Start an interative interpreter (using the :mod:`code` module) whose global
+   namespace contains all the (global and local) names found in the current
+   scope.
+
+   .. versionadded:: 3.2
+
 .. _debugger-aliases:
 
 .. pdbcommand:: alias [name [command]]

Modified: python/branches/py3k-cdecimal/Doc/library/pickle.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/pickle.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/pickle.rst	Sun Jan  2 13:18:37 2011
@@ -42,7 +42,7 @@
 objects.  :mod:`marshal` exists primarily to support Python's :file:`.pyc`
 files.
 
-The :mod:`pickle` module differs from :mod:`marshal` several significant ways:
+The :mod:`pickle` module differs from :mod:`marshal` in several significant ways:
 
 * The :mod:`pickle` module keeps track of the objects it has already serialized,
   so that later references to the same object won't be serialized again.

Modified: python/branches/py3k-cdecimal/Doc/library/pkgutil.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/pkgutil.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/pkgutil.rst	Sun Jan  2 13:18:37 2011
@@ -77,8 +77,8 @@
    newly created by a path hook.
 
    If there is no importer, a wrapper around the basic import machinery is
-   returned.  This wrapper is never inserted into the importer cache (None is
-   inserted instead).
+   returned.  This wrapper is never inserted into the importer cache (``None``
+   is inserted instead).
 
    The cache (or part of it) can be cleared manually if a rescan of
    :data:`sys.path_hooks` is necessary.

Modified: python/branches/py3k-cdecimal/Doc/library/platform.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/platform.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/platform.rst	Sun Jan  2 13:18:37 2011
@@ -36,6 +36,16 @@
    and then only if the executable points to the Python interpreter.  Reasonable
    defaults are used when the above needs are not met.
 
+   .. note::
+
+      On Mac OS X (and perhaps other platforms), executable files may be
+      universal files containing multiple architectures.
+
+      To get at the "64-bitness" of the current interpreter, it is more
+      reliable to query the :attr:`sys.maxsize` attribute::
+
+         is_64bits = sys.maxsize > 2**32
+
 
 .. function:: machine()
 
@@ -186,7 +196,7 @@
 
    .. note::
 
-      Note: this function works best with Mark Hammond's
+      This function works best with Mark Hammond's
       :mod:`win32all` package installed, but also on Python 2.3 and
       later (support for this was added in Python 2.6). It obviously
       only runs on Win32 compatible platforms.

Modified: python/branches/py3k-cdecimal/Doc/library/pty.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/pty.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/pty.rst	Sun Jan  2 13:18:37 2011
@@ -45,3 +45,50 @@
    a file descriptor. The defaults try to read 1024 bytes each time they are
    called.
 
+
+Example
+-------
+
+.. sectionauthor:: Steen Lumholt
+
+The following program acts like the Unix command :manpage:`script(1)`, using a
+pseudo-terminal to record all input and output of a terminal session in a
+"typescript". ::
+
+   import sys, os, time, getopt
+   import pty
+
+   mode = 'wb'
+   shell = 'sh'
+   filename = 'typescript'
+   if 'SHELL' in os.environ:
+       shell = os.environ['SHELL']
+
+   try:
+       opts, args = getopt.getopt(sys.argv[1:], 'ap')
+   except getopt.error as msg:
+       print('%s: %s' % (sys.argv[0], msg))
+       sys.exit(2)
+
+   for opt, arg in opts:
+       # option -a: append to typescript file
+       if opt == '-a':
+           mode = 'ab'
+       # option -p: use a Python shell as the terminal command
+       elif opt == '-p':
+           shell = sys.executable
+   if args:
+       filename = args[0]
+
+   script = open(filename, mode)
+
+   def read(fd):
+       data = os.read(fd, 1024)
+       script.write(data)
+       return data
+
+   sys.stdout.write('Script started, file is %s\n' % filename)
+   script.write(('Script started on %s\n' % time.asctime()).encode())
+   pty.spawn(shell, read)
+   script.write(('Script done on %s\n' % time.asctime()).encode())
+   sys.stdout.write('Script done, file is %s\n' % filename)

Modified: python/branches/py3k-cdecimal/Doc/library/py_compile.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/py_compile.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/py_compile.rst	Sun Jan  2 13:18:37 2011
@@ -22,20 +22,29 @@
    Exception raised when an error occurs while attempting to compile the file.
 
 
-.. function:: compile(file, cfile=None, dfile=None, doraise=False)
+.. function:: compile(file, cfile=None, dfile=None, doraise=False, optimize=-1)
 
-   Compile a source file to byte-code and write out the byte-code cache  file.  The
-   source code is loaded from the file name *file*.  The  byte-code is written to
-   *cfile*, which defaults to the :PEP:`3147` path, ending in ``.pyc``
-   (``'.pyo`` if optimization is enabled in the current interpreter).  For
-   example, if *file* is ``/foo/bar/baz.py`` *cfile* will default to
-   ``/foo/bar/__pycache__/baz.cpython-32.pyc`` for Python 3.2.  If *dfile* is specified, it is used as the
-   name of the source file in error messages instead of *file*.  If *doraise* is
-   true, a :exc:`PyCompileError` is raised when an error is encountered while
-   compiling *file*. If *doraise* is false (the default), an error string is
-   written to ``sys.stderr``, but no exception is raised.  This function
-   returns the path to byte-compiled file, i.e. whatever *cfile* value was
-   used.
+   Compile a source file to byte-code and write out the byte-code cache  file.
+   The source code is loaded from the file name *file*.  The  byte-code is
+   written to *cfile*, which defaults to the :PEP:`3147` path, ending in
+   ``.pyc`` (``.pyo`` if optimization is enabled in the current interpreter).
+   For example, if *file* is ``/foo/bar/baz.py`` *cfile* will default to
+   ``/foo/bar/__pycache__/baz.cpython-32.pyc`` for Python 3.2.  If *dfile* is
+   specified, it is used as the name of the source file in error messages when
+   instead of *file*.  If *doraise* is true, a :exc:`PyCompileError` is raised
+   when an error is encountered while compiling *file*. If *doraise* is false
+   (the default), an error string is written to ``sys.stderr``, but no exception
+   is raised.  This function returns the path to byte-compiled file, i.e.
+   whatever *cfile* value was used.
+
+   *optimize* controls the optimization level and is passed to the built-in
+   :func:`compile` function.  The default of ``-1`` selects the optimization
+   level of the current interpreter.
+
+   .. versionchanged:: 3.2
+      Changed default value of *cfile* to be :PEP:`3147`-compliant.  Previous
+      default was *file* + ``'c'`` (``'o'`` if optimization was enabled).
+      Also added the *optimize* parameter.
 
 
 .. function:: main(args=None)
@@ -44,6 +53,11 @@
    line, if *args* is ``None``) are compiled and the resulting bytecode is
    cached in the normal manner.  This function does not search a directory
    structure to locate source files; it only compiles files named explicitly.
+   If ``'-'`` is the only parameter in args, the list of files is taken from
+   standard input.
+
+   .. versionchanged:: 3.2
+      Added support for ``'-'``.
 
 When this module is run as a script, the :func:`main` is used to compile all the
 files named on the command line.  The exit status is nonzero if one of the files

Modified: python/branches/py3k-cdecimal/Doc/library/pydoc.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/pydoc.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/pydoc.rst	Sun Jan  2 13:18:37 2011
@@ -50,12 +50,21 @@
 module is the first line of its documentation string.
 
 You can also use :program:`pydoc` to start an HTTP server on the local machine
-that will serve documentation to visiting Web browsers. :program:`pydoc -p 1234`
-will start a HTTP server on port 1234, allowing you to browse
-the documentation at ``http://localhost:1234/`` in your preferred Web browser.
+that will serve documentation to visiting Web browsers.  :program:`pydoc -p 1234`
+will start a HTTP server on port 1234, allowing you to browse the
+documentation at ``http://localhost:1234/`` in your preferred Web browser.
+Specifying ``0`` as the port number will select an arbitrary unused port.
+
 :program:`pydoc -g` will start the server and additionally bring up a
 small :mod:`tkinter`\ -based graphical interface to help you search for
-documentation pages.
+documentation pages.  The ``-g`` option is deprecated, since the server can
+now be controlled directly from HTTP clients.
+
+:program:`pydoc -b` will start the server and additionally open a web
+browser to a module index page.  Each served page has a navigation bar at the
+top where you can *Get* help on an individual item, *Search* all modules with a
+keyword in their synopsis line, and go to the *Module index*, *Topics* and
+*Keywords* pages.
 
 When :program:`pydoc` generates documentation, it uses the current environment
 and path to locate modules.  Thus, invoking :program:`pydoc spam`
@@ -69,3 +78,5 @@
 to a different URL or to a local directory containing the Library
 Reference Manual pages.
 
+.. versionchanged:: 3.2
+   Added the ``-b`` option, deprecated the ``-g`` option.

Modified: python/branches/py3k-cdecimal/Doc/library/random.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/random.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/random.rst	Sun Jan  2 13:18:37 2011
@@ -233,41 +233,18 @@
    parameter.
 
 
-Alternative Generators:
+Alternative Generator:
 
 .. class:: SystemRandom([seed])
 
    Class that uses the :func:`os.urandom` function for generating random numbers
    from sources provided by the operating system. Not available on all systems.
-   Does not rely on software state and sequences are not reproducible. Accordingly,
+   Does not rely on software state, and sequences are not reproducible. Accordingly,
    the :meth:`seed` method has no effect and is ignored.
    The :meth:`getstate` and :meth:`setstate` methods raise
    :exc:`NotImplementedError` if called.
 
 
-Examples of basic usage::
-
-   >>> random.random()        # Random float x, 0.0 <= x < 1.0
-   0.37444887175646646
-   >>> random.uniform(1, 10)  # Random float x, 1.0 <= x < 10.0
-   1.1800146073117523
-   >>> random.randint(1, 10)  # Integer from 1 to 10, endpoints included
-   7
-   >>> random.randrange(0, 101, 2)  # Even integer from 0 to 100
-   26
-   >>> random.choice('abcdefghij')  # Choose a random element
-   'c'
-
-   >>> items = [1, 2, 3, 4, 5, 6, 7]
-   >>> random.shuffle(items)
-   >>> items
-   [7, 3, 2, 5, 6, 4, 1]
-
-   >>> random.sample([1, 2, 3, 4, 5],  3)  # Choose 3 elements
-   [4, 1, 5]
-
-
-
 .. seealso::
 
    M. Matsumoto and T. Nishimura, "Mersenne Twister: A 623-dimensionally
@@ -280,8 +257,9 @@
    random number generator with a long period and comparatively simple update
    operations.
 
+
 Notes on Reproducibility
-========================
+------------------------
 
 Sometimes it is useful to be able to reproduce the sequences given by a pseudo
 random number generator.  By re-using a seed value, the same sequence should be
@@ -295,3 +273,53 @@
 
 * The generator's :meth:`random` method will continue to produce the same
   sequence when the compatible seeder is given the same seed.
+
+.. _random-examples:
+
+Examples and Recipes
+--------------------
+
+Basic usage::
+
+   >>> random.random()                      # Random float x, 0.0 <= x < 1.0
+   0.37444887175646646
+
+   >>> random.uniform(1, 10)                # Random float x, 1.0 <= x < 10.0
+   1.1800146073117523
+
+   >>> random.randrange(10)                 # Integer from 0 to 9
+   7
+
+   >>> random.randrange(0, 101, 2)          # Even integer from 0 to 100
+   26
+
+   >>> random.choice('abcdefghij')          # Single random element
+   'c'
+
+   >>> items = [1, 2, 3, 4, 5, 6, 7]
+   >>> random.shuffle(items)
+   >>> items
+   [7, 3, 2, 5, 6, 4, 1]
+
+   >>> random.sample([1, 2, 3, 4, 5],  3)   # Three samples without replacement
+   [4, 1, 5]
+
+A common task is to make a :func:`random.choice` with weighted probababilites.
+
+If the weights are small integer ratios, a simple technique is to build a sample
+population with repeats::
+
+    >>> weighted_choices = [('Red', 3), ('Blue', 2), ('Yellow', 1), ('Green', 4)]
+    >>> population = [val for val, cnt in weighted_choices for i in range(cnt)]
+    >>> random.choice(population)
+    'Green'
+
+A more general approach is to arrange the weights in a cumulative distribution
+with :func:`itertools.accumulate`, and then locate the random value with
+:func:`bisect.bisect`::
+
+    >>> choices, weights = zip(*weighted_choices)
+    >>> cumdist = list(itertools.accumulate(weights))
+    >>> x = random.random() * cumdist[-1]
+    >>> choices[bisect.bisect(cumdist, x)]
+    'Blue'

Modified: python/branches/py3k-cdecimal/Doc/library/re.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/re.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/re.rst	Sun Jan  2 13:18:37 2011
@@ -991,8 +991,10 @@
    The string passed to :meth:`~regex.match` or :meth:`~regex.search`.
 
 
-Examples
---------
+.. _re-examples:
+
+Regular Expression Examples
+---------------------------
 
 
 Checking For a Pair
@@ -1298,6 +1300,7 @@
     Token = collections.namedtuple('Token', 'typ value line column')
 
     def tokenize(s):
+        keywords = {'IF', 'THEN', 'FOR', 'NEXT', 'GOSUB', 'RETURN'}
         tok_spec = [
             ('NUMBER', r'\d+(\.\d*)?'), # Integer or decimal number
             ('ASSIGN', r':='),          # Assignment operator
@@ -1318,6 +1321,8 @@
                 line_start = pos
                 line += 1
             elif typ != 'SKIP':
+                if typ == 'ID' and val in keywords:
+                    typ = val
                 yield Token(typ, mo.group(typ), line, mo.start()-line_start)
             pos = mo.end()
             mo = gettok(s, pos)

Modified: python/branches/py3k-cdecimal/Doc/library/runpy.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/runpy.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/runpy.rst	Sun Jan  2 13:18:37 2011
@@ -70,6 +70,9 @@
    .. versionchanged:: 3.1
       Added ability to execute packages by looking for a ``__main__`` submodule.
 
+   .. versionchanged:: 3.2
+      Added ``__cached__`` global variable (see :PEP:`3147`).
+
 
 .. function:: run_path(file_path, init_globals=None, run_name=None)
 

Modified: python/branches/py3k-cdecimal/Doc/library/shelve.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/shelve.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/shelve.rst	Sun Jan  2 13:18:37 2011
@@ -101,7 +101,7 @@
   implementation used.
 
 
-.. class:: Shelf(dict, protocol=None, writeback=False)
+.. class:: Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8')
 
    A subclass of :class:`collections.MutableMapping` which stores pickled values
    in the *dict* object.
@@ -115,8 +115,15 @@
    This allows natural operations on mutable entries, but can consume much more
    memory and make sync and close take a long time.
 
+   The *keyencoding* parameter is the encoding used to encode keys before they
+   are used with the underlying dict.
 
-.. class:: BsdDbShelf(dict, protocol=None, writeback=False)
+   .. versionadded:: 3.2
+      The *keyencoding* parameter; previously, keys were always encoded in
+      UTF-8.
+
+
+.. class:: BsdDbShelf(dict, protocol=None, writeback=False, keyencoding='utf-8')
 
    A subclass of :class:`Shelf` which exposes :meth:`first`, :meth:`!next`,
    :meth:`previous`, :meth:`last` and :meth:`set_location` which are available
@@ -125,8 +132,8 @@
    modules.  The *dict* object passed to the constructor must support those
    methods.  This is generally accomplished by calling one of
    :func:`bsddb.hashopen`, :func:`bsddb.btopen` or :func:`bsddb.rnopen`.  The
-   optional *protocol* and *writeback* parameters have the same interpretation
-   as for the :class:`Shelf` class.
+   optional *protocol*, *writeback*, and *keyencoding* parameters have the same
+   interpretation as for the :class:`Shelf` class.
 
 
 .. class:: DbfilenameShelf(filename, flag='c', protocol=None, writeback=False)

Modified: python/branches/py3k-cdecimal/Doc/library/socket.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/socket.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/socket.rst	Sun Jan  2 13:18:37 2011
@@ -14,16 +14,6 @@
    Some behavior may be platform dependent, since calls are made to the operating
    system socket APIs.
 
-For an introduction to socket programming (in C), see the following papers: An
-Introductory 4.3BSD Interprocess Communication Tutorial, by Stuart Sechrest and
-An Advanced 4.3BSD Interprocess Communication Tutorial, by Samuel J.  Leffler et
-al, both in the UNIX Programmer's Manual, Supplementary Documents 1 (sections
-PS1:7 and PS1:8).  The platform-specific reference material for the various
-socket-related system calls are also a valuable source of information on the
-details of socket semantics.  For Unix, refer to the manual pages; for Windows,
-see the WinSock (or Winsock 2) specification. For IPv6-ready APIs, readers may
-want to refer to :rfc:`3493` titled Basic Socket Interface Extensions for IPv6.
-
 .. index:: object: socket
 
 The Python interface is a straightforward transliteration of the Unix system
@@ -34,26 +24,63 @@
 files, buffer allocation on receive operations is automatic, and buffer length
 is implicit on send operations.
 
-Socket addresses are represented as follows: A single string is used for the
-:const:`AF_UNIX` address family. A pair ``(host, port)`` is used for the
-:const:`AF_INET` address family, where *host* is a string representing either a
-hostname in Internet domain notation like ``'daring.cwi.nl'`` or an IPv4 address
-like ``'100.50.200.5'``, and *port* is an integral port number. For
-:const:`AF_INET6` address family, a four-tuple ``(host, port, flowinfo,
-scopeid)`` is used, where *flowinfo* and *scopeid* represents ``sin6_flowinfo``
-and ``sin6_scope_id`` member in :const:`struct sockaddr_in6` in C. For
-:mod:`socket` module methods, *flowinfo* and *scopeid* can be omitted just for
-backward compatibility. Note, however, omission of *scopeid* can cause problems
-in manipulating scoped IPv6 addresses. Other address families are currently not
-supported. The address format required by a particular socket object is
-automatically selected based on the address family specified when the socket
-object was created.
+
+Socket families
+---------------
+
+Depending on the system and the build options, various socket families
+are supported by this module.
+
+Socket addresses are represented as follows:
+
+- A single string is used for the :const:`AF_UNIX` address family.
+
+- A pair ``(host, port)`` is used for the :const:`AF_INET` address family,
+  where *host* is a string representing either a hostname in Internet domain
+  notation like ``'daring.cwi.nl'`` or an IPv4 address like ``'100.50.200.5'``,
+  and *port* is an integral port number.
+
+- For :const:`AF_INET6` address family, a four-tuple ``(host, port, flowinfo,
+  scopeid)`` is used, where *flowinfo* and *scopeid* represent the ``sin6_flowinfo``
+  and ``sin6_scope_id`` members in :const:`struct sockaddr_in6` in C.  For
+  :mod:`socket` module methods, *flowinfo* and *scopeid* can be omitted just for
+  backward compatibility.  Note, however, omission of *scopeid* can cause problems
+  in manipulating scoped IPv6 addresses.
+
+- :const:`AF_NETLINK` sockets are represented as pairs ``(pid, groups)``.
+
+- Linux-only support for TIPC is available using the :const:`AF_TIPC`
+  address family.  TIPC is an open, non-IP based networked protocol designed
+  for use in clustered computer environments.  Addresses are represented by a
+  tuple, and the fields depend on the address type. The general tuple form is
+  ``(addr_type, v1, v2, v3 [, scope])``, where:
+
+  - *addr_type* is one of TIPC_ADDR_NAMESEQ, TIPC_ADDR_NAME, or
+    TIPC_ADDR_ID.
+  - *scope* is one of TIPC_ZONE_SCOPE, TIPC_CLUSTER_SCOPE, and
+    TIPC_NODE_SCOPE.
+  - If *addr_type* is TIPC_ADDR_NAME, then *v1* is the server type, *v2* is
+    the port identifier, and *v3* should be 0.
+
+    If *addr_type* is TIPC_ADDR_NAMESEQ, then *v1* is the server type, *v2*
+    is the lower port number, and *v3* is the upper port number.
+
+    If *addr_type* is TIPC_ADDR_ID, then *v1* is the node, *v2* is the
+    reference, and *v3* should be set to 0.
+
+    If *addr_type* is TIPC_ADDR_ID, then *v1* is the node, *v2* is the
+    reference, and *v3* should be set to 0.
+
+- Certain other address families (:const:`AF_BLUETOOTH`, :const:`AF_PACKET`)
+  support specific representations.
+
+  .. XXX document them!
 
 For IPv4 addresses, two special forms are accepted instead of a host address:
 the empty string represents :const:`INADDR_ANY`, and the string
-``''`` represents :const:`INADDR_BROADCAST`. The behavior is not
-available for IPv6 for backward compatibility, therefore, you may want to avoid
-these if you intend to support IPv6 with your Python programs.
+``''`` represents :const:`INADDR_BROADCAST`.  This behavior is not
+compatible with IPv6, therefore, you may want to avoid these if you intend
+to support IPv6 with your Python programs.
 
 If you use a hostname in the *host* portion of IPv4/v6 socket address, the
 program may show a nondeterministic behavior, as Python uses the first address
@@ -62,40 +89,18 @@
 resolution and/or the host configuration.  For deterministic behavior use a
 numeric address in *host* portion.
 
-AF_NETLINK sockets are represented as  pairs ``pid, groups``.
-
-
-Linux-only support for TIPC is also available using the :const:`AF_TIPC`
-address family. TIPC is an open, non-IP based networked protocol designed
-for use in clustered computer environments.  Addresses are represented by a
-tuple, and the fields depend on the address type. The general tuple form is
-``(addr_type, v1, v2, v3 [, scope])``, where:
-
-- *addr_type* is one of TIPC_ADDR_NAMESEQ, TIPC_ADDR_NAME, or
-  TIPC_ADDR_ID.
-- *scope* is one of TIPC_ZONE_SCOPE, TIPC_CLUSTER_SCOPE, and
-  TIPC_NODE_SCOPE.
-- If *addr_type* is TIPC_ADDR_NAME, then *v1* is the server type, *v2* is
-  the port identifier, and *v3* should be 0.
-
-  If *addr_type* is TIPC_ADDR_NAMESEQ, then *v1* is the server type, *v2*
-  is the lower port number, and *v3* is the upper port number.
-
-  If *addr_type* is TIPC_ADDR_ID, then *v1* is the node, *v2* is the
-  reference, and *v3* should be set to 0.
-
-  If *addr_type* is TIPC_ADDR_ID, then *v1* is the node, *v2* is the
-  reference, and *v3* should be set to 0.
-
-
 All errors raise exceptions.  The normal exceptions for invalid argument types
 and out-of-memory conditions can be raised; errors related to socket or address
-semantics raise the error :exc:`socket.error`.
+semantics raise :exc:`socket.error` or one of its subclasses.
 
 Non-blocking mode is supported through :meth:`~socket.setblocking`.  A
 generalization of this based on timeouts is supported through
 :meth:`~socket.settimeout`.
 
+
+Module contents
+---------------
+
 The module :mod:`socket` exports the following constants and functions:
 
 
@@ -144,7 +149,8 @@
 
    These constants represent the address (and protocol) families, used for the
    first argument to :func:`socket`.  If the :const:`AF_UNIX` constant is not
-   defined then this protocol is unsupported.
+   defined then this protocol is unsupported.  More constants may be available
+   depending on the system.
 
 
 .. data:: SOCK_STREAM
@@ -154,8 +160,9 @@
           SOCK_SEQPACKET
 
    These constants represent the socket types, used for the second argument to
-   :func:`socket`. (Only :const:`SOCK_STREAM` and :const:`SOCK_DGRAM` appear to be
-   generally useful.)
+   :func:`socket`.  More constants may be available depending on the system.
+   (Only :const:`SOCK_STREAM` and :const:`SOCK_DGRAM` appear to be generally
+   useful.)
 
 .. data:: SOCK_CLOEXEC
           SOCK_NONBLOCK
@@ -627,18 +634,24 @@
    is system-dependent (usually 5).
 
 
-.. method:: socket.makefile(mode='r', buffering=None, *, encoding=None, errors=None, newline=None)
+.. method:: socket.makefile(mode='r', buffering=None, *, encoding=None, \
+                            errors=None, newline=None)
 
    .. index:: single: I/O control; buffering
 
-   Return a :term:`file object` associated with the socket.  The exact
-   returned type depends on the arguments given to :meth:`makefile`.  These
-   arguments are interpreted the same way as by the built-in :func:`open`
-   function.
-
-   Closing the file object won't close the socket unless there are no
-   remaining references to the socket.  The socket must be in blocking mode
-   (it can not have a timeout).
+   Return a :term:`file object` associated with the socket.  The exact returned
+   type depends on the arguments given to :meth:`makefile`.  These arguments are
+   interpreted the same way as by the built-in :func:`open` function.
+
+   Closing the file object won't close the socket unless there are no remaining
+   references to the socket.  The socket must be in blocking mode (it can not
+   have a timeout).
+
+   .. note::
+
+      On Windows, the file-like object created by :meth:`makefile` cannot be
+      used where a file object with a file descriptor is expected, such as the
+      stream arguments of :meth:`subprocess.Popen`.
 
 
 .. method:: socket.recv(bufsize[, flags])
@@ -950,3 +963,21 @@
 
    # disabled promiscuous mode
    s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
+
+
+.. seealso::
+
+   For an introduction to socket programming (in C), see the following papers:
+
+   - *An Introductory 4.3BSD Interprocess Communication Tutorial*, by Stuart Sechrest
+
+   - *An Advanced 4.3BSD Interprocess Communication Tutorial*, by Samuel J.  Leffler et
+     al,
+
+   both in the UNIX Programmer's Manual, Supplementary Documents 1 (sections
+   PS1:7 and PS1:8).  The platform-specific reference material for the various
+   socket-related system calls are also a valuable source of information on the
+   details of socket semantics.  For Unix, refer to the manual pages; for Windows,
+   see the WinSock (or Winsock 2) specification.  For IPv6-ready APIs, readers may
+   want to refer to :rfc:`3493` titled Basic Socket Interface Extensions for IPv6.
+

Modified: python/branches/py3k-cdecimal/Doc/library/someos.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/someos.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/someos.rst	Sun Jan  2 13:18:37 2011
@@ -14,11 +14,11 @@
 
    select.rst
    threading.rst
-   dummy_threading.rst
-   _thread.rst
-   _dummy_thread.rst
-   concurrent.futures.rst
    multiprocessing.rst
+   concurrent.futures.rst
    mmap.rst
    readline.rst
    rlcompleter.rst
+   dummy_threading.rst
+   _thread.rst
+   _dummy_thread.rst

Modified: python/branches/py3k-cdecimal/Doc/library/sqlite3.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/sqlite3.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/sqlite3.rst	Sun Jan  2 13:18:37 2011
@@ -888,4 +888,4 @@
 .. [#f1] The sqlite3 module is not built with loadable extension support by
   default, because some platforms (notably Mac OS X) have SQLite libraries which
   are compiled without this feature. To get loadable extension support, you must
-  modify setup.py and and remove the line that sets SQLITE_OMIT_LOAD_EXTENSION.
+  pass --enable-loadable-sqlite-extensions to configure.

Modified: python/branches/py3k-cdecimal/Doc/library/stdtypes.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/stdtypes.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/stdtypes.rst	Sun Jan  2 13:18:37 2011
@@ -836,8 +836,8 @@
 must have a trailing comma, such as ``(d,)``.
 
 Objects of type range are created using the :func:`range` function.  They don't
-support slicing, concatenation or repetition, and using ``in``, ``not in``,
-:func:`min` or :func:`max` on them is inefficient.
+support concatenation or repetition, and using :func:`min` or :func:`max` on
+them is inefficient.
 
 Most sequence types support the following operations.  The ``in`` and ``not in``
 operations have the same priorities as the comparison operations.  The ``+`` and
@@ -1078,20 +1078,26 @@
 .. method:: str.isalnum()
 
    Return true if all characters in the string are alphanumeric and there is at
-   least one character, false otherwise.
+   least one character, false otherwise.  A character ``c`` is alphanumeric if one
+   of the following returns ``True``: ``c.isalpha()``, ``c.isdecimal()``,
+   ``c.isdigit()``, or ``c.isnumeric()``.
 
 
 .. method:: str.isalpha()
 
    Return true if all characters in the string are alphabetic and there is at least
-   one character, false otherwise.
+   one character, false otherwise.  Alphabetic characters are those characters defined
+   in the Unicode character database as "Letter", i.e., those with general category
+   property being one of "Lm", "Lt", "Lu", "Ll", or "Lo".  Note that this is different
+   from the "Alphabetic" property defined in the Unicode Standard.
 
 
 .. method:: str.isdecimal()
 
    Return true if all characters in the string are decimal
    characters and there is at least one character, false
-   otherwise. Decimal characters include digit characters, and all characters
+   otherwise. Decimal characters are those from general category "Nd". This category
+   includes digit characters, and all characters
    that that can be used to form decimal-radix numbers, e.g. U+0660,
    ARABIC-INDIC DIGIT ZERO.
 
@@ -1099,7 +1105,9 @@
 .. method:: str.isdigit()
 
    Return true if all characters in the string are digits and there is at least one
-   character, false otherwise.
+   character, false otherwise.  Digits include decimal characters and digits that need
+   special handling, such as the compatibility superscript digits.  Formally, a digit
+   is a character that has the property value Numeric_Type=Digit or Numeric_Type=Decimal.
 
 
 .. method:: str.isidentifier()
@@ -1111,7 +1119,9 @@
 .. method:: str.islower()
 
    Return true if all cased characters in the string are lowercase and there is at
-   least one cased character, false otherwise.
+   least one cased character, false otherwise.  Cased characters are those with
+   general category property being one of "Lu", "Ll", or "Lt" and lowercase characters
+   are those with general category property "Ll".
 
 
 .. method:: str.isnumeric()
@@ -1120,7 +1130,8 @@
    characters, and there is at least one character, false
    otherwise. Numeric characters include digit characters, and all characters
    that have the Unicode numeric value property, e.g. U+2155,
-   VULGAR FRACTION ONE FIFTH.
+   VULGAR FRACTION ONE FIFTH.  Formally, numeric characters are those with the property
+   value Numeric_Type=Digit, Numeric_Type=Decimal or Numeric_Type=Numeric.
 
 
 .. method:: str.isprintable()
@@ -1137,8 +1148,9 @@
 .. method:: str.isspace()
 
    Return true if there are only whitespace characters in the string and there is
-   at least one character, false otherwise.
-
+   at least one character, false otherwise.  Whitespace characters  are those
+   characters defined in the Unicode character database as "Other" or "Separator"
+   and those with bidirectional property being one of "WS", "B", or "S".
 
 .. method:: str.istitle()
 
@@ -1150,7 +1162,9 @@
 .. method:: str.isupper()
 
    Return true if all cased characters in the string are uppercase and there is at
-   least one cased character, false otherwise.
+   least one cased character, false otherwise. Cased characters are those with
+   general category property being one of "Lu", "Ll", or "Lt" and uppercase characters
+   are those with general category property "Lu".
 
 
 .. method:: str.join(iterable)
@@ -2279,8 +2293,8 @@
 ===============
 
 :class:`memoryview` objects allow Python code to access the internal data
-of an object that supports the buffer protocol without copying.  Memory
-is generally interpreted as simple bytes.
+of an object that supports the :ref:`buffer protocol ` without
+copying.  Memory is generally interpreted as simple bytes.
 
 .. class:: memoryview(obj)
 
@@ -2419,6 +2433,10 @@
       A tuple of integers the length of :attr:`ndim` giving the size in bytes to
       access each element for each dimension of the array.
 
+   .. attribute:: readonly
+
+      A bool indicating whether the memory is read only.
+
    .. memoryview.suboffsets isn't documented because it only seems useful for C
 
 
@@ -2433,12 +2451,9 @@
    single: protocol; context management
 
 Python's :keyword:`with` statement supports the concept of a runtime context
-defined by a context manager.  This is implemented using two separate methods
+defined by a context manager.  This is implemented using a pair of methods
 that allow user-defined classes to define a runtime context that is entered
-before the statement body is executed and exited when the statement ends.
-
-The :dfn:`context management protocol` consists of a pair of methods that need
-to be provided for a context manager object to define a runtime context:
+before the statement body is executed and exited when the statement ends:
 
 
 .. method:: contextmanager.__enter__()
@@ -2486,9 +2501,9 @@
 their implementation of the context management protocol. See the
 :mod:`contextlib` module for some examples.
 
-Python's :term:`generator`\s and the ``contextlib.contextmanager`` :term:`decorator`
+Python's :term:`generator`\s and the :class:`contextlib.contextmanager` decorator
 provide a convenient way to implement these protocols.  If a generator function is
-decorated with the ``contextlib.contextmanager`` decorator, it will return a
+decorated with the :class:`contextlib.contextmanager` decorator, it will return a
 context manager implementing the necessary :meth:`__enter__` and
 :meth:`__exit__` methods, rather than the iterator produced by an undecorated
 generator function.

Modified: python/branches/py3k-cdecimal/Doc/library/string.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/string.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/string.rst	Sun Jan  2 13:18:37 2011
@@ -350,9 +350,18 @@
    |         | positive numbers, and a minus sign on negative numbers.  |
    +---------+----------------------------------------------------------+
 
-The ``'#'`` option is only valid for integers, and only for binary, octal, or
-hexadecimal output.  If present, it specifies that the output will be prefixed
-by ``'0b'``, ``'0o'``, or ``'0x'``, respectively.
+
+The ``'#'`` option causes the "alternate form" to be used for the
+conversion.  The alternate form is defined differently for different
+types.  This option is only valid for integer, float, complex and
+Decimal types. For integers, when binary, octal, or hexadecimal output
+is used, this option adds the prefix respective ``'0b'``, ``'0o'``, or
+``'0x'`` to the output value. For floats, complex and Decimal the
+alternate form causes the result of the conversion to always contain a
+decimal-point character, even if no digits follow it. Normally, a
+decimal-point character appears in the result of these conversions
+only if a digit follows it. In addition, for ``'g'`` and ``'G'``
+conversions, trailing zeros are not removed from the result.
 
 The ``','`` option signals the use of a comma for a thousands separator.
 For a locale aware separator, use the ``'n'`` integer presentation type

Modified: python/branches/py3k-cdecimal/Doc/library/struct.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/struct.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/struct.rst	Sun Jan  2 13:18:37 2011
@@ -164,58 +164,53 @@
 +--------+--------------------------+--------------------+----------------+------------+
 | ``c``  | :c:type:`char`           | bytes of length 1  | 1              |            |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``b``  | :c:type:`signed char`    | integer            | 1              | \(1),\(4)  |
+| ``b``  | :c:type:`signed char`    | integer            | 1              | \(1),\(3)  |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``B``  | :c:type:`unsigned char`  | integer            | 1              | \(4)       |
+| ``B``  | :c:type:`unsigned char`  | integer            | 1              | \(3)       |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``?``  | :c:type:`_Bool`          | bool               | 1              | \(2)       |
+| ``?``  | :c:type:`_Bool`          | bool               | 1              | \(1)       |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``h``  | :c:type:`short`          | integer            | 2              | \(4)       |
+| ``h``  | :c:type:`short`          | integer            | 2              | \(3)       |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``H``  | :c:type:`unsigned short` | integer            | 2              | \(4)       |
+| ``H``  | :c:type:`unsigned short` | integer            | 2              | \(3)       |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``i``  | :c:type:`int`            | integer            | 4              | \(4)       |
+| ``i``  | :c:type:`int`            | integer            | 4              | \(3)       |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``I``  | :c:type:`unsigned int`   | integer            | 4              | \(4)       |
+| ``I``  | :c:type:`unsigned int`   | integer            | 4              | \(3)       |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``l``  | :c:type:`long`           | integer            | 4              | \(4)       |
+| ``l``  | :c:type:`long`           | integer            | 4              | \(3)       |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``L``  | :c:type:`unsigned long`  | integer            | 4              | \(4)       |
+| ``L``  | :c:type:`unsigned long`  | integer            | 4              | \(3)       |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``q``  | :c:type:`long long`      | integer            | 8              | \(3), \(4) |
+| ``q``  | :c:type:`long long`      | integer            | 8              | \(2), \(3) |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``Q``  | :c:type:`unsigned long   | integer            | 8              | \(3), \(4) |
+| ``Q``  | :c:type:`unsigned long   | integer            | 8              | \(2), \(3) |
 |        | long`                    |                    |                |            |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``f``  | :c:type:`float`          | float              | 4              | \(5)       |
+| ``f``  | :c:type:`float`          | float              | 4              | \(4)       |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``d``  | :c:type:`double`         | float              | 8              | \(5)       |
+| ``d``  | :c:type:`double`         | float              | 8              | \(4)       |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``s``  | :c:type:`char[]`         | bytes              |                | \(1)       |
+| ``s``  | :c:type:`char[]`         | bytes              |                |            |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``p``  | :c:type:`char[]`         | bytes              |                | \(1)       |
+| ``p``  | :c:type:`char[]`         | bytes              |                |            |
 +--------+--------------------------+--------------------+----------------+------------+
-| ``P``  | :c:type:`void \*`        | integer            |                | \(6)       |
+| ``P``  | :c:type:`void \*`        | integer            |                | \(5)       |
 +--------+--------------------------+--------------------+----------------+------------+
 
 Notes:
 
 (1)
-   The ``c``, ``s`` and ``p`` conversion codes operate on :class:`bytes`
-   objects, but packing with such codes also supports :class:`str` objects,
-   which are encoded using UTF-8.
-
-(2)
    The ``'?'`` conversion code corresponds to the :c:type:`_Bool` type defined by
    C99. If this type is not available, it is simulated using a :c:type:`char`. In
    standard mode, it is always represented by one byte.
 
-(3)
+(2)
    The ``'q'`` and ``'Q'`` conversion codes are available in native mode only if
    the platform C compiler supports C :c:type:`long long`, or, on Windows,
    :c:type:`__int64`.  They are always available in standard modes.
 
-(4)
+(3)
    When attempting to pack a non-integer using any of the integer conversion
    codes, if the non-integer has a :meth:`__index__` method then that method is
    called to convert the argument to an integer before packing.
@@ -223,12 +218,12 @@
    .. versionchanged:: 3.2
       Use of the :meth:`__index__` method for non-integers is new in 3.2.
 
-(5)
+(4)
    For the ``'f'`` and ``'d'`` conversion codes, the packed representation uses
    the IEEE 754 binary32 (for ``'f'``) or binary64 (for ``'d'``) format,
    regardless of the floating-point format used by the platform.
 
-(6)
+(5)
    The ``'P'`` format character is only available for the native byte ordering
    (selected as the default or with the ``'@'`` byte order character). The byte
    order character ``'='`` chooses to use little- or big-endian ordering based
@@ -310,9 +305,9 @@
 The ordering of format characters may have an impact on size since the padding
 needed to satisfy alignment requirements is different::
 
-    >>> pack('ci', '*', 0x12131415)
+    >>> pack('ci', b'*', 0x12131415)
     b'*\x00\x00\x00\x12\x13\x14\x15'
-    >>> pack('ic', 0x12131415, '*')
+    >>> pack('ic', 0x12131415, b'*')
     b'\x12\x13\x14\x15*'
     >>> calcsize('ci')
     8

Modified: python/branches/py3k-cdecimal/Doc/library/subprocess.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/subprocess.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/subprocess.rst	Sun Jan  2 13:18:37 2011
@@ -28,7 +28,7 @@
 This module defines one class called :class:`Popen`:
 
 
-.. class:: Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False)
+.. class:: Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, restore_signals=True, start_new_session=False, pass_fds=())
 
    Arguments are:
 
@@ -153,12 +153,22 @@
 
    If *close_fds* is true, all file descriptors except :const:`0`, :const:`1` and
    :const:`2` will be closed before the child process is executed. (Unix only).
-   Or, on Windows, if *close_fds* is true then no handles will be inherited by the
+   The default varies by platform:  Always true on Unix.  On Windows it is
+   true when *stdin*/*stdout*/*stderr* are :const:`None`, false otherwise.
+   On Windows, if *close_fds* is true then no handles will be inherited by the
    child process.  Note that on Windows, you cannot set *close_fds* to true and
    also redirect the standard handles by setting *stdin*, *stdout* or *stderr*.
 
-   If *shell* is :const:`True`, the specified command will be executed through the
-   shell.
+   .. versionchanged:: 3.2
+      The default for *close_fds* was changed from :const:`False` to
+      what is described above.
+
+   *pass_fds* is an optional sequence of file descriptors to keep open
+   between the parent and child.  Providing any *pass_fds* forces
+   *close_fds* to be :const:`True`.  (Unix only)
+
+   .. versionadded:: 3.2
+      The *pass_fds* parameter was added.
 
    If *cwd* is not ``None``, the child's current directory will be changed to *cwd*
    before it is executed.  Note that this directory is not considered when
@@ -208,6 +218,16 @@
    underlying CreateProcess() function.  They can specify things such as appearance
    of the main window and priority for the new process.  (Windows only)
 
+   Popen objects are supported as context managers via the :keyword:`with` statement,
+   closing any open file descriptors on exit.
+   ::
+
+      with Popen(["ifconfig"], stdout=PIPE) as proc:
+          log.write(proc.stdout.read())
+
+   .. versionchanged:: 3.2
+      Added context manager support.
+
 
 .. data:: PIPE
 
@@ -639,4 +659,5 @@
 * ``stdin=PIPE`` and ``stdout=PIPE`` must be specified.
 
 * popen2 closes all file descriptors by default, but you have to specify
-  ``close_fds=True`` with :class:`Popen`.
+  ``close_fds=True`` with :class:`Popen` to guarantee this behavior on
+  all platforms or past Python versions.

Modified: python/branches/py3k-cdecimal/Doc/library/sys.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/sys.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/sys.rst	Sun Jan  2 13:18:37 2011
@@ -99,13 +99,39 @@
 
 .. function:: displayhook(value)
 
-   If *value* is not ``None``, this function prints it to ``sys.stdout``, and saves
-   it in ``builtins._``.
+   If *value* is not ``None``, this function prints ``repr(value)`` to
+   ``sys.stdout``, and saves *value* in ``builtins._``. If ``repr(value)`` is
+   not encodable to ``sys.stdout.encoding`` with ``sys.stdout.errors`` error
+   handler (which is probably ``'strict'``), encode it to
+   ``sys.stdout.encoding`` with ``'backslashreplace'`` error handler.
 
    ``sys.displayhook`` is called on the result of evaluating an :term:`expression`
    entered in an interactive Python session.  The display of these values can be
    customized by assigning another one-argument function to ``sys.displayhook``.
 
+   Pseudo-code::
+
+       def displayhook(value):
+           if value is None:
+               return
+           # Set '_' to None to avoid recursion
+           builtins._ = None
+           text = repr(value)
+           try:
+               sys.stdout.write(text)
+           except UnicodeEncodeError:
+               bytes = text.encode(sys.stdout.encoding, 'backslashreplace')
+               if hasattr(sys.stdout, 'buffer'):
+                   sys.stdout.buffer.write(bytes)
+               else:
+                   text = bytes.decode(sys.stdout.encoding, 'strict')
+                   sys.stdout.write(text)
+           sys.stdout.write("\n")
+           builtins._ = value
+
+   .. versionchanged:: 3.2
+      Use ``'backslashreplace'`` error handler on :exc:`UnicodeEncodeError`.
+
 
 .. function:: excepthook(type, value, traceback)
 
@@ -238,6 +264,11 @@
    +------------------------------+------------------------------------------+
    | :const:`bytes_warning`       | -b                                       |
    +------------------------------+------------------------------------------+
+   | :const:`quiet`               | -q                                       |
+   +------------------------------+------------------------------------------+
+
+   .. versionchanged:: 3.2
+      Added ``quiet`` attribute for the new :option:`-q` flag.
 
 
 .. data:: float_info
@@ -389,6 +420,9 @@
    additional garbage collector overhead if the object is managed by the garbage
    collector.
 
+   See `recursive sizeof recipe `_
+   for an example of using :func:`getsizeof` recursively to find the size of
+   containers and all their contents.
 
 .. function:: getswitchinterval()
 

Modified: python/branches/py3k-cdecimal/Doc/library/test.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/test.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/test.rst	Sun Jan  2 13:18:37 2011
@@ -6,11 +6,11 @@
 .. sectionauthor:: Brett Cannon 
 
 .. note::
-    The :mod:`test` package is meant for internal use by Python only. It is
-    documented for the benefit of the core developers of Python. Any use of
-    this package outside of Python's standard library is discouraged as code
-    mentioned here can change or be removed without notice between releases of
-    Python.
+   The :mod:`test` package is meant for internal use by Python only. It is
+   documented for the benefit of the core developers of Python. Any use of
+   this package outside of Python's standard library is discouraged as code
+   mentioned here can change or be removed without notice between releases of
+   Python.
 
 
 The :mod:`test` package contains all regression tests for Python as well as the
@@ -154,28 +154,31 @@
 
 .. _regrtest:
 
-Running tests using :mod:`test.regrtest`
-----------------------------------------
+Running tests using the command-line interface
+----------------------------------------------
 
-:mod:`test.regrtest` can be used as a script to drive Python's regression test
-suite. Running the script by itself automatically starts running all regression
+The :mod:`test` package can be run as a script to drive Python's regression
+test suite, thanks to the :option:`-m` option: :program:`python -m test`. Under
+the hood, it uses :mod:`test.regrtest`; the call :program:`python -m
+test.regrtest` used in previous Python versions still works).
+Running the script by itself automatically starts running all regression
 tests in the :mod:`test` package. It does this by finding all modules in the
 package whose name starts with ``test_``, importing them, and executing the
 function :func:`test_main` if present. The names of tests to execute may also
 be passed to the script. Specifying a single regression test (:program:`python
-regrtest.py test_spam.py`) will minimize output and only print
+-m test test_spam`) will minimize output and only print
 whether the test passed or failed and thus minimize output.
 
-Running :mod:`test.regrtest` directly allows what resources are available for
+Running :mod:`test` directly allows what resources are available for
 tests to use to be set. You do this by using the ``-u`` command-line
-option. Run :program:`python regrtest.py -uall` to turn on all
+option. Run :program:`python -m test -uall` to turn on all
 resources; specifying ``all`` as an option for ``-u`` enables all
 possible resources. If all but one resource is desired (a more common case), a
 comma-separated list of resources that are not desired may be listed after
-``all``. The command :program:`python regrtest.py -uall,-audio,-largefile`
-will run :mod:`test.regrtest` with all resources except the ``audio`` and
+``all``. The command :program:`python -m test -uall,-audio,-largefile`
+will run :mod:`test` with all resources except the ``audio`` and
 ``largefile`` resources. For a list of all resources and more command-line
-options, run :program:`python regrtest.py -h`.
+options, run :program:`python -m test -h`.
 
 Some other ways to execute the regression tests depend on what platform the
 tests are being executed on. On Unix, you can run :program:`make test` at the

Modified: python/branches/py3k-cdecimal/Doc/library/textwrap.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/textwrap.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/textwrap.rst	Sun Jan  2 13:18:37 2011
@@ -121,6 +121,13 @@
          each tab character will be replaced by a single space, which is *not*
          the same as tab expansion.
 
+      .. note::
+
+         If :attr:`replace_whitespace` is false, newlines may appear in the
+         middle of a line and cause strange output. For this reason, text should
+         be split into paragraphs (using :meth:`str.splitlines` or similar)
+         which are wrapped separately.
+
 
    .. attribute:: drop_whitespace
 

Modified: python/branches/py3k-cdecimal/Doc/library/threading.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/threading.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/threading.rst	Sun Jan  2 13:18:37 2011
@@ -1,8 +1,8 @@
-:mod:`threading` --- Higher-level threading interface
-=====================================================
+:mod:`threading` --- Thread-based parallelism
+=============================================
 
 .. module:: threading
-   :synopsis: Higher-level threading interface.
+   :synopsis: Thread-based parallelism.
 
 
 This module constructs higher-level threading interfaces on top of the lower
@@ -408,6 +408,9 @@
    .. versionchanged:: 3.2
       The *timeout* parameter is new.
 
+   .. versionchanged:: 3.2
+      Lock acquires can now be interrupted by signals on POSIX.
+
 
 .. method:: Lock.release()
 

Modified: python/branches/py3k-cdecimal/Doc/library/tkinter.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/tkinter.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/tkinter.rst	Sun Jan  2 13:18:37 2011
@@ -659,9 +659,7 @@
 
 scrollcommand
    This is almost always the :meth:`!set` method of some scrollbar widget, but can
-   be any widget method that takes a single argument.   Refer to the file
-   :file:`Demo/tkinter/matt/canvas-with-scrollbars.py` in the Python source
-   distribution for an example.
+   be any widget method that takes a single argument.
 
 wrap:
    Must be one of: ``"none"``, ``"char"``, or ``"word"``.

Modified: python/branches/py3k-cdecimal/Doc/library/tkinter.tix.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/tkinter.tix.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/tkinter.tix.rst	Sun Jan  2 13:18:37 2011
@@ -84,11 +84,7 @@
 -----------
 
 `Tix `_
-introduces over 40 widget classes to the :mod:`tkinter` repertoire.  There is a
-demo of all the :mod:`tkinter.tix` widgets in the :file:`Demo/tix` directory of
-the standard distribution.
-
-.. The Python sample code is still being added to Python, hence commented out
+introduces over 40 widget classes to the :mod:`tkinter` repertoire.
 
 
 Basic Widgets

Modified: python/branches/py3k-cdecimal/Doc/library/trace.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/trace.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/trace.rst	Sun Jan  2 13:18:37 2011
@@ -17,103 +17,178 @@
 
 .. _trace-cli:
 
-Command Line Usage
+Command-Line Usage
 ------------------
 
 The :mod:`trace` module can be invoked from the command line.  It can be as
 simple as ::
 
-   python -m trace --count somefile.py ...
+   python -m trace --count -C . somefile.py ...
 
-The above will generate annotated listings of all Python modules imported during
-the execution of :file:`somefile.py`.
+The above will execute :file:`somefile.py` and generate annotated listings of
+all Python modules imported during the execution into the current directory.
 
-The following command-line arguments are supported:
+.. program:: trace
+
+.. cmdoption:: --help
+
+   Display usage and exit.
+
+.. cmdoption:: --version
+
+   Display the version of the module and exit.
+
+Main options
+^^^^^^^^^^^^
+
+At least one of the following options must be specified when invoking
+:mod:`trace`.  The :option:`--listfuncs <-l>` option is mutually exclusive with
+the :option:`--trace <-t>` and :option:`--counts <-c>` options . When
+:option:`--listfuncs <-l>` is provided, neither :option:`--counts <-c>` nor
+:option:`--trace <-t>` are accepted, and vice versa.
+
+.. program:: trace
+
+.. cmdoption:: -c, --count
+
+   Produce a set of annotated listing files upon program completion that shows
+   how many times each statement was executed.  See also
+   :option:`--coverdir <-C>`, :option:`--file <-f>` and
+   :option:`--no-report <-R>` below.
+
+.. cmdoption:: -t, --trace
 
-:option:`--trace`, :option:`-t`
    Display lines as they are executed.
 
-:option:`--count`, :option:`-c`
-   Produce a set of  annotated listing files upon program completion that shows how
-   many times each statement was executed.
+.. cmdoption:: -l, --listfuncs
+
+   Display the functions executed by running the program.
+
+.. cmdoption:: -r, --report
 
-:option:`--report`, :option:`-r`
    Produce an annotated list from an earlier program run that used the
-   :option:`--count` and :option:`--file` arguments.
+   :option:`--count <-c>` and :option:`--file <-f>` option.  This does not
+   execute any code.
 
-:option:`--no-report`, :option:`-R`
-   Do not generate annotated listings.  This is useful if you intend to make
-   several runs with :option:`--count` then produce a single set of annotated
-   listings at the end.
+.. cmdoption:: -T, --trackcalls
+
+   Display the calling relationships exposed by running the program.
+
+Modifiers
+^^^^^^^^^
+
+.. program:: trace
+
+.. cmdoption:: -f, --file=
 
-:option:`--listfuncs`, :option:`-l`
-   List the functions executed by running the program.
+   Name of a file to accumulate counts over several tracing runs.  Should be
+   used with the :option:`--count <-c>` option.
 
-:option:`--trackcalls`, :option:`-T`
-   Generate calling relationships exposed by running the program.
+.. cmdoption:: -C, --coverdir=
 
-:option:`--file`, :option:`-f`
-   Name a file containing (or to contain) counts.
+   Directory where the report files go.  The coverage report for
+   ``package.module`` is written to file :file:`{dir}/{package}/{module}.cover`.
 
-:option:`--coverdir`, :option:`-C`
-   Name a directory in which to save annotated listing files.
+.. cmdoption:: -m, --missing
 
-:option:`--missing`, :option:`-m`
    When generating annotated listings, mark lines which were not executed with
-   '``>>>>>>``'.
+   ``>>>>>>``.
 
-:option:`--summary`, :option:`-s`
-   When using :option:`--count` or :option:`--report`, write a brief summary to
-   stdout for each file processed.
-
-:option:`--ignore-module`
-   Accepts comma separated list of module names. Ignore each of the named
-   module and its submodules (if it is a package).  May be given
-   multiple times.
-
-:option:`--ignore-dir`
-   Ignore all modules and packages in the named directory and subdirectories
-   (multiple directories can be joined by os.pathsep).  May be given multiple
-   times.
+.. cmdoption:: -s, --summary
 
+   When using :option:`--count <-c>` or :option:`--report <-r>`, write a brief
+   summary to stdout for each file processed.
+
+.. cmdoption:: -R, --no-report
+
+   Do not generate annotated listings.  This is useful if you intend to make
+   several runs with :option:`--count <-c>`, and then produce a single set of
+   annotated listings at the end.
+
+.. cmdoption:: -g, --timing
+
+   Prefix each line with the time since the program started.  Only used while
+   tracing.
+
+Filters
+^^^^^^^
+
+These options may be repeated multiple times.
+
+.. program:: trace
+
+.. cmdoption:: --ignore-module=
+
+   Ignore each of the given module names and its submodules (if it is a
+   package).  The argument can be a list of names separated by a comma.
+
+.. cmdoption:: --ignore-dir=
+
+   Ignore all modules and packages in the named directory and subdirectories.
+   The argument can be a list of directories separated by :data:`os.pathsep`.
 
 .. _trace-api:
 
-Programming Interface
----------------------
+Programmatic Interface
+----------------------
+
+.. class:: Trace(count=1, trace=1, countfuncs=0, countcallers=0, ignoremods=(),\
+                 ignoredirs=(), infile=None, outfile=None, timing=False)
+
+   Create an object to trace execution of a single statement or expression.  All
+   parameters are optional.  *count* enables counting of line numbers.  *trace*
+   enables line execution tracing.  *countfuncs* enables listing of the
+   functions called during the run.  *countcallers* enables call relationship
+   tracking.  *ignoremods* is a list of modules or packages to ignore.
+   *ignoredirs* is a list of directories whose modules or packages should be
+   ignored.  *infile* is the name of the file from which to read stored count
+   information.  *outfile* is the name of the file in which to write updated
+   count information.  *timing* enables a timestamp relative to when tracing was
+   started to be displayed.
+
+    .. method:: run(cmd)
+
+       Execute the command and gather statistics from the execution with
+       the current tracing parameters.  *cmd* must be a string or code object,
+       suitable for passing into :func:`exec`.
 
+    .. method:: runctx(cmd, globals=None, locals=None)
 
-.. class:: Trace(count=1, trace=1, countfuncs=0, countcallers=0, ignoremods=(), ignoredirs=(), infile=None, outfile=None, timing=False)
+       Execute the command and gather statistics from the execution with the
+       current tracing parameters, in the defined global and local
+       environments.  If not defined, *globals* and *locals* default to empty
+       dictionaries.
 
-   Create an object to trace execution of a single statement or expression. All
-   parameters are optional.  *count* enables counting of line numbers. *trace*
-   enables line execution tracing.  *countfuncs* enables listing of the functions
-   called during the run.  *countcallers* enables call relationship tracking.
-   *ignoremods* is a list of modules or packages to ignore.  *ignoredirs* is a list
-   of directories whose modules or packages should be ignored.  *infile* is the
-   file from which to read stored count information.  *outfile* is a file in which
-   to write updated count information. *timing* enables a timestamp relative
-   to when tracing was started to be displayed.
+    .. method:: runfunc(func, *args, **kwds)
 
+       Call *func* with the given arguments under control of the :class:`Trace`
+       object with the current tracing parameters.
 
-.. method:: Trace.run(cmd)
+    .. method:: results()
 
-   Run *cmd* under control of the Trace object with the current tracing parameters.
+       Return a :class:`CoverageResults` object that contains the cumulative
+       results of all previous calls to ``run``, ``runctx`` and ``runfunc``
+       for the given :class:`Trace` instance.  Does not reset the accumulated
+       trace results.
 
+.. class:: CoverageResults
 
-.. method:: Trace.runctx(cmd, globals=None, locals=None)
+   A container for coverage results, created by :meth:`Trace.results`.  Should
+   not be created directly by the user.
 
-   Run *cmd* under control of the Trace object with the current tracing parameters
-   in the defined global and local environments.  If not defined, *globals* and
-   *locals* default to empty dictionaries.
+    .. method:: update(other)
 
+       Merge in data from another :class:`CoverageResults` object.
 
-.. method:: Trace.runfunc(func, *args, **kwds)
+    .. method:: write_results(show_missing=True, summary=False, coverdir=None)
 
-   Call *func* with the given arguments under control of the :class:`Trace` object
-   with the current tracing parameters.
+       Write coverage results.  Set *show_missing* to show lines that had no
+       hits.  Set *summary* to include in the output the coverage summary per
+       module.  *coverdir* specifies the directory into which the coverage
+       result files will be output.  If ``None``, the results for each source
+       file are placed in its directory.
 
-This is a simple example showing the use of this module::
+A simple example demonstrating the use of the programmatic interface::
 
    import sys
    import trace

Modified: python/branches/py3k-cdecimal/Doc/library/turtle.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/turtle.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/turtle.rst	Sun Jan  2 13:18:37 2011
@@ -2268,7 +2268,7 @@
 stored and an additional one in the current working directory.  The latter will
 override the settings of the first one.
 
-The :file:`Demo/turtle` directory contains a :file:`turtle.cfg` file.  You can
+The :file:`Lib/turtledemo` directory contains a :file:`turtle.cfg` file.  You can
 study it as an example and see its effects when running the demos (preferably
 not from within the demo-viewer).
 
@@ -2400,8 +2400,7 @@
   strings and numbers respectively.
 
 - Two example scripts :file:`tdemo_nim.py` and :file:`tdemo_round_dance.py`
-  have been added to the Demo directory (source distribution only). As usual
-  they can be viewed and executed within the demo viewer :file:`turtleDemo.py`.
+  have been added to the :file:`Lib/turtledemo` directory.
 
 
 .. doctest::

Modified: python/branches/py3k-cdecimal/Doc/library/unicodedata.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/unicodedata.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/unicodedata.rst	Sun Jan  2 13:18:37 2011
@@ -13,14 +13,15 @@
    single: character
    pair: Unicode; database
 
-This module provides access to the Unicode Character Database which defines
-character properties for all Unicode characters. The data in this database is
-based on the :file:`UnicodeData.txt` file version 5.2.0 which is publicly
-available from ftp://ftp.unicode.org/.
-
-The module uses the same names and symbols as defined by the UnicodeData File
-Format 5.2.0 (see http://www.unicode.org/reports/tr44/tr44-4.html).
-It defines the following functions:
+This module provides access to the Unicode Character Database (UCD) which
+defines character properties for all Unicode characters. The data contained in
+this database is compiled from the `UCD version 6.0.0
+`_.
+
+The module uses the same names and symbols as defined by Unicode
+Standard Annex #44, `"Unicode Character Database"
+`_.  It defines the
+following functions:
 
 
 .. function:: lookup(name)

Modified: python/branches/py3k-cdecimal/Doc/library/unittest.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/unittest.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/unittest.rst	Sun Jan  2 13:18:37 2011
@@ -191,7 +191,7 @@
 
 .. _unittest-command-line-interface:
 
-Command Line Interface
+Command-Line Interface
 ----------------------
 
 The unittest module can be used from the command line to run tests from
@@ -204,6 +204,16 @@
 You can pass in a list with any combination of module names, and fully
 qualified class or method names.
 
+Test modules can be specified by file path as well::
+
+   python -m unittest tests/test_something.py
+
+This allows you to use the shell filename completion to specify the test module.
+The file specified must still be importable as a module. The path is converted
+to a module name by removing the '.py' and converting path separators into '.'.
+If you want to execute a test file that isn't importable as a module you should
+execute the file directly instead.
+
 You can run tests with more detail (higher verbosity) by passing in the -v flag::
 
    python -m unittest -v test_module
@@ -221,8 +231,8 @@
    not modules or classes.
 
 
-failfast, catch and buffer command-line options
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Command-line options
+~~~~~~~~~~~~~~~~~~~~
 
 :program:`unittest` supports these command-line options:
 
@@ -247,7 +257,7 @@
    Stop the test run on the first error or failure.
 
 .. versionadded:: 3.2
-   The command-line options :option:`-c`, :option:`-b` and :option:`-f` were added.
+   The command-line options ``-b``, ``-c`` and ``-f`` were added.
 
 The command line can also be used for test discovery, for running all of the
 tests in a project or just a subset.
@@ -834,16 +844,16 @@
    +-----------------------------------------+-----------------------------+---------------+
 
    All the assert methods (except :meth:`assertRaises`,
-   :meth:`assertRaisesRegexp`, :meth:`assertWarns`, :meth:`assertWarnsRegexp`)
+   :meth:`assertRaisesRegex`, :meth:`assertWarns`, :meth:`assertWarnsRegex`)
    accept a *msg* argument that, if specified, is used as the error message on
    failure (see also :data:`longMessage`).
 
-   .. method:: assertEqual(first, second, msg=None)
+   .. method:: assertEqual(actual, expected, msg=None)
 
-      Test that *first* and *second* are equal.  If the values do not compare
-      equal, the test will fail.
+      Test that *actual* and *expected* are equal.  If the values do not
+      compare equal, the test will fail.
 
-      In addition, if *first* and *second* are the exact same type and one of
+      In addition, if *actual* and *expected* are the exact same type and one of
       list, tuple, dict, set, frozenset or str or any type that a subclass
       registers with :meth:`addTypeEqualityFunc` the type specific equality
       function will be called in order to generate a more useful default
@@ -858,10 +868,10 @@
          function for comparing strings.
 
 
-   .. method:: assertNotEqual(first, second, msg=None)
+   .. method:: assertNotEqual(actual, expected, msg=None)
 
-      Test that *first* and *second* are not equal.  If the values do compare
-      equal, the test will fail.
+      Test that *actual* and *expected* are not equal.  If the values do
+      compare equal, the test will fail.
 
    .. method:: assertTrue(expr, msg=None)
                assertFalse(expr, msg=None)
@@ -875,10 +885,11 @@
       provide a better error message in case of failure.
 
 
-   .. method:: assertIs(first, second, msg=None)
-               assertIsNot(first, second, msg=None)
+   .. method:: assertIs(actual, expected, msg=None)
+               assertIsNot(actual, expected, msg=None)
 
-      Test that *first* and *second* evaluate (or don't evaluate) to the same object.
+      Test that *actual* and *expected* evaluate (or don't evaluate) to the
+      same object.
 
       .. versionadded:: 3.1
 
@@ -918,14 +929,14 @@
    | :meth:`assertRaises(exc, fun, *args, **kwds)            | ``fun(*args, **kwds)`` raises `exc`  |            |
    | `                                |                                      |            |
    +---------------------------------------------------------+--------------------------------------+------------+
-   | :meth:`assertRaisesRegexp(exc, re, fun, *args, **kwds)  | ``fun(*args, **kwds)`` raises `exc`  | 3.1        |
-   | `                          | and the message matches `re`         |            |
+   | :meth:`assertRaisesRegex(exc, re, fun, *args, **kwds)   | ``fun(*args, **kwds)`` raises `exc`  | 3.1        |
+   | `                           | and the message matches `re`         |            |
    +---------------------------------------------------------+--------------------------------------+------------+
    | :meth:`assertWarns(warn, fun, *args, **kwds)            | ``fun(*args, **kwds)`` raises `warn` | 3.2        |
    | `                                 |                                      |            |
    +---------------------------------------------------------+--------------------------------------+------------+
-   | :meth:`assertWarnsRegexp(warn, re, fun, *args, **kwds)  | ``fun(*args, **kwds)`` raises `warn` | 3.2        |
-   | `                           | and the message matches `re`         |            |
+   | :meth:`assertWarnsRegex(warn, re, fun, *args, **kwds)   | ``fun(*args, **kwds)`` raises `warn` | 3.2        |
+   | `                            | and the message matches `re`         |            |
    +---------------------------------------------------------+--------------------------------------+------------+
 
    .. method:: assertRaises(exception, callable, *args, **kwds)
@@ -961,23 +972,26 @@
          Added the :attr:`exception` attribute.
 
 
-   .. method:: assertRaisesRegexp(exception, regexp, callable, *args, **kwds)
-               assertRaisesRegexp(exception, regexp)
+   .. method:: assertRaisesRegex(exception, regex, callable, *args, **kwds)
+               assertRaisesRegex(exception, regex)
 
-      Like :meth:`assertRaises` but also tests that *regexp* matches
-      on the string representation of the raised exception.  *regexp* may be
+      Like :meth:`assertRaises` but also tests that *regex* matches
+      on the string representation of the raised exception.  *regex* may be
       a regular expression object or a string containing a regular expression
       suitable for use by :func:`re.search`.  Examples::
 
-         self.assertRaisesRegexp(ValueError, 'invalid literal for.*XYZ$',
-                                 int, 'XYZ')
+         self.assertRaisesRegex(ValueError, 'invalid literal for.*XYZ$',
+                                int, 'XYZ')
 
       or::
 
-         with self.assertRaisesRegexp(ValueError, 'literal'):
+         with self.assertRaisesRegex(ValueError, 'literal'):
             int('XYZ')
 
       .. versionadded:: 3.1
+         under the name ``assertRaisesRegexp``.
+      .. versionchanged:: 3.2
+         Renamed to :meth:`assertRaisesRegex`.
 
 
    .. method:: assertWarns(warning, callable, *args, **kwds)
@@ -1014,21 +1028,21 @@
       .. versionadded:: 3.2
 
 
-   .. method:: assertWarnsRegexp(warning, regexp, callable, *args, **kwds)
-               assertWarnsRegexp(warning, regexp)
+   .. method:: assertWarnsRegex(warning, regex, callable, *args, **kwds)
+               assertWarnsRegex(warning, regex)
 
-      Like :meth:`assertWarns` but also tests that *regexp* matches on the
-      message of the triggered warning.  *regexp* may be a regular expression
+      Like :meth:`assertWarns` but also tests that *regex* matches on the
+      message of the triggered warning.  *regex* may be a regular expression
       object or a string containing a regular expression suitable for use
       by :func:`re.search`.  Example::
 
-         self.assertWarnsRegexp(DeprecationWarning,
-                                r'legacy_function\(\) is deprecated',
-                                legacy_function, 'XYZ')
+         self.assertWarnsRegex(DeprecationWarning,
+                               r'legacy_function\(\) is deprecated',
+                               legacy_function, 'XYZ')
 
       or::
 
-         with self.assertWarnsRegexp(RuntimeWarning, 'unsafe frobnicating'):
+         with self.assertWarnsRegex(RuntimeWarning, 'unsafe frobnicating'):
              frobnicate('/etc/passwd')
 
       .. versionadded:: 3.2
@@ -1058,47 +1072,44 @@
    | :meth:`assertLessEqual(a, b)          | ``a <= b``                     | 3.1          |
    | `           |                                |              |
    +---------------------------------------+--------------------------------+--------------+
-   | :meth:`assertRegexpMatches(s, re)     | ``regex.search(s)``            | 3.1          |
-   | `       |                                |              |
+   | :meth:`assertRegex(s, re)             | ``regex.search(s)``            | 3.1          |
+   | `               |                                |              |
    +---------------------------------------+--------------------------------+--------------+
-   | :meth:`assertNotRegexpMatches(s, re)  | ``not regex.search(s)``        | 3.2          |
-   | `    |                                |              |
+   | :meth:`assertNotRegex(s, re)          | ``not regex.search(s)``        | 3.2          |
+   | `            |                                |              |
    +---------------------------------------+--------------------------------+--------------+
-   | :meth:`assertDictContainsSubset(a, b) | all the key/value pairs        | 3.1          |
-   | `  | in `a` exist in `b`            |              |
-   +---------------------------------------+--------------------------------+--------------+
-   | :meth:`assertItemsEqual(a, b)         | `a` and `b` have the same      | 3.2          |
-   | `          | elements in the same number,   |              |
+   | :meth:`assertCountEqual(a, b)         | `a` and `b` have the same      | 3.2          |
+   | `          | elements in the same number,   |              |
    |                                       | regardless of their order      |              |
    +---------------------------------------+--------------------------------+--------------+
 
 
-   .. method:: assertAlmostEqual(first, second, places=7, msg=None, delta=None)
-               assertNotAlmostEqual(first, second, places=7, msg=None, delta=None)
+   .. method:: assertAlmostEqual(actual, expected, places=7, msg=None, delta=None)
+               assertNotAlmostEqual(actual, expected, places=7, msg=None, delta=None)
 
-      Test that *first* and *second* are approximately (or not approximately)
+      Test that *actual* and *expected* are approximately (or not approximately)
       equal by computing the difference, rounding to the given number of
       decimal *places* (default 7), and comparing to zero.  Note that these
       methods round the values to the given number of *decimal places* (i.e.
       like the :func:`round` function) and not *significant digits*.
 
       If *delta* is supplied instead of *places* then the difference
-      between *first* and *second* must be less (or more) than *delta*.
+      between *actual* and *expected* must be less (or more) than *delta*.
 
       Supplying both *delta* and *places* raises a ``TypeError``.
 
       .. versionchanged:: 3.2
-         assertAlmostEqual automatically considers almost equal objects that compare equal.
-         assertNotAlmostEqual automatically fails if the objects compare equal.
-         Added the ``delta`` keyword argument.
+         :meth:`assertAlmostEqual` automatically considers almost equal objects
+         that compare equal.  :meth:`assertNotAlmostEqual` automatically fails
+         if the objects compare equal.  Added the *delta* keyword argument.
 
 
-   .. method:: assertGreater(first, second, msg=None)
-               assertGreaterEqual(first, second, msg=None)
-               assertLess(first, second, msg=None)
-               assertLessEqual(first, second, msg=None)
+   .. method:: assertGreater(actual, expected, msg=None)
+               assertGreaterEqual(actual, expected, msg=None)
+               assertLess(actual, expected, msg=None)
+               assertLessEqual(actual, expected, msg=None)
 
-      Test that *first* is respectively >, >=, < or <= than *second* depending
+      Test that *actual* is respectively >, >=, < or <= than *expected* depending
       on the method name.  If not, the test will fail::
 
          >>> self.assertGreaterEqual(3, 4)
@@ -1107,54 +1118,64 @@
       .. versionadded:: 3.1
 
 
-   .. method:: assertRegexpMatches(text, regexp, msg=None)
-               assertNotRegexpMatches(text, regexp, msg=None)
+   .. method:: assertRegex(text, regex, msg=None)
+               assertNotRegex(text, regex, msg=None)
 
-      Test that a *regexp* search matches (or does not match) *text*.  In case
+      Test that a *regex* search matches (or does not match) *text*.  In case
       of failure, the error message will include the pattern and the *text* (or
-      the pattern and the part of *text* that unexpectedly matched).  *regexp*
+      the pattern and the part of *text* that unexpectedly matched).  *regex*
       may be a regular expression object or a string containing a regular
       expression suitable for use by :func:`re.search`.
 
-      .. versionadded:: 3.1 :meth:`~TestCase.assertRegexpMatches`
-      .. versionadded:: 3.2 :meth:`~TestCase.assertNotRegexpMatches`
+      .. versionadded:: 3.1
+         under the name ``assertRegexpMatches``.
+      .. versionchanged:: 3.2
+         The method ``assertRegexpMatches()`` has been renamed to
+         :meth:`.assertRegex`.
+      .. versionadded:: 3.2
+         :meth:`.assertNotRegex`.
 
 
-   .. method:: assertDictContainsSubset(expected, actual, msg=None)
+   .. method:: assertDictContainsSubset(subset, dictionary, msg=None)
 
-      Tests whether the key/value pairs in dictionary *actual* are a
-      superset of those in *expected*.  If not, an error message listing
-      the missing keys and mismatched values is generated.
+      Tests whether the key/value pairs in *dictionary* are a superset of
+      those in *subset*.  If not, an error message listing the missing keys
+      and mismatched values is generated.
+
+      Note, the arguments are in the opposite order of what the method name
+      dictates.  Instead, consider using the set-methods on :ref:`dictionary
+      views `, for example: ``d.keys() <= e.keys()`` or
+      ``d.items() <= d.items()``.
 
       .. versionadded:: 3.1
+      .. deprecated:: 3.2
 
 
-   .. method:: assertItemsEqual(actual, expected, msg=None)
+   .. method:: assertCountEqual(first, second, msg=None)
 
-      Test that sequence *expected* contains the same elements as *actual*,
+      Test that sequence *first* contains the same elements as *second*,
       regardless of their order. When they don't, an error message listing the
       differences between the sequences will be generated.
 
-      Duplicate elements are *not* ignored when comparing *actual* and
-      *expected*. It verifies if each element has the same count in both
-      sequences. It is the equivalent of ``assertEqual(sorted(expected),
-      sorted(actual))`` but it works with sequences of unhashable objects as
-      well.
+      Duplicate elements are *not* ignored when comparing *first* and
+      *second*. It verifies whether each element has the same count in both
+      sequences. Equivalent to:
+      ``assertEqual(Counter(list(first)), Counter(list(second)))``
+      but works with sequences of unhashable objects as well.
 
       .. versionadded:: 3.2
 
-
    .. method:: assertSameElements(actual, expected, msg=None)
 
-      Test that sequence *expected* contains the same elements as *actual*,
+      Test that sequence *actual* contains the same elements as *expected*,
       regardless of their order. When they don't, an error message listing
       the differences between the sequences will be generated.
 
       Duplicate elements are ignored when comparing *actual* and *expected*.
-      It is the equivalent of ``assertEqual(set(expected), set(actual))``
+      It is the equivalent of ``assertEqual(set(actual), set(expected))``
       but it works with sequences of unhashable objects as well. Because
       duplicates are ignored, this method has been deprecated in favour of
-      :meth:`assertItemsEqual`.
+      :meth:`assertCountEqual`.
 
       .. versionadded:: 3.1
       .. deprecated:: 3.2
@@ -1208,9 +1229,9 @@
 
 
 
-   .. method:: assertMultiLineEqual(first, second, msg=None)
+   .. method:: assertMultiLineEqual(actual, expected, msg=None)
 
-      Test that the multiline string *first* is equal to the string *second*.
+      Test that the multiline string *actual* is equal to the string *expected*.
       When not equal a diff of the two strings highlighting the differences
       will be included in the error message. This method is used by default
       when comparing strings with :meth:`assertEqual`.
@@ -1218,10 +1239,10 @@
       .. versionadded:: 3.1
 
 
-   .. method:: assertSequenceEqual(seq1, seq2, msg=None, seq_type=None)
+   .. method:: assertSequenceEqual(actual, expected, msg=None, seq_type=None)
 
       Tests that two sequences are equal.  If a *seq_type* is supplied, both
-      *seq1* and *seq2* must be instances of *seq_type* or a failure will
+      *actual* and *expected* must be instances of *seq_type* or a failure will
       be raised.  If the sequences are different an error message is
       constructed that shows the difference between the two.
 
@@ -1232,8 +1253,8 @@
       .. versionadded:: 3.1
 
 
-   .. method:: assertListEqual(list1, list2, msg=None)
-               assertTupleEqual(tuple1, tuple2, msg=None)
+   .. method:: assertListEqual(actual, expected, msg=None)
+               assertTupleEqual(actual, expected, msg=None)
 
       Tests that two lists or tuples are equal.  If not an error message is
       constructed that shows only the differences between the two.  An error
@@ -1244,19 +1265,19 @@
       .. versionadded:: 3.1
 
 
-   .. method:: assertSetEqual(set1, set2, msg=None)
+   .. method:: assertSetEqual(actual, expected, msg=None)
 
       Tests that two sets are equal.  If not, an error message is constructed
       that lists the differences between the sets.  This method is used by
       default when comparing sets or frozensets with :meth:`assertEqual`.
 
-      Fails if either of *set1* or *set2* does not have a :meth:`set.difference`
+      Fails if either of *actual* or *expected* does not have a :meth:`set.difference`
       method.
 
       .. versionadded:: 3.1
 
 
-   .. method:: assertDictEqual(expected, actual, msg=None)
+   .. method:: assertDictEqual(actual, expected, msg=None)
 
       Test that two dictionaries are equal.  If not, an error message is
       constructed that shows the differences in the dictionaries. This
@@ -1297,8 +1318,8 @@
       to ``True`` allows you to have a custom error message in addition to the
       normal one.
 
-      This attribute defaults to ``False``, meaning that a custom message passed
-      to an assert method will silence the normal message.
+      This attribute defaults to ``True``. If set to False then a custom message
+      passed to an assert method will silence the normal message.
 
       The class setting can be overridden in individual tests by assigning an
       instance attribute to ``True`` or ``False`` before calling the assert methods.
@@ -1355,11 +1376,11 @@
       returns the first line of the test method's docstring, if available,
       or ``None``.
 
-      .. versionchanged:: 3.1,3.2
+      .. versionchanged:: 3.1
          In 3.1 this was changed to add the test name to the short description
-         even in the presence of a docstring. This caused compatibility issues
+         even in the presence of a docstring.  This caused compatibility issues
          with unittest extensions and adding the test name was moved to the
-         :class:`TextTestResult`.
+         :class:`TextTestResult` in Python 3.2.
 
 
    .. method:: addCleanup(function, *args, **kwargs)
@@ -1401,6 +1422,8 @@
    :mod:`unittest`-based test framework.
 
 
+.. _deprecated-aliases:
+
 Deprecated aliases
 ##################
 
@@ -1408,21 +1431,27 @@
 aliases that are now deprecated.  The following table lists the correct names
 along with their deprecated aliases:
 
-   ==============================  ===============================
-    Method Name                     Deprecated alias(es)
-   ==============================  ===============================
-    :meth:`.assertEqual`            failUnlessEqual, assertEquals
-    :meth:`.assertNotEqual`         failIfEqual
-    :meth:`.assertTrue`             failUnless, assert\_
+   ==============================  ====================== ======================
+    Method Name                     Deprecated alias       Deprecated alias
+   ==============================  ====================== ======================
+    :meth:`.assertEqual`            failUnlessEqual        assertEquals
+    :meth:`.assertNotEqual`         failIfEqual            assertNotEquals
+    :meth:`.assertTrue`             failUnless             assert\_
     :meth:`.assertFalse`            failIf
     :meth:`.assertRaises`           failUnlessRaises
-    :meth:`.assertAlmostEqual`      failUnlessAlmostEqual
-    :meth:`.assertNotAlmostEqual`   failIfAlmostEqual
-   ==============================  ===============================
-
-   .. deprecated:: 3.1
-         the aliases listed in the second column
-
+    :meth:`.assertAlmostEqual`      failUnlessAlmostEqual  assertAlmostEquals
+    :meth:`.assertNotAlmostEqual`   failIfAlmostEqual      assertNotAlmostEquals
+    :meth:`.assertRegex`                                   assertRegexpMatches
+    :meth:`.assertRaisesRegex`                             assertRaisesRegexp
+   ==============================  ====================== ======================
+
+   .. deprecated-removed:: 3.1 3.3
+         the fail* aliases listed in the second column.
+   .. deprecated:: 3.2
+         the assert* aliases listed in the third column.
+   .. deprecated:: 3.2
+         ``assertRegexpMatches`` and ``assertRaisesRegexp`` have been renamed to
+         :meth:`.assertRegex` and :meth:`.assertRaisesRegex`
 
 
 .. _testsuite-objects:
@@ -1841,12 +1870,21 @@
    instead of repeatedly creating new instances.
 
 
-.. class:: TextTestRunner(stream=sys.stderr, descriptions=True, verbosity=1, runnerclass=None)
+.. class:: TextTestRunner(stream=sys.stderr, descriptions=True, verbosity=1, runnerclass=None, warnings=None)
 
    A basic test runner implementation which prints results on standard error.  It
    has a few configurable parameters, but is essentially very simple.  Graphical
    applications which run test suites should provide alternate implementations.
 
+   By default this runner shows :exc:`DeprecationWarning`,
+   :exc:`PendingDeprecationWarning`, and :exc:`ImportWarning` even if they are
+   :ref:`ignored by default `. Deprecation warnings caused by
+   :ref:`deprecated unittest methods ` are also
+   special-cased and, when the warning filters are ``'default'`` or ``'always'``,
+   they will appear only once per-module, in order to avoid too many warning
+   messages.  This behavior can be overridden using the :option:`-Wd` or
+   :option:`-Wa` options and leaving *warnings* to ``None``.
+
    .. method:: _makeResult()
 
       This method returns the instance of ``TestResult`` used by :meth:`run`.
@@ -1860,7 +1898,12 @@
 
         stream, descriptions, verbosity
 
-.. function:: main(module='__main__', defaultTest=None, argv=None, testRunner=None, testLoader=unittest.loader.defaultTestLoader, exit=True, verbosity=1, failfast=None, catchbreak=None, buffer=None)
+   .. versionchanged:: 3.2
+      Added the ``warnings`` argument.
+
+.. function:: main(module='__main__', defaultTest=None, argv=None, testRunner=None, \
+                   testLoader=unittest.loader.defaultTestLoader, exit=True, verbosity=1, \
+                   failfast=None, catchbreak=None, buffer=None, warnings=None)
 
    A command-line program that runs a set of tests; this is primarily for making
    test modules conveniently executable.  The simplest use for this function is to
@@ -1887,23 +1930,29 @@
       >>> main(module='test_module', exit=False)
 
    The ``failfast``, ``catchbreak`` and ``buffer`` parameters have the same
-   effect as the `failfast, catch and buffer command-line options`_.
+   effect as the same-name `command-line options`_.
+
+   The *warning* argument specifies the :ref:`warning filter `
+   that should be used while running the tests.  If it's not specified, it will
+   remain ``None`` if a :option:`-W` option is passed to :program:`python`,
+   otherwise it will be set to ``'default'``.
 
    Calling ``main`` actually returns an instance of the ``TestProgram`` class.
    This stores the result of the tests run as the ``result`` attribute.
 
+   .. versionchanged:: 3.1
+      The ``exit`` parameter was added.
+
    .. versionchanged:: 3.2
-      The ``exit``, ``verbosity``, ``failfast``, ``catchbreak`` and ``buffer``
-      parameters were added.
+      The ``verbosity``, ``failfast``, ``catchbreak``, ``buffer``
+      and ``warnings`` parameters were added.
 
 
 load_tests Protocol
 ###################
 
-
 .. versionadded:: 3.2
 
-
 Modules or packages can customize how tests are loaded from them during normal
 test runs or test discovery by implementing a function called ``load_tests``.
 
@@ -2050,12 +2099,14 @@
 Signal Handling
 ---------------
 
-The ``-c``/``--catch`` command-line option to unittest, along with the ``catchbreak``
-parameter to :func:`unittest.main()`, provide more friendly handling of
-control-C during a test run. With catch break behavior enabled control-C will
-allow the currently running test to complete, and the test run will then end
-and report all the results so far. A second control-c will raise a
-:exc:`KeyboardInterrupt` in the usual way.
+.. versionadded:: 3.2
+
+The :option:`-c/--catch ` command-line option to unittest,
+along with the ``catchbreak`` parameter to :func:`unittest.main()`, provide
+more friendly handling of control-C during a test run. With catch break
+behavior enabled control-C will allow the currently running test to complete,
+and the test run will then end and report all the results so far. A second
+control-c will raise a :exc:`KeyboardInterrupt` in the usual way.
 
 The control-c handling signal handler attempts to remain compatible with code or
 tests that install their own :const:`signal.SIGINT` handler. If the ``unittest``
@@ -2075,7 +2126,6 @@
    (usually in response to the user pressing control-c) all registered results
    have :meth:`~TestResult.stop` called.
 
-   .. versionadded:: 3.2
 
 .. function:: registerResult(result)
 
@@ -2087,7 +2137,6 @@
    handling is not enabled, so test frameworks can unconditionally register
    all results they create independently of whether or not handling is enabled.
 
-   .. versionadded:: 3.2
 
 .. function:: removeResult(result)
 
@@ -2095,7 +2144,6 @@
    :meth:`~TestResult.stop` will no longer be called on that result object in
    response to a control-c.
 
-   .. versionadded:: 3.2
 
 .. function:: removeHandler(function=None)
 
@@ -2106,6 +2154,3 @@
       @unittest.removeHandler
       def test_signal_handling(self):
           ...
-
-   .. versionadded:: 3.2
-

Modified: python/branches/py3k-cdecimal/Doc/library/urllib.parse.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/urllib.parse.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/urllib.parse.rst	Sun Jan  2 13:18:37 2011
@@ -24,7 +24,15 @@
 ``rsync``, ``rtsp``, ``rtspu``, ``sftp``, ``shttp``, ``sip``, ``sips``,
 ``snews``, ``svn``, ``svn+ssh``, ``telnet``, ``wais``.
 
-The :mod:`urllib.parse` module defines the following functions:
+The :mod:`urllib.parse` module defines functions that fall into two broad
+categories: URL parsing and URL quoting. These are covered in detail in
+the following sections.
+
+URL Parsing
+-----------
+
+The URL parsing functions focus on splitting a URL string into its components,
+or on combining URL components into a URL string.
 
 .. function:: urlparse(urlstring, scheme='', allow_fragments=True)
 
@@ -242,6 +250,161 @@
    string.  If there is no fragment identifier in *url*, return *url* unmodified
    and an empty string.
 
+   The return value is actually an instance of a subclass of :class:`tuple`.  This
+   class has the following additional read-only convenience attributes:
+
+   +------------------+-------+-------------------------+----------------------+
+   | Attribute        | Index | Value                   | Value if not present |
+   +==================+=======+=========================+======================+
+   | :attr:`url`      | 0     | URL with no fragment    | empty string         |
+   +------------------+-------+-------------------------+----------------------+
+   | :attr:`fragment` | 1     | Fragment identifier     | empty string         |
+   +------------------+-------+-------------------------+----------------------+
+
+   See section :ref:`urlparse-result-object` for more information on the result
+   object.
+
+   .. versionchanged:: 3.2
+      Result is a structured object rather than a simple 2-tuple
+
+
+Parsing ASCII Encoded Bytes
+---------------------------
+
+The URL parsing functions were originally designed to operate on character
+strings only. In practice, it is useful to be able to manipulate properly
+quoted and encoded URLs as sequences of ASCII bytes. Accordingly, the
+URL parsing functions in this module all operate on :class:`bytes` and
+:class:`bytearray` objects in addition to :class:`str` objects.
+
+If :class:`str` data is passed in, the result will also contain only
+:class:`str` data. If :class:`bytes` or :class:`bytearray` data is
+passed in, the result will contain only :class:`bytes` data.
+
+Attempting to mix :class:`str` data with :class:`bytes` or
+:class:`bytearray` in a single function call will result in a
+:exc:`TypeError` being raised, while attempting to pass in non-ASCII
+byte values will trigger :exc:`UnicodeDecodeError`.
+
+To support easier conversion of result objects between :class:`str` and
+:class:`bytes`, all return values from URL parsing functions provide
+either an :meth:`encode` method (when the result contains :class:`str`
+data) or a :meth:`decode` method (when the result contains :class:`bytes`
+data). The signatures of these methods match those of the corresponding
+:class:`str` and :class:`bytes` methods (except that the default encoding
+is ``'ascii'`` rather than ``'utf-8'``). Each produces a value of a
+corresponding type that contains either :class:`bytes` data (for
+:meth:`encode` methods) or :class:`str` data (for
+:meth:`decode` methods).
+
+Applications that need to operate on potentially improperly quoted URLs
+that may contain non-ASCII data will need to do their own decoding from
+bytes to characters before invoking the URL parsing methods.
+
+The behaviour described in this section applies only to the URL parsing
+functions. The URL quoting functions use their own rules when producing
+or consuming byte sequences as detailed in the documentation of the
+individual URL quoting functions.
+
+.. versionchanged:: 3.2
+   URL parsing functions now accept ASCII encoded byte sequences
+
+
+.. _urlparse-result-object:
+
+Structured Parse Results
+------------------------
+
+The result objects from the :func:`urlparse`, :func:`urlsplit`  and
+:func:`urldefrag` functions are subclasses of the :class:`tuple` type.
+These subclasses add the attributes listed in the documentation for
+those functions, the encoding and decoding support described in the
+previous section, as well as an additional method:
+
+.. method:: urllib.parse.SplitResult.geturl()
+
+   Return the re-combined version of the original URL as a string. This may
+   differ from the original URL in that the scheme may be normalized to lower
+   case and empty components may be dropped. Specifically, empty parameters,
+   queries, and fragment identifiers will be removed.
+
+   For :func:`urldefrag` results, only empty fragment identifiers will be removed.
+   For :func:`urlsplit` and :func:`urlparse` results, all noted changes will be
+   made to the URL returned by this method.
+
+   The result of this method remains unchanged if passed back through the original
+   parsing function:
+
+      >>> from urllib.parse import urlsplit
+      >>> url = 'HTTP://www.Python.org/doc/#'
+      >>> r1 = urlsplit(url)
+      >>> r1.geturl()
+      'http://www.Python.org/doc/'
+      >>> r2 = urlsplit(r1.geturl())
+      >>> r2.geturl()
+      'http://www.Python.org/doc/'
+
+
+The following classes provide the implementations of the structured parse
+results when operating on :class:`str` objects:
+
+.. class:: DefragResult(url, fragment)
+
+   Concrete class for :func:`urldefrag` results containing :class:`str`
+   data. The :meth:`encode` method returns a :class:`DefragResultBytes`
+   instance.
+
+   .. versionadded:: 3.2
+
+.. class:: ParseResult(scheme, netloc, path, params, query, fragment)
+
+   Concrete class for :func:`urlparse` results containing :class:`str`
+   data. The :meth:`encode` method returns a :class:`ParseResultBytes`
+   instance.
+
+.. class:: SplitResult(scheme, netloc, path, query, fragment)
+
+   Concrete class for :func:`urlsplit` results containing :class:`str`
+   data. The :meth:`encode` method returns a :class:`SplitResultBytes`
+   instance.
+
+
+The following classes provide the implementations of the parse results when
+operating on :class:`bytes` or :class:`bytearray` objects:
+
+.. class:: DefragResultBytes(url, fragment)
+
+   Concrete class for :func:`urldefrag` results containing :class:`bytes`
+   data. The :meth:`decode` method returns a :class:`DefragResult`
+   instance.
+
+   .. versionadded:: 3.2
+
+.. class:: ParseResultBytes(scheme, netloc, path, params, query, fragment)
+
+   Concrete class for :func:`urlparse` results containing :class:`bytes`
+   data. The :meth:`decode` method returns a :class:`ParseResult`
+   instance.
+
+   .. versionadded:: 3.2
+
+.. class:: SplitResultBytes(scheme, netloc, path, query, fragment)
+
+   Concrete class for :func:`urlsplit` results containing :class:`bytes`
+   data. The :meth:`decode` method returns a :class:`SplitResult`
+   instance.
+
+   .. versionadded:: 3.2
+
+
+URL Quoting
+-----------
+
+The URL quoting functions focus on taking program data and making it safe
+for use as URL components by quoting special characters and appropriately
+encoding non-ASCII text. They also support reversing these operations to
+recreate the original data from the contents of a URL component if that
+task isn't already covered by the URL parsing functions above.
 
 .. function:: quote(string, safe='/', encoding=None, errors=None)
 
@@ -322,8 +485,7 @@
    If it is a :class:`str`, unescaped non-ASCII characters in *string*
    are encoded into UTF-8 bytes.
 
-   Example: ``unquote_to_bytes('a%26%EF')`` yields
-   ``b'a&\xef'``.
+   Example: ``unquote_to_bytes('a%26%EF')`` yields ``b'a&\xef'``.
 
 
 .. function:: urlencode(query, doseq=False, safe='', encoding=None, errors=None)
@@ -340,12 +502,13 @@
    the optional parameter *doseq* is evaluates to *True*, individual
    ``key=value`` pairs separated by ``'&'`` are generated for each element of
    the value sequence for the key.  The order of parameters in the encoded
-   string will match the order of parameter tuples in the sequence. This module
-   provides the functions :func:`parse_qs` and :func:`parse_qsl` which are used
-   to parse query strings into Python data structures.
+   string will match the order of parameter tuples in the sequence.
 
    When *query* parameter is a :class:`str`, the *safe*, *encoding* and *error*
-   parameters are sent the :func:`quote_plus` for encoding.
+   parameters are passed down to :func:`quote_plus` for encoding.
+
+   To reverse this encoding process, :func:`parse_qs` and :func:`parse_qsl` are
+   provided in this module to parse query strings into Python data structures.
 
    .. versionchanged:: 3.2
       Query parameter supports bytes and string objects.
@@ -376,57 +539,3 @@
 
    :rfc:`1738` - Uniform Resource Locators (URL)
       This specifies the formal syntax and semantics of absolute URLs.
-
-
-.. _urlparse-result-object:
-
-Results of :func:`urlparse` and :func:`urlsplit`
-------------------------------------------------
-
-The result objects from the :func:`urlparse` and :func:`urlsplit` functions are
-subclasses of the :class:`tuple` type.  These subclasses add the attributes
-described in those functions, as well as provide an additional method:
-
-.. method:: ParseResult.geturl()
-
-   Return the re-combined version of the original URL as a string. This may differ
-   from the original URL in that the scheme will always be normalized to lower case
-   and empty components may be dropped. Specifically, empty parameters, queries,
-   and fragment identifiers will be removed.
-
-   The result of this method is a fixpoint if passed back through the original
-   parsing function:
-
-      >>> import urllib.parse
-      >>> url = 'HTTP://www.Python.org/doc/#'
-
-      >>> r1 = urllib.parse.urlsplit(url)
-      >>> r1.geturl()
-      'http://www.Python.org/doc/'
-
-      >>> r2 = urllib.parse.urlsplit(r1.geturl())
-      >>> r2.geturl()
-      'http://www.Python.org/doc/'
-
-
-The following classes provide the implementations of the parse results:
-
-.. class:: BaseResult
-
-   Base class for the concrete result classes.  This provides most of the
-   attribute definitions.  It does not provide a :meth:`geturl` method.  It is
-   derived from :class:`tuple`, but does not override the :meth:`__init__` or
-   :meth:`__new__` methods.
-
-
-.. class:: ParseResult(scheme, netloc, path, params, query, fragment)
-
-   Concrete class for :func:`urlparse` results.  The :meth:`__new__` method is
-   overridden to support checking that the right number of arguments are passed.
-
-
-.. class:: SplitResult(scheme, netloc, path, query, fragment)
-
-   Concrete class for :func:`urlsplit` results.  The :meth:`__new__` method is
-   overridden to support checking that the right number of arguments are passed.
-

Modified: python/branches/py3k-cdecimal/Doc/library/urllib.request.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/urllib.request.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/urllib.request.rst	Sun Jan  2 13:18:37 2011
@@ -1,4 +1,4 @@
-:mod:`urllib.request` --- extensible library for opening URLs
+:mod:`urllib.request` --- Extensible library for opening URLs
 =============================================================
 
 .. module:: urllib.request
@@ -20,14 +20,15 @@
    Open the URL *url*, which can be either a string or a
    :class:`Request` object.
 
-   *data* may be a string specifying additional data to send to the
-   server, or ``None`` if no such data is needed.  Currently HTTP
-   requests are the only ones that use *data*; the HTTP request will
-   be a POST instead of a GET when the *data* parameter is provided.
-   *data* should be a buffer in the standard
+   *data* may be a bytes object specifying additional data to send to the
+   server, or ``None`` if no such data is needed. *data* may also be an
+   iterable object and in that case Content-Length value must be specified in
+   the headers. Currently HTTP requests are the only ones that use *data*; the
+   HTTP request will be a POST instead of a GET when the *data* parameter is
+   provided.  *data* should be a buffer in the standard
    :mimetype:`application/x-www-form-urlencoded` format.  The
-   :func:`urllib.parse.urlencode` function takes a mapping or sequence
-   of 2-tuples and returns a string in this format. urllib.request module uses
+   :func:`urllib.parse.urlencode` function takes a mapping or sequence of
+   2-tuples and returns a string in this format. urllib.request module uses
    HTTP/1.1 and includes ``Connection:close`` header in its HTTP requests.
 
    The optional *timeout* parameter specifies a timeout in seconds for
@@ -76,6 +77,9 @@
       HTTPS virtual hosts are now supported if possible (that is, if
       :data:`ssl.HAS_SNI` is true).
 
+   .. versionadded:: 3.2
+      *data* can be an iterable object.
+
 .. function:: install_opener(opener)
 
    Install an :class:`OpenerDirector` instance as the default global opener.
@@ -104,52 +108,6 @@
    member variable to modify its position in the handlers list.
 
 
-.. function:: urlretrieve(url, filename=None, reporthook=None, data=None)
-
-   Copy a network object denoted by a URL to a local file, if necessary. If the URL
-   points to a local file, or a valid cached copy of the object exists, the object
-   is not copied.  Return a tuple ``(filename, headers)`` where *filename* is the
-   local file name under which the object can be found, and *headers* is whatever
-   the :meth:`info` method of the object returned by :func:`urlopen` returned (for
-   a remote object, possibly cached). Exceptions are the same as for
-   :func:`urlopen`.
-
-   The second argument, if present, specifies the file location to copy to (if
-   absent, the location will be a tempfile with a generated name). The third
-   argument, if present, is a hook function that will be called once on
-   establishment of the network connection and once after each block read
-   thereafter.  The hook will be passed three arguments; a count of blocks
-   transferred so far, a block size in bytes, and the total size of the file.  The
-   third argument may be ``-1`` on older FTP servers which do not return a file
-   size in response to a retrieval request.
-
-   If the *url* uses the :file:`http:` scheme identifier, the optional *data*
-   argument may be given to specify a ``POST`` request (normally the request type
-   is ``GET``).  The *data* argument must in standard
-   :mimetype:`application/x-www-form-urlencoded` format; see the :func:`urlencode`
-   function below.
-
-   :func:`urlretrieve` will raise :exc:`ContentTooShortError` when it detects that
-   the amount of data available  was less than the expected amount (which is the
-   size reported by a  *Content-Length* header). This can occur, for example, when
-   the  download is interrupted.
-
-   The *Content-Length* is treated as a lower bound: if there's more data  to read,
-   urlretrieve reads more data, but if less data is available,  it raises the
-   exception.
-
-   You can still retrieve the downloaded data in this case, it is stored  in the
-   :attr:`content` attribute of the exception instance.
-
-   If no *Content-Length* header was supplied, urlretrieve can not check the size
-   of the data it has downloaded, and just returns it.  In this case you just have
-   to assume that the download was successful.
-
-.. function:: urlcleanup()
-
-   Clear the cache that may have been built up by previous calls to
-   :func:`urlretrieve`.
-
 .. function:: pathname2url(path)
 
    Convert the pathname *path* from the local syntax for a path to the form used in
@@ -218,115 +176,6 @@
    fetching of the image, this should be true.
 
 
-.. class:: URLopener(proxies=None, **x509)
-
-   Base class for opening and reading URLs.  Unless you need to support opening
-   objects using schemes other than :file:`http:`, :file:`ftp:`, or :file:`file:`,
-   you probably want to use :class:`FancyURLopener`.
-
-   By default, the :class:`URLopener` class sends a :mailheader:`User-Agent` header
-   of ``urllib/VVV``, where *VVV* is the :mod:`urllib` version number.
-   Applications can define their own :mailheader:`User-Agent` header by subclassing
-   :class:`URLopener` or :class:`FancyURLopener` and setting the class attribute
-   :attr:`version` to an appropriate string value in the subclass definition.
-
-   The optional *proxies* parameter should be a dictionary mapping scheme names to
-   proxy URLs, where an empty dictionary turns proxies off completely.  Its default
-   value is ``None``, in which case environmental proxy settings will be used if
-   present, as discussed in the definition of :func:`urlopen`, above.
-
-   Additional keyword parameters, collected in *x509*, may be used for
-   authentication of the client when using the :file:`https:` scheme.  The keywords
-   *key_file* and *cert_file* are supported to provide an  SSL key and certificate;
-   both are needed to support client authentication.
-
-   :class:`URLopener` objects will raise an :exc:`IOError` exception if the server
-   returns an error code.
-
-    .. method:: open(fullurl, data=None)
-
-       Open *fullurl* using the appropriate protocol.  This method sets up cache and
-       proxy information, then calls the appropriate open method with its input
-       arguments.  If the scheme is not recognized, :meth:`open_unknown` is called.
-       The *data* argument has the same meaning as the *data* argument of
-       :func:`urlopen`.
-
-
-    .. method:: open_unknown(fullurl, data=None)
-
-       Overridable interface to open unknown URL types.
-
-
-    .. method:: retrieve(url, filename=None, reporthook=None, data=None)
-
-       Retrieves the contents of *url* and places it in *filename*.  The return value
-       is a tuple consisting of a local filename and either a
-       :class:`email.message.Message` object containing the response headers (for remote
-       URLs) or ``None`` (for local URLs).  The caller must then open and read the
-       contents of *filename*.  If *filename* is not given and the URL refers to a
-       local file, the input filename is returned.  If the URL is non-local and
-       *filename* is not given, the filename is the output of :func:`tempfile.mktemp`
-       with a suffix that matches the suffix of the last path component of the input
-       URL.  If *reporthook* is given, it must be a function accepting three numeric
-       parameters.  It will be called after each chunk of data is read from the
-       network.  *reporthook* is ignored for local URLs.
-
-       If the *url* uses the :file:`http:` scheme identifier, the optional *data*
-       argument may be given to specify a ``POST`` request (normally the request type
-       is ``GET``).  The *data* argument must in standard
-       :mimetype:`application/x-www-form-urlencoded` format; see the :func:`urlencode`
-       function below.
-
-
-    .. attribute:: version
-
-       Variable that specifies the user agent of the opener object.  To get
-       :mod:`urllib` to tell servers that it is a particular user agent, set this in a
-       subclass as a class variable or in the constructor before calling the base
-       constructor.
-
-
-.. class:: FancyURLopener(...)
-
-   :class:`FancyURLopener` subclasses :class:`URLopener` providing default handling
-   for the following HTTP response codes: 301, 302, 303, 307 and 401.  For the 30x
-   response codes listed above, the :mailheader:`Location` header is used to fetch
-   the actual URL.  For 401 response codes (authentication required), basic HTTP
-   authentication is performed.  For the 30x response codes, recursion is bounded
-   by the value of the *maxtries* attribute, which defaults to 10.
-
-   For all other response codes, the method :meth:`http_error_default` is called
-   which you can override in subclasses to handle the error appropriately.
-
-   .. note::
-
-      According to the letter of :rfc:`2616`, 301 and 302 responses to POST requests
-      must not be automatically redirected without confirmation by the user.  In
-      reality, browsers do allow automatic redirection of these responses, changing
-      the POST to a GET, and :mod:`urllib` reproduces this behaviour.
-
-   The parameters to the constructor are the same as those for :class:`URLopener`.
-
-   .. note::
-
-      When performing basic authentication, a :class:`FancyURLopener` instance calls
-      its :meth:`prompt_user_passwd` method.  The default implementation asks the
-      users for the required information on the controlling terminal.  A subclass may
-      override this method to support more appropriate behavior if needed.
-
-    The :class:`FancyURLopener` class offers one additional method that should be
-    overloaded to provide the appropriate behavior:
-
-    .. method:: prompt_user_passwd(host, realm)
-
-       Return information needed to authenticate the user at the given host in the
-       specified security realm.  The return value should be a tuple, ``(user,
-       password)``, which can be used for basic authentication.
-
-       The implementation prompts for this information on the terminal; an application
-       should override this method to use an appropriate interaction model in the local
-       environment.
-
 .. class:: OpenerDirector()
 
    The :class:`OpenerDirector` class opens URLs via :class:`BaseHandler`\ s chained
@@ -1219,6 +1068,170 @@
    >>> f.read().decode('utf-8')
 
 
+Legacy interface
+----------------
+
+The following functions and classes are ported from the Python 2 module
+``urllib`` (as opposed to ``urllib2``).  They might become deprecated at
+some point in the future.
+
+
+.. function:: urlretrieve(url, filename=None, reporthook=None, data=None)
+
+   Copy a network object denoted by a URL to a local file, if necessary. If the URL
+   points to a local file, or a valid cached copy of the object exists, the object
+   is not copied.  Return a tuple ``(filename, headers)`` where *filename* is the
+   local file name under which the object can be found, and *headers* is whatever
+   the :meth:`info` method of the object returned by :func:`urlopen` returned (for
+   a remote object, possibly cached). Exceptions are the same as for
+   :func:`urlopen`.
+
+   The second argument, if present, specifies the file location to copy to (if
+   absent, the location will be a tempfile with a generated name). The third
+   argument, if present, is a hook function that will be called once on
+   establishment of the network connection and once after each block read
+   thereafter.  The hook will be passed three arguments; a count of blocks
+   transferred so far, a block size in bytes, and the total size of the file.  The
+   third argument may be ``-1`` on older FTP servers which do not return a file
+   size in response to a retrieval request.
+
+   If the *url* uses the :file:`http:` scheme identifier, the optional *data*
+   argument may be given to specify a ``POST`` request (normally the request type
+   is ``GET``).  The *data* argument must in standard
+   :mimetype:`application/x-www-form-urlencoded` format; see the :func:`urlencode`
+   function below.
+
+   :func:`urlretrieve` will raise :exc:`ContentTooShortError` when it detects that
+   the amount of data available  was less than the expected amount (which is the
+   size reported by a  *Content-Length* header). This can occur, for example, when
+   the  download is interrupted.
+
+   The *Content-Length* is treated as a lower bound: if there's more data  to read,
+   urlretrieve reads more data, but if less data is available,  it raises the
+   exception.
+
+   You can still retrieve the downloaded data in this case, it is stored  in the
+   :attr:`content` attribute of the exception instance.
+
+   If no *Content-Length* header was supplied, urlretrieve can not check the size
+   of the data it has downloaded, and just returns it.  In this case you just have
+   to assume that the download was successful.
+
+.. function:: urlcleanup()
+
+   Clear the cache that may have been built up by previous calls to
+   :func:`urlretrieve`.
+
+.. class:: URLopener(proxies=None, **x509)
+
+   Base class for opening and reading URLs.  Unless you need to support opening
+   objects using schemes other than :file:`http:`, :file:`ftp:`, or :file:`file:`,
+   you probably want to use :class:`FancyURLopener`.
+
+   By default, the :class:`URLopener` class sends a :mailheader:`User-Agent` header
+   of ``urllib/VVV``, where *VVV* is the :mod:`urllib` version number.
+   Applications can define their own :mailheader:`User-Agent` header by subclassing
+   :class:`URLopener` or :class:`FancyURLopener` and setting the class attribute
+   :attr:`version` to an appropriate string value in the subclass definition.
+
+   The optional *proxies* parameter should be a dictionary mapping scheme names to
+   proxy URLs, where an empty dictionary turns proxies off completely.  Its default
+   value is ``None``, in which case environmental proxy settings will be used if
+   present, as discussed in the definition of :func:`urlopen`, above.
+
+   Additional keyword parameters, collected in *x509*, may be used for
+   authentication of the client when using the :file:`https:` scheme.  The keywords
+   *key_file* and *cert_file* are supported to provide an  SSL key and certificate;
+   both are needed to support client authentication.
+
+   :class:`URLopener` objects will raise an :exc:`IOError` exception if the server
+   returns an error code.
+
+    .. method:: open(fullurl, data=None)
+
+       Open *fullurl* using the appropriate protocol.  This method sets up cache and
+       proxy information, then calls the appropriate open method with its input
+       arguments.  If the scheme is not recognized, :meth:`open_unknown` is called.
+       The *data* argument has the same meaning as the *data* argument of
+       :func:`urlopen`.
+
+
+    .. method:: open_unknown(fullurl, data=None)
+
+       Overridable interface to open unknown URL types.
+
+
+    .. method:: retrieve(url, filename=None, reporthook=None, data=None)
+
+       Retrieves the contents of *url* and places it in *filename*.  The return value
+       is a tuple consisting of a local filename and either a
+       :class:`email.message.Message` object containing the response headers (for remote
+       URLs) or ``None`` (for local URLs).  The caller must then open and read the
+       contents of *filename*.  If *filename* is not given and the URL refers to a
+       local file, the input filename is returned.  If the URL is non-local and
+       *filename* is not given, the filename is the output of :func:`tempfile.mktemp`
+       with a suffix that matches the suffix of the last path component of the input
+       URL.  If *reporthook* is given, it must be a function accepting three numeric
+       parameters.  It will be called after each chunk of data is read from the
+       network.  *reporthook* is ignored for local URLs.
+
+       If the *url* uses the :file:`http:` scheme identifier, the optional *data*
+       argument may be given to specify a ``POST`` request (normally the request type
+       is ``GET``).  The *data* argument must in standard
+       :mimetype:`application/x-www-form-urlencoded` format; see the :func:`urlencode`
+       function below.
+
+
+    .. attribute:: version
+
+       Variable that specifies the user agent of the opener object.  To get
+       :mod:`urllib` to tell servers that it is a particular user agent, set this in a
+       subclass as a class variable or in the constructor before calling the base
+       constructor.
+
+
+.. class:: FancyURLopener(...)
+
+   :class:`FancyURLopener` subclasses :class:`URLopener` providing default handling
+   for the following HTTP response codes: 301, 302, 303, 307 and 401.  For the 30x
+   response codes listed above, the :mailheader:`Location` header is used to fetch
+   the actual URL.  For 401 response codes (authentication required), basic HTTP
+   authentication is performed.  For the 30x response codes, recursion is bounded
+   by the value of the *maxtries* attribute, which defaults to 10.
+
+   For all other response codes, the method :meth:`http_error_default` is called
+   which you can override in subclasses to handle the error appropriately.
+
+   .. note::
+
+      According to the letter of :rfc:`2616`, 301 and 302 responses to POST requests
+      must not be automatically redirected without confirmation by the user.  In
+      reality, browsers do allow automatic redirection of these responses, changing
+      the POST to a GET, and :mod:`urllib` reproduces this behaviour.
+
+   The parameters to the constructor are the same as those for :class:`URLopener`.
+
+   .. note::
+
+      When performing basic authentication, a :class:`FancyURLopener` instance calls
+      its :meth:`prompt_user_passwd` method.  The default implementation asks the
+      users for the required information on the controlling terminal.  A subclass may
+      override this method to support more appropriate behavior if needed.
+
+   The :class:`FancyURLopener` class offers one additional method that should be
+   overloaded to provide the appropriate behavior:
+
+   .. method:: prompt_user_passwd(host, realm)
+
+      Return information needed to authenticate the user at the given host in the
+      specified security realm.  The return value should be a tuple, ``(user,
+      password)``, which can be used for basic authentication.
+
+      The implementation prompts for this information on the terminal; an application
+      should override this method to use an appropriate interaction model in the local
+      environment.
+
+
 :mod:`urllib.request` Restrictions
 ----------------------------------
 
@@ -1272,8 +1285,8 @@
 
 
 
-:mod:`urllib.response` --- Response classes used by urllib.
-===========================================================
+:mod:`urllib.response` --- Response classes used by urllib
+==========================================================
 
 .. module:: urllib.response
    :synopsis: Response classes used by urllib.

Modified: python/branches/py3k-cdecimal/Doc/library/warnings.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/warnings.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/warnings.rst	Sun Jan  2 13:18:37 2011
@@ -249,6 +249,8 @@
 entries from the warnings list before each new operation).
 
 
+.. _warning-ignored:
+
 Updating Code For New Versions of Python
 ----------------------------------------
 
@@ -279,6 +281,9 @@
 developer want to be notified that your code is using a deprecated module, to a
 user this information is essentially noise and provides no benefit to them.
 
+The :mod:`unittest` module has been also updated to use the ``'default'``
+filter while running tests.
+
 
 .. _warning-functions:
 

Modified: python/branches/py3k-cdecimal/Doc/library/xml.dom.minidom.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/xml.dom.minidom.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/xml.dom.minidom.rst	Sun Jan  2 13:18:37 2011
@@ -122,7 +122,7 @@
           ... # Work with dom.
 
 
-.. method:: Node.writexml(writer, indent="", addindent="", newl="", encoding="")
+.. method:: Node.writexml(writer, indent="", addindent="", newl="")
 
    Write XML to the writer object.  The writer should have a :meth:`write` method
    which matches that of the file object interface.  The *indent* parameter is the
@@ -130,8 +130,8 @@
    indentation to use for subnodes of the current one.  The *newl* parameter
    specifies the string to use to terminate newlines.
 
-   For the :class:`Document` node, an additional keyword argument *encoding* can be
-   used to specify the encoding field of the XML header.
+   For the :class:`Document` node, an additional keyword argument *encoding* can
+   be used to specify the encoding field of the XML header.
 
 
 .. method:: Node.toxml(encoding=None)

Modified: python/branches/py3k-cdecimal/Doc/library/zipfile.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/library/zipfile.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/library/zipfile.rst	Sun Jan  2 13:18:37 2011
@@ -51,6 +51,7 @@
 
 
 .. class:: PyZipFile
+   :noindex:
 
    Class for creating ZIP archives containing Python libraries.
 
@@ -178,8 +179,8 @@
    .. note::
 
       The file-like object is read-only and provides the following methods:
-      :meth:`read`, :meth:`readline`, :meth:`readlines`, :meth:`__iter__`,
-      :meth:`__next__`.
+      :meth:`!read`, :meth:`!readline`, :meth:`!readlines`, :meth:`!__iter__`,
+      :meth:`!__next__`.
 
    .. note::
 
@@ -294,7 +295,7 @@
 
    .. note::
 
-      When passing a :class:`ZipInfo` instance as the *zinfo_or_acrname* parameter,
+      When passing a :class:`ZipInfo` instance as the *zinfo_or_arcname* parameter,
       the compression method used will be that specified in the *compress_type*
       member of the given :class:`ZipInfo` instance.  By default, the
       :class:`ZipInfo` constructor sets this member to :const:`ZIP_STORED`.
@@ -318,37 +319,53 @@
    string no longer than 65535 bytes.  Comments longer than this will be
    truncated in the written archive when :meth:`ZipFile.close` is called.
 
+
 .. _pyzipfile-objects:
 
 PyZipFile Objects
 -----------------
 
 The :class:`PyZipFile` constructor takes the same parameters as the
-:class:`ZipFile` constructor.  Instances have one method in addition to those of
-:class:`ZipFile` objects.
+:class:`ZipFile` constructor, and one additional parameter, *optimize*.
+
+.. class:: PyZipFile(file, mode='r', compression=ZIP_STORED, allowZip64=False, \
+                     optimize=-1)
+
+   .. versionadded:: 3.2
+      The *optimize* parameter.
+
+   Instances have one method in addition to those of :class:`ZipFile` objects:
 
+   .. method:: PyZipFile.writepy(pathname, basename='')
 
-.. method:: PyZipFile.writepy(pathname, basename='')
+      Search for files :file:`\*.py` and add the corresponding file to the
+      archive.
 
-   Search for files :file:`\*.py` and add the corresponding file to the archive.
-   The corresponding file is a :file:`\*.pyo` file if available, else a
-   :file:`\*.pyc` file, compiling if necessary.  If the pathname is a file, the
-   filename must end with :file:`.py`, and just the (corresponding
-   :file:`\*.py[co]`) file is added at the top level (no path information).  If the
-   pathname is a file that does not end with :file:`.py`, a :exc:`RuntimeError`
-   will be raised.  If it is a directory, and the directory is not a package
-   directory, then all the files :file:`\*.py[co]` are added at the top level.  If
-   the directory is a package directory, then all :file:`\*.py[co]` are added under
-   the package name as a file path, and if any subdirectories are package
-   directories, all of these are added recursively.  *basename* is intended for
-   internal use only.  The :meth:`writepy` method makes archives with file names
-   like this::
-
-      string.pyc                                # Top level name
-      test/__init__.pyc                         # Package directory
-      test/testall.pyc                          # Module test.testall
-      test/bogus/__init__.pyc                   # Subpackage directory
-      test/bogus/myfile.pyc                     # Submodule test.bogus.myfile
+      If the *optimize* parameter to :class:`PyZipFile` was not given or ``-1``,
+      the corresponding file is a :file:`\*.pyo` file if available, else a
+      :file:`\*.pyc` file, compiling if necessary.
+
+      If the *optimize* parameter to :class:`PyZipFile` was ``0``, ``1`` or
+      ``2``, only files with that optimization level (see :func:`compile`) are
+      added to the archive, compiling if necessary.
+
+      If the pathname is a file, the filename must end with :file:`.py`, and
+      just the (corresponding :file:`\*.py[co]`) file is added at the top level
+      (no path information).  If the pathname is a file that does not end with
+      :file:`.py`, a :exc:`RuntimeError` will be raised.  If it is a directory,
+      and the directory is not a package directory, then all the files
+      :file:`\*.py[co]` are added at the top level.  If the directory is a
+      package directory, then all :file:`\*.py[co]` are added under the package
+      name as a file path, and if any subdirectories are package directories,
+      all of these are added recursively.  *basename* is intended for internal
+      use only.  The :meth:`writepy` method makes archives with file names like
+      this::
+
+         string.pyc                   # Top level name
+         test/__init__.pyc            # Package directory
+         test/testall.pyc             # Module test.testall
+         test/bogus/__init__.pyc      # Subpackage directory
+         test/bogus/myfile.pyc        # Submodule test.bogus.myfile
 
 
 .. _zipinfo-objects:

Modified: python/branches/py3k-cdecimal/Doc/license.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/license.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/license.rst	Sun Jan  2 13:18:37 2011
@@ -108,7 +108,7 @@
 +----------------+--------------+------------+------------+-----------------+
 | 3.1.2          | 3.1          | 2010       | PSF        | yes             |
 +----------------+--------------+------------+------------+-----------------+
-| 3.2            | 3.1          | 2010       | PSF        | yes             |
+| 3.2            | 3.1          | 2011       | PSF        | yes             |
 +----------------+--------------+------------+------------+-----------------+
 
 .. note::
@@ -138,7 +138,7 @@
    analyze, test, perform and/or display publicly, prepare derivative works,
    distribute, and otherwise use Python |release| alone or in any derivative
    version, provided, however, that PSF's License Agreement and PSF's notice of
-   copyright, i.e., "Copyright ?? 2001-2010 Python Software Foundation; All Rights
+   copyright, i.e., "Copyright ?? 2001-2011 Python Software Foundation; All Rights
    Reserved" are retained in Python |release| alone or in any derivative version
    prepared by Licensee.
 
@@ -906,7 +906,7 @@
 sources unless the zlib version found on the system is too old to be
 used for the build::
 
-  Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+  Copyright (C) 1995-2011 Jean-loup Gailly and Mark Adler
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages

Modified: python/branches/py3k-cdecimal/Doc/reference/datamodel.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/reference/datamodel.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/reference/datamodel.rst	Sun Jan  2 13:18:37 2011
@@ -618,7 +618,7 @@
       an object passed to the C function as an implicit extra argument.  An example of
       a built-in method is ``alist.append()``, assuming *alist* is a list object. In
       this case, the special read-only attribute :attr:`__self__` is set to the object
-      denoted by *list*.
+      denoted by *alist*.
 
    Classes
       Classes are callable.  These objects normally act as factories for new

Modified: python/branches/py3k-cdecimal/Doc/reference/expressions.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/reference/expressions.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/reference/expressions.rst	Sun Jan  2 13:18:37 2011
@@ -1161,7 +1161,7 @@
 'foo'`` yields ``False``, not ``''``.)
 
 
-Conditional Expressions
+Conditional expressions
 =======================
 
 .. index::
@@ -1322,8 +1322,8 @@
    true numerically due to roundoff.  For example, and assuming a platform on which
    a Python float is an IEEE 754 double-precision number, in order that ``-1e-100 %
    1e100`` have the same sign as ``1e100``, the computed result is ``-1e-100 +
-   1e100``, which is numerically exactly equal to ``1e100``.  Function :func:`fmod`
-   in the :mod:`math` module returns a result whose sign matches the sign of the
+   1e100``, which is numerically exactly equal to ``1e100``.  The function
+   :func:`math.fmod` returns a result whose sign matches the sign of the
    first argument instead, and so returns ``-1e-100`` in this case. Which approach
    is more appropriate depends on the application.
 
@@ -1344,7 +1344,8 @@
    the :keyword:`is` operator, like those involving comparisons between instance
    methods, or constants.  Check their documentation for more info.
 
-.. [#] The ``%`` is also used for string formatting; the same precedence applies.
+.. [#] The ``%`` operator is also used for string formatting; the same
+   precedence applies.
 
 .. [#] The power operator ``**`` binds less tightly than an arithmetic or
    bitwise unary operator on its right, that is, ``2**-1`` is ``0.5``.

Modified: python/branches/py3k-cdecimal/Doc/reference/lexical_analysis.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/reference/lexical_analysis.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/reference/lexical_analysis.rst	Sun Jan  2 13:18:37 2011
@@ -292,9 +292,11 @@
 Identifiers are unlimited in length.  Case is significant.
 
 .. productionlist::
-   identifier: `id_start` `id_continue`*
+   identifier: `xid_start` `xid_continue`*
    id_start: 
    id_continue: 
+   xid_start: 
+   xid_continue: 
 
 The Unicode category codes mentioned above stand for:
 
@@ -308,9 +310,11 @@
 * *Mc* - spacing combining marks
 * *Nd* - decimal numbers
 * *Pc* - connector punctuations
+* *Other_ID_Start* - explicit list of characters in `PropList.txt `_ to support backwards compatibility
+* *Other_ID_Continue* - likewise
 
-All identifiers are converted into the normal form NFC while parsing; comparison
-of identifiers is based on NFC.
+All identifiers are converted into the normal form NFKC while parsing; comparison
+of identifiers is based on NFKC.
 
 A non-normative HTML file listing all valid identifier characters for Unicode
 4.1 can be found at

Modified: python/branches/py3k-cdecimal/Doc/tools/sphinxext/static/basic.css
==============================================================================
--- python/branches/py3k-cdecimal/Doc/tools/sphinxext/static/basic.css	(original)
+++ python/branches/py3k-cdecimal/Doc/tools/sphinxext/static/basic.css	Sun Jan  2 13:18:37 2011
@@ -364,6 +364,7 @@
 
 pre {
     overflow: auto;
+    overflow-y: hidden;
 }
 
 td.linenos pre {

Modified: python/branches/py3k-cdecimal/Doc/tools/sphinxext/susp-ignored.csv
==============================================================================
--- python/branches/py3k-cdecimal/Doc/tools/sphinxext/susp-ignored.csv	(original)
+++ python/branches/py3k-cdecimal/Doc/tools/sphinxext/susp-ignored.csv	Sun Jan  2 13:18:37 2011
@@ -324,3 +324,22 @@
 library/configparser,,`,# Set the optional `raw` argument of get() to True if you wish to disable
 library/configparser,,`,# The optional `vars` argument is a dict with members that will take
 library/configparser,,`,# The optional `fallback` argument can be used to provide a fallback value
+library/configparser,,:option,${section:option}
+library/configparser,,:system,path: ${Common:system_dir}/Library/Frameworks/
+library/configparser,,:home,my_dir: ${Common:home_dir}/twosheds
+library/configparser,,:path,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python}
+library/configparser,,:Python,python_dir: ${Frameworks:path}/Python/Versions/${Frameworks:Python}
+library/pdb,,:lineno,[filename:lineno | bpnumber [bpnumber ...]]
+library/pdb,,:lineno,filename:lineno
+library/logging,,:Watch,WARNING:root:Watch out!
+library/logging,,:So,INFO:root:So should this
+library/logging,,:Started,INFO:root:Started
+library/logging,,:Doing,INFO:root:Doing something
+library/logging,,:Finished,INFO:root:Finished
+library/logging,,:Look,WARNING:root:Look before you leap!
+library/logging,,:So,INFO:So should this
+library/logging,,:logger,severity:logger name:message
+library/logging,,:message,severity:logger name:message
+whatsnew/3.2,,:directory,...   ${buildout:directory}/downloads/dist
+whatsnew/3.2,,:location,... zope9-location = ${zope9:location}
+whatsnew/3.2,,:prefix,... zope-conf = ${custom:prefix}/etc/zope.conf

Modified: python/branches/py3k-cdecimal/Doc/tutorial/interpreter.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/tutorial/interpreter.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/tutorial/interpreter.rst	Sun Jan  2 13:18:37 2011
@@ -58,14 +58,6 @@
 ``python -m module [arg] ...``, which executes the source file for *module* as
 if you had spelled out its full name on the command line.
 
-Note that there is a difference between ``python file`` and ``python
->> import os
-   >>> os.system('time 0:02')
-   0
    >>> os.getcwd()      # Return the current working directory
    'C:\\Python31'
-   >>> os.chdir('/server/accesslogs')
+   >>> os.chdir('/server/accesslogs')   # Change current working directory
+   >>> os.system('mkdir today')   # Run the command mkdir in the system shell
+   0
 
 Be sure to use the ``import os`` style instead of ``from os import *``.  This
 will keep :func:`os.open` from shadowing the built-in :func:`open` function which
@@ -207,14 +207,14 @@
 :mod:`tarfile`. ::
 
    >>> import zlib
-   >>> s = 'witch which has which witches wrist watch'
+   >>> s = b'witch which has which witches wrist watch'
    >>> len(s)
    41
    >>> t = zlib.compress(s)
    >>> len(t)
    37
    >>> zlib.decompress(t)
-   'witch which has which witches wrist watch'
+   b'witch which has which witches wrist watch'
    >>> zlib.crc32(s)
    226805979
 

Modified: python/branches/py3k-cdecimal/Doc/using/cmdline.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/using/cmdline.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/using/cmdline.rst	Sun Jan  2 13:18:37 2011
@@ -220,6 +220,13 @@
    Discard docstrings in addition to the :option:`-O` optimizations.
 
 
+.. cmdoption:: -q
+
+   Don't display the copyright and version messages even in interactive mode.
+
+   .. versionadded:: 3.2
+
+
 .. cmdoption:: -s
 
    Don't add user site directory to sys.path

Modified: python/branches/py3k-cdecimal/Doc/whatsnew/2.7.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/whatsnew/2.7.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/whatsnew/2.7.rst	Sun Jan  2 13:18:37 2011
@@ -246,7 +246,7 @@
 modules.
 
 * The :mod:`ConfigParser` module uses them by default, meaning that
-  configuration files can now read, modified, and then written back
+  configuration files can now be read, modified, and then written back
   in their original order.
 
 * The :meth:`~collections.somenamedtuple._asdict()` method for

Modified: python/branches/py3k-cdecimal/Doc/whatsnew/3.2.rst
==============================================================================
--- python/branches/py3k-cdecimal/Doc/whatsnew/3.2.rst	(original)
+++ python/branches/py3k-cdecimal/Doc/whatsnew/3.2.rst	Sun Jan  2 13:18:37 2011
@@ -11,7 +11,7 @@
 
    * Anyone can add text to this document.  Do not spend very much time
    on the wording of your changes, because your text will probably
-   get rewritten to some degree.
+   get rewritten.
 
    * The maintainer will go through Misc/NEWS periodically and add
    changes; it's therefore more important to add your changes to
@@ -47,7 +47,128 @@
    This saves the maintainer the effort of going through the SVN log
    when researching a change.
 
-This article explains the new features in Python 3.2, compared to 3.1.
+This article explains the new features in Python 3.2 as compared to 3.1.  It
+focuses on a few highlights and gives a few examples.  For full details, see the
+:source:`Misc/NEWS ` file.
+
+.. seealso::
+
+   :pep:`392` - Python 3.2 Release Schedule
+
+PEP 384: Defining a Stable ABI
+==============================
+
+In the past, extension modules built for one Python version were often
+not usable with other Python versions. Particularly on Windows, every
+feature release of Python required rebuilding all extension modules that
+one wanted to use. This requirement was the result of the free access to
+Python interpreter internals that extension modules could use.
+
+With Python 3.2, an alternative approach becomes available: extension
+modules which restrict themselves to a limited API (by defining
+Py_LIMITED_API) cannot use many of the internals, but are constrained
+to a set of API functions that are promised to be stable for several
+releases. As a consequence, extension modules built for 3.2 in that
+mode will also work with 3.3, 3.4, and so on. Extension modules that
+make use of details of memory structures can still be built, but will
+need to be recompiled for every feature release.
+
+.. seealso::
+
+   :pep:`384` - Defining a Stable ABI
+      PEP written by Martin von L??wis.
+
+PEP 389: Argparse Command Line Parsing Module
+=============================================
+
+A new module for command line parsing, :mod:`argparse`, was introduced to
+overcome the limitations of :mod:`optparse` which did not provide support for
+positional arguments (not just options), subcommands, required options and other
+common patterns of specifying and validating options.
+
+This module has already has wide-spread success in the community as a
+third-party module.  Being more fully featured than its predecessor, the
+:mod:`argparse` module is now the preferred module for command-line processing.
+The older module is still being kept available because of the substantial amount
+of legacy code that depends on it.
+
+Here's an annotated example parser showing features like limiting results to a
+set of choices, specifying a *metavar* in the help screen, validating that one
+or more positional arguments is present, and making a required option::
+
+    import argparse
+    parser = argparse.ArgumentParser(
+                description = 'Manage servers',         # main description for help
+                epilog = 'Tested on Solaris and Linux') # displayed after help
+    parser.add_argument('action',                       # argument name
+                choices = ['deploy', 'start', 'stop'],  # one of four allowed values
+                help = 'action on each target')         # help msg
+    parser.add_argument('targets',
+                metavar = 'HOSTNAME',                   # var name used in help msg
+                nargs = '+',                            # require 1 or more targets
+                help = 'url for target machines')       # help msg explanation
+    parser.add_argument('-u', '--user',                 # -u or --user option
+                required = True,                        # make this a required argument
+                help = 'login as user')
+
+Example of calling the parser on a command string::
+
+    >>> cmd  = 'deploy sneezy.example.com sleepy.example.com -u skycaptain'
+    >>> result = parser.parse_args(cmd.split())
+    >>> result.action
+    'deploy'
+    >>> result.targets
+    ['sneezy.example.com', 'sleepy.example.com']
+    >>> result.user
+    'skycaptain'
+
+Example of the parser's automatically generated help::
+
+    >>> parser.parse_args('-h'.split())
+
+    usage: manage_cloud.py [-h] -u USER
+                           {deploy,start,stop} HOSTNAME [HOSTNAME ...]
+
+    Manage servers
+
+    positional arguments:
+      {deploy,start,stop}   action on each target
+      HOSTNAME              url for target machines
+
+    optional arguments:
+      -h, --help            show this help message and exit
+      -u USER, --user USER  login as user
+
+    Tested on Solaris and Linux
+
+An especially nice :mod:`argparse` feature is the ability to define subparsers,
+each with their own argument patterns and help displays::
+
+    import argparse
+    parser = argparse.ArgumentParser(prog='HELM')
+    subparsers = parser.add_subparsers()
+
+    parser_l = subparsers.add_parser('launch', help='Launch Control')   # first subgroup
+    parser_l.add_argument('-m', '--missiles', action='store_true')
+    parser_l.add_argument('-t', '--torpedos', action='store_true')
+
+    parser_m = subparsers.add_parser('move', help='Move Vessel',        # second subgroup
+                                     aliases=('steer', 'turn'))         # equivalent names
+    parser_m.add_argument('-c', '--course', type=int, required=True)
+    parser_m.add_argument('-s', '--speed', type=int, default=0)
+
+    $ ./helm.py --help                         # top level help (launch and move)
+    $ ./helm.py launch --help                  # help for launch options
+    $ ./helm.py launch --missiles              # set missiles=True and torpedos=False
+    $ ./helm.py steer --course 180 --speed 5   # set movement parameters
+
+.. seealso::
+
+   :pep:`389` - New Command Line Parsing Module
+      PEP written by Steven Bethard.
+
+   :ref:`upgrading-optparse-code` for details on the differences from
+      :mod:`optparse`.
 
 
 PEP 391:  Dictionary Based Configuration for Logging
@@ -84,7 +205,7 @@
     "root": {"level": "DEBUG", "handlers": ["console", "console_priority"]}}
 
 
-If that dictionary is stored in a file called "conf.json", it can loaded
+If that dictionary is stored in a file called :file:`conf.json`, it can loaded
 and called with code like this::
 
    >>> import logging.config
@@ -100,7 +221,60 @@
 PEP 3148:  The ``concurrent.futures`` module
 ============================================
 
-.. (Stub section)
+Code for creating and managing concurrency is being collected in a new toplevel
+namespace, *concurrent*.  Its first member is a *futures* package which provides
+a uniform high level interface for managing threads and processes.
+
+The design for :mod:`concurrent.futures` was inspired by
+*java.util.concurrent.package*.  In that model, a running call and its result
+are represented by a :class:`~concurrent.futures.Future` object which abstracts
+features common to threads, processes, and remote procedure calls.  That object
+supports status checks (running or done), timeouts, cancellations, adding
+callbacks, and access to results or exceptions.
+
+The primary offering of the new module is a pair of executor classes for
+launching and managing calls.  The goal of the executors is to make it easier to
+use existing tools for making parallel calls. They save the effort needed to
+setup a pool of resources, launch the calls, create a results queue, add
+time-out handling, and limit the total number of threads, processes, or remote
+procedure calls.
+
+Ideally, each application should share a single executor across multiple
+components so that process and thread limits can be centrally managed.  This
+solves the design challenge that arises when each component has its own
+competing strategy for resource management.
+
+Both classes share a common interface with three methods:
+:meth:`~concurrent.futures.Executor.submit` for scheduling a callable and
+returning a :class:`~concurrent.futures.Future` object;
+:meth:`~concurrent.futures.Executor.map` for scheduling many asynchronous calls
+at a time, and :meth:`~concurrent.futures.Executor.shutdown` for freeing
+resources.  The class is a :term:`context manager` and can be used within a
+:keyword:`with` statement to assure that resources are automatically released
+when currently pending futures are done executing.
+
+A simple of example of :class:`~concurrent.futures.ThreadPoolExecutor` is a
+launch of four parallel threads for copying files::
+
+  import shutil
+  with ThreadPoolExecutor(max_workers=4) as e:
+      e.submit(shutil.copy, 'src1.txt', 'dest1.txt')
+      e.submit(shutil.copy, 'src2.txt', 'dest2.txt')
+      e.submit(shutil.copy, 'src3.txt', 'dest3.txt')
+      e.submit(shutil.copy, 'src3.txt', 'dest4.txt')
+
+.. seealso::
+
+   :pep:`3148` - Futures -- Execute Computations Asynchronously
+      PEP written by Brian Quinlan.
+
+   :ref:`Code for Threaded Parallel URL reads`, an
+   example using threads to fetch multiple web pages in parallel.
+
+   :ref:`Code for computing prime numbers in
+   parallel`, an example demonstrating
+   :class:`~concurrent.futures.ProcessPoolExecutor`.
+
 
 
 PEP 3147:  PYC Repository Directories
@@ -158,8 +332,8 @@
       PEP written by Barry Warsaw.
 
 
-PEP 3149 ABI Version Tagged .so Files
-=====================================
+PEP 3149: ABI Version Tagged .so Files
+======================================
 
 The PYC repository directory allows multiple bytecode cache files to be
 co-located.  This PEP implements a similar mechanism for shared object files by
@@ -189,38 +363,29 @@
       PEP written by Barry Warsaw.
 
 
-Email 5.1
-=========
-
-The email package is extended to be able to parse and generate email messages
-in bytes format.
-
-* New functions :func:`~email.message_from_bytes` and
-  :func:`~email.message_from_binary_file`, and new classes
-  :class:`~email.parser.BytesFeedParser` and :class:`~email.parser.BytesParser`
-  allow binary message data to be parsed into model objects.
-
-* Given bytes input to the model, :meth:`~email.message.Message.get_payload`
-  will by default decode a message body that has a
-  :mailheader:`Content-Transfer-Encoding` of ``8bit`` using the charset
-  specified in the MIME headers and return the resulting string.
-
-* Given bytes input to the model, :class:`~email.generator.Generator` will
-  convert message bodies that have a :mailheader:`Content-Transfer-Encoding` of
-  8bit to instead have a 7bit Content-Transfer-Encoding.
+Other Language Changes
+======================
 
-* New class :class:`~email.generator.BytesGenerator` produces bytes
-  as output, preserving any unchanged non-ASCII data that was
-  present in the input used to build the model, including message bodies
-  with a :mailheader:`Content-Transfer-Encoding` of 8bit.
+Some smaller changes made to the core Python language are:
 
-  (Proposed and implemented by R. David Murray, :issue:`4661`.)
+* String formatting for :func:`format` and :meth:`str.format` gained new
+  capabilities for the format character **#**.  Previously, for integers in
+  binary, octal, or hexadecimal, it caused the output to be prefixed with '0b',
+  '0o', or '0x' respectively.  Now it can also handle floats, complex, and
+  Decimal, causing the output to always have a decimal point even when no digits
+  follow it.
+
+  >>> format(20, '#o')
+  '0o24'
+  >>> format(12.34, '#5.0f')
+  '  12.'
 
+  (Suggested by Mark Dickinson and implemented by Eric Smith in :issue:`7094`.)
 
-Other Language Changes
-======================
+* The interpreter can now be started with a quiet option, ``-q``, to suppress
+  the copyright and version information in an interactive mode.
 
-Some smaller changes made to the core Python language are:
+  (Contributed by Marcin Wojdyr in issue:`1772833`).
 
 * The :func:`hasattr` function used to catch and suppress any Exception.  Now,
   it only catches :exc:`AttributeError`.  Under the hood, :func:`hasattr` works
@@ -244,20 +409,18 @@
 
   (Proposed and implemented by Mark Dickinson; :issue:`9337`.)
 
-* :class:`memoryview` objects now have a :meth:`release()` method and support
-  the context manager protocol.  This allows timely release of any resources
-  that were acquired when requesting a buffer from the original object.
+* :class:`memoryview` objects now have a :meth:`~memoryview.release()` method
+  and they also now support the context manager protocol.  This allows timely
+  release of any resources that were acquired when requesting a buffer from the
+  original object.
+
+  >>> with memoryview(b'abcdefgh') as v:
+  ...     print(v.tolist())
+  ...
+  [97, 98, 99, 100, 101, 102, 103, 104]
 
   (Added by Antoine Pitrou; :issue:`9757`.)
 
-* Mark Dickinson crafted an elegant and efficient scheme for assuring that
-  different numeric datatypes will have the same hash value whenever their
-  actual values are equal::
-
-   >>> assert hash(Fraction(3, 2)) == hash(1.5) == \
-              hash(Decimal("1.5")) == hash(complex(1.5, 0))
-
-  (See :issue:`8188`.)
 
 * Previously it was illegal to delete a name from the local namespace if it
   occurs as a free variable in a nested block::
@@ -283,41 +446,179 @@
 
   (See :issue:`4617`.)
 
+* The internal :c:type:`structsequence` tool now creates subclasses of tuple.
+  This means that C generated structures like those returned by :func:`os.stat`,
+  :func:`time.gmtime`, and :func:`sys.version_info` now work like a
+  :term:`named tuple` and are more interoperable with functions and methods that
+  expect a tuple as an argument.  The is a big step forward in making the C
+  structures as flexible as their pure Python counterparts.
+
+  (Suggested by Arfrever Frehtes Taifersar Arahesis and implemented
+  by Benjamin Peterson in :issue:`8413`.)
+
+* Warnings are now easier to control.  A :envvar:`PYTHONWARNINGS` environment
+  variable is now available as an alternative to using ``-W`` at the command
+  line.
+
+  (Suggested by Barry Warsaw and implemented by Philip Jenvey in :issue:`7301`.)
+
 * A new warning category, :exc:`ResourceWarning`, has been added.  It is
-  emitted when certain potential issues with resource consumption or cleanup
+  emitted when potential issues with resource consumption or cleanup
   are detected.  It is silenced by default in normal release builds, but
-  can be easily enabled through the means provided by the :mod:`warnings`
+  can be enabled through the means provided by the :mod:`warnings`
   module, or on the command line.
 
-  :exc:`ResourceWarning` is issued at interpreter shutdown if the
+  A :exc:`ResourceWarning` is issued at interpreter shutdown if the
   :data:`gc.garbage` list isn't empty.  This is meant to make the programmer
   aware that their code contains object finalization issues.
 
-  (Added by Antoine Pitrou and Georg Brandl; :issue:`477863`.)
-
-  :exc:`ResourceWarning` is also issued when a :term:`file object` is destroyed
+  A :exc:`ResourceWarning` is also issued when a :term:`file object` is destroyed
   without having been explicitly closed.  While the deallocator for such
   object ensures it closes the underlying operating system resource
   (usually, a file descriptor), the delay in deallocating the object could
   produce various issues, especially under Windows.  Here is an example
   of enabling the warning from the command line::
 
-      $ ./python -Wdefault
-      Python 3.2a3+ (py3k, Nov  5 2010, 22:58:04)
-      [GCC 4.4.3] on linux2
-      Type "help", "copyright", "credits" or "license" for more information.
+      $ ./python -q -Wdefault
       >>> f = open("foo", "wb")
       >>> del f
       __main__:1: ResourceWarning: unclosed file <_io.BufferedWriter name='foo'>
-      >>>
 
-  (Added by Antoine Pitrou, :issue:`10093`.)
+  (Added by Antoine Pitrou and Georg Brandl in :issue:`10093` and :issue:`477863`.)
+
+* :class:`range` objects now support *index* and *count* methods. This is part
+  of an effort to make more objects fully implement the
+  :class:`collections.Sequence` :term:`abstract base class`.  As a result, the
+  language will have a more uniform API.  In addition, :class:`range` objects
+  now support slicing and negative indices.  This makes *range* more
+  interoperable with lists::
+
+      >>> range(0, 100, 2).count(10)
+      1
+      >>> range(0, 100, 2).index(10)
+      5
+      >>> range(0, 100, 2)[5]
+      10
+      >>> range(0, 100, 2)[0:5]
+      range(0, 10, 2)
+
+  (Contributed by Daniel Stuzback in :issue:`9213` and by Alexander Belopolsky
+  in :issue:`2690`.)
+
+* The :func:`callable` builtin function from Py2.x was resurrected.  It provides
+  a concise, readable alternative to using an :term:`abstract base class` in an
+  expression like ``isinstance(x, collections.Callable)``:
+
+  >>> callable(max)
+  True
+  >>> callable(20)
+  False
+
+  (See :issue:`10518`.)
+
+* Python's import mechanism can now load module installed in directories with
+  non-ASCII characters in the path name.
+
+  (Required extensive work by Victor Stinner in :issue:`9425`.)
 
 
 New, Improved, and Deprecated Modules
 =====================================
 
-* XXX mention :mod:`argparse`.
+Python's standard library has undergone significant maintenance efforts and
+quality improvements.
+
+The biggest news for Python 3.2 is that the :mod:`email` package and
+:mod:`nntplib` modules now work correctly with the bytes/text model in Python 3.
+For the first time, there is correct handling of inputs with mixed encodings.
+
+Throughout the standard library, there has been more careful attention to
+encodings and text versus bytes issues.  In particular, interactions with the
+operating system are now better able to pass non-ASCII data using the Windows
+mcbs encoding, locale aware encodings, or UTF-8.
+
+Another significant win is the addition of substantially better support for
+*SSL* connections and security certificates.
+
+In addition, more functions and classes now have a :term:`context manager` to
+support convenient and reliable resource clean-up using the
+:keyword:`with`-statement.
+
+email
+-----
+
+The usability of the :mod:`email` package in Python 3 has been mostly fixed by
+the extensive efforts of R. David Murray.  The problem was that emails are
+typically read and stored in the form of :class:`bytes` rather than :class:`str`
+text, and they may contain multiple encodings within a single email.  So, the
+email package had to be extended to parse and generate email messages in bytes
+format.
+
+* New functions :func:`~email.message_from_bytes` and
+  :func:`~email.message_from_binary_file`, and new classes
+  :class:`~email.parser.BytesFeedParser` and :class:`~email.parser.BytesParser`
+  allow binary message data to be parsed into model objects.
+
+* Given bytes input to the model, :meth:`~email.message.Message.get_payload`
+  will by default decode a message body that has a
+  :mailheader:`Content-Transfer-Encoding` of *8bit* using the charset
+  specified in the MIME headers and return the resulting string.
+
+* Given bytes input to the model, :class:`~email.generator.Generator` will
+  convert message bodies that have a :mailheader:`Content-Transfer-Encoding` of
+  *8bit* to instead have a *7bit* :mailheader:`Content-Transfer-Encoding`.
+
+* A new class :class:`~email.generator.BytesGenerator` produces bytes as output,
+  preserving any unchanged non-ASCII data that was present in the input used to
+  build the model, including message bodies with a
+  :mailheader:`Content-Transfer-Encoding` of *8bit*.
+
+* The :mod:`smtplib` :class:`~smtplib.SMTP` class now accepts a byte string
+  for the *msg* argument to the :meth:`~smtplib.SMTP.sendmail` method,
+  and a new method, :meth:`~smtplib.SMTP.send_message` accepts a
+  :class:`~email.message.Message` object and can optionally obtain the
+  *from_addr* and *to_addrs* addresses directly from the object.
+
+.. XXX Update before 3.2rc1 to reflect all of the latest work and add examples.
+
+(Proposed and implemented by R. David Murray, :issue:`4661` and :issue:`10321`.)
+
+elementtree
+-----------
+
+The :mod:`xml.etree.ElementTree` package and its :mod:`xml.etree.cElementTree`
+counterpart have been updated to version 1.3.
+
+Several new and useful functions and methods have been added:
+
+* :func:`xml.etree.ElementTree.fromstringlist` which builds an XML document
+  from a sequence of fragments
+* :func:`xml.etree.ElementTree.register_namespace` for registering a global
+  namespace prefix
+* :func:`xml.etree.ElementTree.tostringlist` for string representation
+  including all sublists
+* :meth:`xml.etree.ElementTree.Element.extend` for appending a sequence of zero
+  or more elements
+* :meth:`xml.etree.ElementTree.Element.iterfind` searches an element and
+  subelements
+* :meth:`xml.etree.ElementTree.Element.itertext` creates a text iterator over
+  an element and its sub-elements
+* :meth:`xml.etree.ElementTree.TreeBuilder.end` closes the current element
+* :meth:`xml.etree.ElementTree.TreeBuilder.doctype` handles a doctype
+  declaration
+
+Two methods have been deprecated:
+
+* :meth:`xml.etree.ElementTree.getchildren` use ``list(elem)`` instead.
+* :meth:`xml.etree.ElementTree.getiterator` use ``Element.iter`` instead.
+
+For details of the update, see `Introducing ElementTree
+`_ on Fredrik Lundh's website.
+
+(Contributed by Florent Xicluna and Fredrik Lundh, :issue:`6472`.)
+
+functools
+---------
 
 * The :mod:`functools` module includes a new decorator for caching function
   calls.  :func:`functools.lru_cache` can save repeated queries to an external
@@ -332,20 +633,22 @@
          c.execute('SELECT phonenumber FROM phonelist WHERE name=?', (name,))
          return c.fetchone()[0]
 
+  >>> for name in user_requests:
+  ...     get_phone_number(name)        # cached lookup
+
   To help with choosing an effective cache size, the wrapped function is
-  instrumented with two attributes *cache_hits* and *cache_misses*:
+  instrumented for tracking cache statistics:
 
-  >>> for name in user_requests:
-  ...     get_phone_number(name)
-  >>> print(get_phone_number.cache_hits, get_phone_number.cache_misses)
-  4805 980
+  >>> get_phone_number.cache_info()
+  CacheInfo(hits=4805, misses=980, maxsize=300, currsize=300)
 
   If the phonelist table gets updated, the outdated contents of the cache can be
   cleared with:
 
   >>> get_phone_number.cache_clear()
 
-  (Contributed by Raymond Hettinger.)
+  (Contributed by Raymond Hettinger and incorporating design ideas from
+  Jim Baker, Miki Tebeka, and Nick Coghlan.)
 
 * The :func:`functools.wraps` decorator now adds a :attr:`__wrapped__` attribute
   pointing to the original callable function.  This allows wrapped functions to
@@ -356,76 +659,312 @@
   (By Nick Coghlan and Terrence Cole; :issue:`9567`, :issue:`3445`, and
   :issue:`8814`.)
 
-* The :mod:`nntplib` module gets a revamped implementation with better
-  bytes / unicode semantics as well as more practical APIs.  These improvements
-  break compatibility with the nntplib version in Python 3.1, which was
-  partly dysfunctional in itself.
+* To help write classes with rich comparison methods, a new decorator
+  :func:`functools.total_ordering` will use a existing equality and inequality
+  methods to fill-in the remaining methods.
+
+  For example, supplying *__eq__* and *__lt__* will enable
+  :func:`~functools.total_ordering` to fill-in *__le__*, *__gt__* and *__ge__*::
+
+    @total_ordering
+    class Student:
+        def __eq__(self, other):
+            return ((self.lastname.lower(), self.firstname.lower()) ==
+                    (other.lastname.lower(), other.firstname.lower()))
+        def __lt__(self, other):
+            return ((self.lastname.lower(), self.firstname.lower()) <
+                    (other.lastname.lower(), other.firstname.lower()))
 
-  (Contributed by Antoine Pitrou in :issue:`9360`)
+  (Contributed by Raymond Hettinger.)
 
-* The :mod:`abc` module now supports :func:`~abc.abstractclassmethod` and
-  :func:`~abc.abstractstaticmethod`.
+.. XXX clarify what the example does
 
-  (Patch submitted by Daniel Urban; :issue:`5867`.)
+* To aid in porting programs from Python 2, the :func:`~functools.cmp_to_key`
+  function converts an old-style comparison function to
+  modern :term:`key function`:
 
-* The previously deprecated :func:`contextlib.nested` function has been removed
-  in favor of a plain :keyword:`with` statement which can accept multiple
-  context managers.  The latter technique is faster (because it is built-in),
-  and it does a better job finalizing multiple context managers when one of them
-  raises an exception.
+  >>> # locale-aware sort order
+  >>> sorted(iterable, key=cmp_to_key(locale.strcoll))
 
-  (Contributed by Georg Brandl and Mattias Br??ndstr??m;
-  `appspot issue 53094 `_.)
+  For sorting examples and a brief sorting tutorial, see the `Sorting HowTo
+  `_ tutorial.
+
+  (Contributed by Raymond Hettinger.)
+
+itertools
+---------
+
+* The :mod:`itertools` module has a new :func:`~itertools.accumulate` function
+  modeled on APL's *scan* operator and on Numpy's *accumulate* function:
+
+  >>> list(accumulate(8, 2, 50))
+  [8, 10, 60]
+
+  >>> prob_dist = [0.1, 0.4, 0.2, 0.3]
+  >>> list(accumulate(prob_dist))      # cumulative probability distribution
+  [0.1, 0.5, 0.7, 1.0]
+
+  For an example using :func:`~itertools.accumulate`, see the :ref:`examples for
+  the random module `.
+
+  (Contributed by Raymond Hettinger and incorporating design suggestions
+  from Mark Dickinson.)
+
+collections
+-----------
+
+* The :class:`collections.Counter` class now has two forms of in-place
+  subtraction, the existing *-=* operator for `saturating subtraction
+  `_ and the new
+  :meth:`~collections.Counter.subtract` method for regular subtraction.  The
+  former is suitable for `multisets `_
+  which only have positive counts, and the latter is more suitable for use cases
+  that allow negative counts:
+
+  >>> tally = Counter(dogs=5, cat=3)
+  >>> tally -= Counter(dogs=2, cats=8)    # saturating subtraction
+  >>> tally
+  Counter({'dogs': 3})
+
+  >>> tally = Counter(dogs=5, cats=3)
+  >>> tally.subtract(dogs=2, cats=8)      # regular subtraction
+  >>> tally
+  Counter({'dogs': 3, 'cats': -5})
+
+  (Contributed by Raymond Hettinger.)
+
+* The :class:`collections.OrderedDict` class has a new method
+  :meth:`~collections.OrderedDict.move_to_end` which takes an existing key and
+  moves it to either the beginning or end of an ordered sequence.  When the
+  dictionary sequence is being used as a queue, these operations correspond to
+  "move to the front of the line" or "move to the back of the line":
+
+  >>> d = OrderedDict.fromkeys(['a', 'b', 'X', 'd', 'e'])
+  >>> list(d)
+  ['a', 'b', 'X', 'd', 'e']
+  >>> d.move_to_end('X', last=True)
+  >>> list(d)
+  ['a', 'b', 'd', 'e', 'X']
+  >>> d.move_to_end('X', last=False)
+  >>> list(d)
+  ['X', 'a', 'b', 'd', 'e']
+
+  (Contributed by Raymond Hettinger.)
+
+* The :class:`collections.deque` grew two new methods :meth:`~collections.deque.count`
+  and :meth:`collections.deque.reverse` that make them more substitutable for
+  :class:`list` when needed:
+
+  >>> d = deque('simsalabim')
+  >>> d.count('s')
+  2
+  >>> d.reverse()
+  >>> d
+  deque(['m', 'i', 'b', 'a', 'l', 'a', 's', 'm', 'i', 's'])
+
+  (Contributed by Raymond Hettinger.)
+
+datetime
+--------
+
+* The :mod:`datetime` module has a new type :class:`~datetime.timezone` that
+  implements the :class:`~datetime.tzinfo` interface by returning a fixed UTC
+  offset and timezone name. This makes it easier to create timezone aware
+  datetime objects:
+
+  >>> datetime.now(timezone.utc)
+  datetime.datetime(2010, 12, 8, 21, 4, 2, 923754, tzinfo=datetime.timezone.utc)
+
+  >>> datetime.strptime("01/01/2000 12:00 +0000", "%m/%d/%Y %H:%M %z")
+  datetime.datetime(2000, 1, 1, 12, 0, tzinfo=datetime.timezone.utc)
+
+* Also, :class:`~datetime.timedelta` objects can now be multiplied by
+  :class:`float` and divided by :class:`float` and :class:`int` objects.
+
+.. XXX Describe added support for dividing a timedelta by another timedelta.
+       See revision 80290 and issue #2706.
+
+  (Contributed by Alexander Belopolsky in :issue:`1289118`, :issue:`5094` and
+  :issue:`6641`.)
+
+abc
+---
+
+The :mod:`abc` module now supports :func:`~abc.abstractclassmethod` and
+:func:`~abc.abstractstaticmethod`.
+
+These tools make it possible to define an :term:`Abstract Base Class` that
+requires a particular :func:`classmethod` or :func:`staticmethod` to be
+implemented.
+
+(Patch submitted by Daniel Urban; :issue:`5867`.)
+
+contextlib
+----------
 
-* The :class:`ftplib.FTP` class now supports the context manager protocol to
-  unconditionally consume :exc:`socket.error` exceptions and to close the FTP
-  connection when done::
+There is a new and slightly mind-blowing tool
+:class:`~contextlib.ContextDecorator` that is helpful for creating a
+:term:`context manager` that does double-duty as a function decorator.
 
-   >>> from ftplib import FTP
-   >>> with FTP("ftp1.at.proftpd.org") as ftp:
-   ...     ftp.login()
-   ...     ftp.dir()
-   ...
-   '230 Anonymous login ok, restrictions apply.'
-   dr-xr-xr-x   9 ftp      ftp           154 May  6 10:43 .
-   dr-xr-xr-x   9 ftp      ftp           154 May  6 10:43 ..
-   dr-xr-xr-x   5 ftp      ftp          4096 May  6 10:43 CentOS
-   dr-xr-xr-x   3 ftp      ftp            18 Jul 10  2008 Fedora
+As a convenience, this new functionality is used by
+:func:`~contextlib.contextmanager` so that no extra effort is needed to support
+both roles.
 
-  Other file-like objects such as :class:`mmap.mmap` and :func:`fileinput.input`
-  also grew auto-closing context managers::
+The basic idea is that both context managers and function decorators can be used
+for pre-action and post-action wrappers.  Context managers wrap a group of
+statements using the :keyword:`with`-statement, and function decorators wrap a
+group of statements enclosed in a function.  So, occasionally there is a need to
+write a pre/post action wrapper that can be used in either role.
 
-      with fileinput.input(files=('log1.txt', 'log2.txt')) as f:
-          for line in f:
-              process(line)
+For example, it is sometimes useful to wrap functions or groups of statements
+with a logger that can track the time of entry and time of exit.  Rather than
+writing both a function decorator and a context manager for the task, the
+:func:`~contextlib.contextmanager` provides both capabilities in a single
+definition:
 
-  (Contributed by Tarek Ziad?? and Giampaolo Rodol?? in :issue:`4972`, and
-  by Georg Brandl in :issue:`8046` and :issue:`1286`.)
+>>> import logging
+>>> logging.basicConfig(level=logging.INFO)
+>>> @contextmanager
+... def track_entry_and_exit(name):
+...     logging.info('Entering: {}'.format(name))
+...     yield
+...     logging.info('Exiting: {}'.format(name))
 
-* :class:`gzip.GzipFile` now implements the :class:`io.BufferedIOBase` ABC
-  (except for ``truncate()``), has a :meth:`~gzip.GzipFile.peek` method,
-  and supports unseekable as well as zero-padded file objects.
+Formerly, this would have only been usable as a context manager:
 
-  (Contributed by Antoine Pitrou, Nir Aides and Brian Curtin in :issue:`9962`,
-  :issue:`1675951`, :issue:`7471` and :issue:`2846`.)
+>>> with track_entry_and_exit('widget loader'):
+...     print('Some time consuming activity goes here')
+...     load_widget()
 
-  The :mod:`gzip` module also gains the :func:`~gzip.compress` and
-  :func:`~gzip.decompress` functions for easier in-memory compression and
-  decompression.
+Now, it can be used as a decorator as well:
 
-  (Contributed by Anand B. Pillai in :issue:`3488`.)
+>>> @track_entry_and_exit('widget loader')
+... def activity():
+...     print('Some time consuming activity goes here')
+...     load_widget()
 
-* The :mod:`os` module now has the :const:`ST_RDONLY` and :const:`ST_NOSUID`
-  constants, for use with the :func:`~os.statvfs` function.
+Trying to fulfill two roles at once places some limitations on the technique.
+Context managers normally have the flexibility to return an argument usable by
+the :keyword:`with`-statement, but there is no parallel for function decorators.
 
-  (Patch by Adam Jackson; :issue:`7647`.)
+In the above example, there is not a clean way for the *track_entry_and_exit*
+context manager does not have a way to return a logging instance for use in the
+body of enclosed statements.
 
-* :func:`os.getppid` is now supported on Windows.  Note that it will continue to
-  return the same pid even after the parent process has exited.
+(Contributed by Michael Foord in :issue:`9110`.)
 
-  (Patch by Jon Anglin; :issue:`6394`.)
+decimal and fractions
+---------------------
 
-* The :func:`shutil.copytree` function has two new options:
+Mark Dickinson crafted an elegant and efficient scheme for assuring that
+different numeric datatypes will have the same hash value whenever their actual
+values are equal (:issue:`8188`)::
+
+   >>> assert hash(Fraction(3, 2)) == hash(1.5) == \
+              hash(Decimal("1.5")) == hash(complex(1.5, 0))
+
+An early decision to limit the inter-operability of various numeric types has
+been relaxed.  It is still unsupported (and ill-advised) to to have implicit
+mixing in arithmetic expressions such as ``Decimal('1.1') + float('1.1')``
+because the latter loses information in the process of constructing the binary
+float.  However, since existing floating point value can be converted losslessly
+to either a decimal or rational representation, it makes sense to add them to
+the constructor and to support mixed-type comparisons.
+
+* The :class:`decimal.Decimal` constructor now accepts :class:`float` objects
+  directly so there in no longer a need to use the :meth:`~decimal.Decimal.from_float`
+  method (:issue:`8257`).
+
+* Mixed type comparisons are now fully supported so that
+  :class:`~decimal.Decimal` objects can be directly compared with :class:`float`
+  and :class:`fractions.Fraction` (:issue:`2531` and :issue:`8188`).
+
+Similar changes were made to :class:`fractions.Fraction` so that the
+:meth:`~fractions.Fraction.from_float()` and :meth:`~fractions.Fraction.from_decimal`
+methods are no longer needed (:issue:`8294`):
+
+>>> Decimal(1.1)
+Decimal('1.100000000000000088817841970012523233890533447265625')
+>>> Fraction(1.1)
+Fraction(2476979795053773, 2251799813685248)
+
+Another useful change for the :mod:`decimal` module is that the
+:attr:`Context.clamp` attribute is now public.  This is useful in creating
+contexts that correspond to the decimal interchange formats specified in IEEE
+754 (see :issue:`8540`).
+
+(Contributed by Mark Dickinson and Raymond Hettinger.)
+
+ftp
+---
+
+The :class:`ftplib.FTP` class now supports the context manager protocol to
+unconditionally consume :exc:`socket.error` exceptions and to close the FTP
+connection when done::
+
+ >>> from ftplib import FTP
+ >>> with FTP("ftp1.at.proftpd.org") as ftp:
+ ...     ftp.login()
+ ...     ftp.dir()
+ ...
+ '230 Anonymous login ok, restrictions apply.'
+ dr-xr-xr-x   9 ftp      ftp           154 May  6 10:43 .
+ dr-xr-xr-x   9 ftp      ftp           154 May  6 10:43 ..
+ dr-xr-xr-x   5 ftp      ftp          4096 May  6 10:43 CentOS
+ dr-xr-xr-x   3 ftp      ftp            18 Jul 10  2008 Fedora
+
+Other file-like objects such as :class:`mmap.mmap` and :func:`fileinput.input`
+also grew auto-closing context managers::
+
+    with fileinput.input(files=('log1.txt', 'log2.txt')) as f:
+        for line in f:
+            process(line)
+
+(Contributed by Tarek Ziad?? and Giampaolo Rodol?? in :issue:`4972`, and
+by Georg Brandl in :issue:`8046` and :issue:`1286`.)
+
+.. XXX mention os.popen and subprocess.Popen auto-closing of fds
+
+gzip and zipfile
+----------------
+
+:class:`gzip.GzipFile` now implements the :class:`io.BufferedIOBase`
+:term:`abstract base class` (except for ``truncate()``).  It also has a
+:meth:`~gzip.GzipFile.peek` method and supports unseekable as well as
+zero-padded file objects.
+
+The :mod:`gzip` module also gains the :func:`~gzip.compress` and
+:func:`~gzip.decompress` functions for easier in-memory compression and
+decompression.  Keep in mind that text needs to be encoded in to :class:`bytes`
+before compressing and decompressing:
+
+>>> s = 'Three shall be the number thou shalt count, '
+>>> s += 'and the number of the counting shall be three'
+>>> b = s.encode()                        # convert to utf-8
+>>> len(b)
+89
+>>> c = gzip.compress(b)
+>>> len(c)
+77
+>>> gzip.decompress(c).decode()[:42]      # decompress and convert to text
+'Three shall be the number thou shalt count,'
+
+(Contributed by Anand B. Pillai in :issue:`3488`; and by Antoine Pitrou, Nir
+Aides and Brian Curtin in :issue:`9962`, :issue:`1675951`, :issue:`7471` and
+:issue:`2846`.)
+
+Also, the :class:`zipfile.ZipExtFile` class was reworked internally to represent
+files stored inside an archive.  The new implementation is significantly faster
+and can be wrapped in a :class:`io.BufferedReader` object for more speedups.  It
+also solves an issue where interleaved calls to *read* and *readline* gave the
+wrong results.
+
+(Patch submitted by by Nir Aides in :issue:`7610`.)
+
+shutil
+------
+
+The :func:`shutil.copytree` function has two new options:
 
   * *ignore_dangling_symlinks*: when ``symlinks=False`` so that the function
     copies the file pointed to by the symlink, not the symlink itself. This
@@ -434,25 +973,40 @@
   * *copy_function*: is a callable that will be used to copy files.
     :func:`shutil.copy2` is used by default.
 
-  (Contributed by Tarek Ziad??.)
+(Contributed by Tarek Ziad??.)
+
+sqlite3
+-------
+
+The :mod:`sqlite3` module was updated to version 2.6.0.  It has two new capabilities.
+
+* The :attr:`sqlite3.Connection.in_transit` attribute is true if there is an
+  active transaction for uncommitted changes.
+
+* The :meth:`sqlite3.Connection.enable_load_extension` and
+  :meth:`sqlite3.Connection.load_extension` methods allows you to load SQLite
+  extensions from ".so" files.  One well-known extension is the fulltext-search
+  extension distributed with SQLite.
+
+(Contributed by R. David Murray and Shashwat Anand; :issue:`8845`.)
+
+socket
+------
+
+The :mod:`socket` module has two new improvements.
 
 * Socket objects now have a :meth:`~socket.socket.detach()` method which puts
   the socket into closed state without actually closing the underlying file
   descriptor.  The latter can then be reused for other purposes.
-
   (Added by Antoine Pitrou; :issue:`8524`.)
 
-* The :mod:`sqlite3` module has two new capabilities.
-
-  The :attr:`Connection.in_transit` attribute is true if there is an active
-  transaction for uncommitted changes.
-
-  The :meth:`Connection.enable_load_extension` and
-  :meth:`Connection.load_extension` methods allows you to load SQLite extensions
-  from ".so" files.  One well-known extension is the fulltext-search extension
-  distributed with SQLite.
+* :func:`socket.create_connection` now supports the context manager protocol
+  to unconditionally consume :exc:`socket.error` exceptions and to close the
+  socket when done.
+  (Contributed by Giampaolo Rodol??; :issue:`9794`.)
 
-  (Contributed by R. David Murray and Shashwat Anand; :issue:`8845`.)
+ssl
+---
 
 * The :mod:`ssl` module has a new class, :class:`~ssl.SSLContext` which serves
   as a container for various persistent SSL data, such as protocol settings,
@@ -460,18 +1014,18 @@
   :meth:`~ssl.SSLContext.wrap_socket` method allows to create an SSL socket from
   such an SSL context.  (Added by Antoine Pitrou; :issue:`8550`.)
 
-  A new function, :func:`ssl.match_hostname`, helps implement server identity
+* A new function, :func:`ssl.match_hostname`, helps implement server identity
   verification for higher-level protocols by implementing the rules of
   HTTPS (from :rfc:`2818`), which are also suitable for other protocols.
   (Added by Antoine Pitrou, :issue:`1589`).
 
-  The :func:`ssl.wrap_socket` constructor function now takes a *ciphers*
+* The :func:`ssl.wrap_socket` constructor function now takes a *ciphers*
   argument that's a string listing the encryption algorithms to be allowed; the
   format of the string is described `in the OpenSSL documentation
   `__.  (Added
   by Antoine Pitrou; :issue:`8322`.)
 
-  When linked against a recent enough version of OpenSSL, the :mod:`ssl`
+* When linked against a recent enough version of OpenSSL, the :mod:`ssl`
   module now supports the Server Name Indication extension to the TLS
   protocol, allowing for several "virtual hosts" using different certificates
   on a single IP/port.  This extension is only supported in client mode,
@@ -479,43 +1033,117 @@
   :meth:`SSLContext.wrap_socket`.
   (Added by Antoine Pitrou, :issue:`5639`.)
 
-  Various options have been added to the :mod:`ssl` module, such as
+* Various options have been added to the :mod:`ssl` module, such as
   :data:`~ssl.OP_NO_SSLv2` which allows to force disabling of the insecure and
   obsolete SSLv2 protocol.  (Added by Antoine Pitrou; :issue:`4870`.)
 
-  Another change makes the extension load all of OpenSSL's ciphers and digest
+* Another change makes the extension load all of OpenSSL's ciphers and digest
   algorithms so that they're all available.  Some SSL certificates couldn't be
   verified, reporting an "unknown algorithm" error.  (Reported by Beda Kosata,
   and fixed by Antoine Pitrou; :issue:`8484`.)
 
-  The version of OpenSSL being used is now available as the module attributes
+* The version of OpenSSL being used is now available as the module attributes
   :data:`ssl.OPENSSL_VERSION` (a string), :data:`ssl.OPENSSL_VERSION_INFO` (a
   5-tuple), and :data:`ssl.OPENSSL_VERSION_NUMBER` (an integer).  (Added by
   Antoine Pitrou; :issue:`8321`.)
 
-* :class:`http.client.HTTPSConnection`, :class:`urllib.request.HTTPSHandler`
-  and :func:`urllib.request.urlopen` now take optional arguments to allow for
-  server certificate checking against a set of Certificate Authorities,
-  as recommended in public uses of HTTPS.
-  (Added by Antoine Pitrou, :issue:`9003`.)
-
-* Instances of :class:`unittest.TestCase` have two new methods
-  :meth:`~unittest.TestCase.assertWarns` and :meth:`~unittest.TestCase.assertWarnsRegexp`
-  to check that a given warning type was triggered by the code under test::
-
-      with self.assertWarns(DeprecationWarning):
-          legacy_function('XYZ')
+nntp
+----
 
+The :mod:`nntplib` module has a revamped implementation with better bytes and
+unicode semantics as well as more practical APIs.  These improvements break
+compatibility with the nntplib version in Python 3.1, which was partly
+dysfunctional in itself.
+
+(Contributed by Antoine Pitrou in :issue:`9360`)
+
+certificates
+------------
+
+:class:`http.client.HTTPSConnection`, :class:`urllib.request.HTTPSHandler`
+and :func:`urllib.request.urlopen` now take optional arguments to allow for
+server certificate checking against a set of Certificate Authorities,
+as recommended in public uses of HTTPS.
+
+(Added by Antoine Pitrou, :issue:`9003`.)
+
+unittest
+--------
+
+* The command-line call, ``python -m unittest`` can now accept file paths
+  instead of module names for running specific tests (:issue:`10620`).  The new
+  test discovery can find tests within packages, locating any test importable
+  from the top level directory.  The top level directory can be specified with
+  the `-t` option, a pattern for matching files with ``-p``, and a directory to
+  start discovery with ``-s``::
+
+    $ python -m unittest discover -s my_proj_dir -p '_test.py'
+
+  (Contributed by Michael Foord.)
+
+* The :mod:`unittest` module has two new methods,
+  :meth:`~unittest.TestCase.assertWarns` and
+  :meth:`~unittest.TestCase.assertWarnsRegex` to check that a given warning type
+  is triggered by the code under test:
+
+  >>> with self.assertWarns(DeprecationWarning):
+  ...     legacy_function('XYZ')
+
+  Another new method, :meth:`~unittest.TestCase.assertCountEqual` is used to
+  compare two iterables to determine if their element counts are equal (whether
+  the same elements are present with the same number of occurrences regardless
+  of order)::
+
+     def test_anagram(self):
+         self.assertCountEqual('algorithm', 'logarithm')
+
+  A principal feature of the unittest module is an effort to produce meaningful
+  diagnostics when a test fails.  When possible the failure is recorded along
+  with a diff of the output.  This is especially helpful for analyzing log files
+  of failed test runs. However, since diffs can sometime be voluminous, there is
+  a new :attr:`~unittest.TestCase.maxDiff` attribute which sets maximum length of
+  diffs.
+
+  In addition the naming in the module has undergone a number of clean-ups.  For
+  example, :meth:`~unittest.TestCase.assertRegex` is the new name for
+  :meth:`~unittest.TestCase.assertRegexpMatches` which was misnamed because the
+  test uses :func:`re.search`, not :func:`re.match`.  Other methods using
+  regular expressions are now named using short form "Regex" in preference
+  to "Regexp" -- this matches the names used in other unittest implementations,
+  matches Python's old name for the :mod:`re` module, and it has unambiguous
+  camel-casing.
+
+  To improve consistency, some of long-standing method aliases are being
+  deprecated in favor of the preferred names:
+
+   - replace :meth:`assert_` with :meth:`.assertTrue`
+   - replace :meth:`assertEquals` with :meth:`.assertEqual`
+   - replace :meth:`assertNotEquals` with :meth:`.assertNotEqual`
+   - replace :meth:`assertAlmostEquals` with :meth:`.assertAlmostEqual`
+   - replace :meth:`assertNotAlmostEquals` with :meth:`.assertNotAlmostEqual`
+
+  Likewise, the ``TestCase.fail*`` methods deprecated in Python 3.1 are expected
+  to be removed in Python 3.3. See also the :ref:`deprecated-aliases` section in
+  the :mod:`unittest` documentation.
+
+  (Contributed by Ezio Melotti; :issue:`9424`.)
+
+random
+------
+
+The integer methods in the :mod:`random` module now do a better job of producing
+uniform distributions.  Previously, they computed selections with
+``int(n*random())`` which had a slight bias whenever *n* was not a power of two.
+Now, multiple selections are made from a range upto the next power of two and a
+selection is kept only when it falls within the range ``0 <= x < n``.  The
+functions and methods affected are :func:`~random.randrange`,
+:func:`~random.randint`, :func:`~random.choice`, :func:`~random.shuffle` and
+:func:`~random.sample`.
 
-* The previously deprecated :func:`string.maketrans` function has been removed
-  in favor of the static methods, :meth:`bytes.maketrans` and
-  :meth:`bytearray.maketrans`.  This change solves the confusion around which
-  types were supported by the :mod:`string` module.  Now, :class:`str`,
-  :class:`bytes`, and :class:`bytearray` each have their own **maketrans** and
-  **translate** methods with intermediate translation tables of the appropriate
-  type.
+(Contributed by Raymond Hettinger; :issue:`9025`.)
 
-  (Contributed by Georg Brandl; :issue:`5675`.)
+poplib
+------
 
 * :class:`~poplib.POP3_SSL` class now accepts a *context* parameter, which is a
   :class:`ssl.SSLContext` object allowing bundling SSL configuration options,
@@ -524,12 +1152,6 @@
 
   (Contributed by Giampaolo Rodol??; :issue:`8807`.)
 
-* :func:`socket.create_connection` now supports the context manager protocol
-  to unconditionally consume :exc:`socket.error` exceptions and to close the
-  socket when done.
-
-  (Contributed by Giampaolo Rodol??; :issue:`9794`.)
-
 * :class:`asyncore.dispatcher` now provides a
   :meth:`~asyncore.dispatcher.handle_accepted()` method
   returning a `(sock, addr)` pair which is called when a connection has actually
@@ -539,28 +1161,208 @@
 
   (Contributed by Giampaolo Rodol??; :issue:`6706`.)
 
-* The :mod:`tempfile` module has a new context manager,
-  :class:`~tempfile.TemporaryDirectory` which provides easy deterministic
-  cleanup of temporary directories.
-
-  (Contributed by Neil Schemenauer and Nick Coghlan; :issue:`5178`.)
-
-* The :mod:`smtplib` :class:`~smtplib.SMTP` class now accepts a byte string
-  for the *msg* argument to the :meth:`~smtplib.SMTP.sendmail` method,
-  and a new method, :meth:`~smtplib.SMTP.send_message` accepts a
-  :class:`~email.message.Message` object and can optionally obtain the
-  *from_addr* and *to_addrs* addresses directly from the object.
-
-  (Contributed by R. David Murray, :issue:`10321`.)
+tempfile
+--------
 
-
-* The :mod:`inspect` module has a new function :func:`getgenatorstate`
-  to easily identify the current state of a generator as one of
-  ``GEN_CREATED``, ``GEN_RUNNING``, ``GEN_SUSPENDED`` or ``GEN_CLOSED``.
-
-  (Contributed by Rodolpho Eckhardt and Nick Coghlan, :issue:`10220`.)
-
-.. XXX: Mention inspect.getattr_static (Michael Foord)
+The :mod:`tempfile` module has a new context manager,
+:class:`~tempfile.TemporaryDirectory` which provides easy deterministic
+cleanup of temporary directories:
+
+>>> with tempfile.TemporaryDirectory() as tmpdirname:
+...     print 'created temporary directory', tmpdirname
+
+(Contributed by Neil Schemenauer and Nick Coghlan; :issue:`5178`.)
+
+inspect
+-------
+
+* The :mod:`inspect` module has a new function
+  :func:`~inspect.getgeneratorstate` to easily identify the current state of a
+  generator as one of ``GEN_CREATED``, ``GEN_RUNNING``, ``GEN_SUSPENDED`` or
+  ``GEN_CLOSED``. (Contributed by Rodolpho Eckhardt and Nick Coghlan,
+  :issue:`10220`.)
+
+* To support lookups without the possibility of activating a dynamic attribute,
+  the :mod:`inspect` module has a new function, :func:`~inspect.getattr_static`.
+  Unlike, :func:`hasattr`, this is a true read-only search, guaranteed not to
+  change state while it is searching.  (Contributed by Michael Foord.)
+
+pydoc
+-----
+
+The :mod:`pydoc` module now provides a much improved Web server interface,
+as well as a new command-line option to automatically open a browser
+window to display that server.
+
+(Contributed by Ron Adam; :issue:`2001`.)
+
+sysconfig
+---------
+
+The new :mod:`sysconfig` module makes it straight-forward to discover
+installation paths and configuration variables which vary across platforms and
+installations.
+
+The module offers access simple access functions for platform and version
+information:
+
+* :func:`~sysconfig.get_platform` returning values like *linux-i586* or
+  *macosx-10.6-ppc*.
+* :func:`~sysconfig.get_python_version` returns a Python version string in
+  the form, "3.2".
+
+It also provides access to the paths and variables corresponding to one of
+seven named schemes used by :mod:`distutils`.  Those include *posix_prefix*,
+*posix_home*, *posix_user*, *nt*, *nt_user*, *os2*, *os2_home*:
+
+* :func:`~sysconfig.get_paths` makes a dictionary containing installation paths
+  for the current installation scheme.
+* :func:`~sysconfig.get_config_vars` returns a dictionary of platform specific
+  variables.
+
+There is also a convenient command-line interface::
+
+  C:\Python32>python -m sysconfig
+  Platform: "win32"
+  Python version: "3.2"
+  Current installation scheme: "nt"
+
+  Paths:
+          data = "C:\Python32"
+          include = "C:\Python32\Include"
+          platinclude = "C:\Python32\Include"
+          platlib = "C:\Python32\Lib\site-packages"
+          platstdlib = "C:\Python32\Lib"
+          purelib = "C:\Python32\Lib\site-packages"
+          scripts = "C:\Python32\Scripts"
+          stdlib = "C:\Python32\Lib"
+
+  Variables:
+          BINDIR = "C:\Python32"
+          BINLIBDEST = "C:\Python32\Lib"
+          EXE = ".exe"
+          INCLUDEPY = "C:\Python32\Include"
+          LIBDEST = "C:\Python32\Lib"
+          SO = ".pyd"
+          VERSION = "32"
+          abiflags = ""
+          base = "C:\Python32"
+          exec_prefix = "C:\Python32"
+          platbase = "C:\Python32"
+          prefix = "C:\Python32"
+          projectbase = "C:\Python32"
+          py_version = "3.2"
+          py_version_nodot = "32"
+          py_version_short = "3.2"
+          srcdir = "C:\Python32"
+          userbase = "C:\Documents and Settings\Raymond\Application Data\Python"
+
+pdb
+---
+
+The :mod:`pdb` debugger module gained a number of usability improvements:
+
+* :file:`pdb.py` now has a ``-c`` option that executes commands as given in a
+  :file:`.pdbrc` script file.
+* A :file:`.pdbrc` script file can contain ``continue`` and ``next`` commands
+  that continue debugging.
+* The :class:`Pdb` class constructor now accepts a *nosigint* argument.
+* new commands: ``l(list)``, ``ll(long list`` and ``source`` for
+  listing source code.
+* new commands: ``display`` and ``undisplay`` for showing or hiding
+  the value of an expression if it has changed.
+* new command: ``interact`` for starting an interactive interpreter containing
+  the global and local  names found in the current scope.
+* breakpoints can be cleared by breakpoint number
+
+(Contributed by Georg Brandl, Antonio Cuni and Ilya Sandler.)
+
+configparser
+------------
+
+The :mod:`configparser` module was modified to improve usability and
+predictability of the default parser and its supported INI syntax.  The old
+:class:`ConfigParser` class was removed in favor of :class:`SafeConfigParser`
+which has in turn been renamed to :class:`~configparser.ConfigParser`. Support
+for inline comments is now turned off by default and section or option
+duplicates are not allowed in a single configuration source.
+
+Config parsers gained a new API based on the mapping protocol::
+
+  >>> parser = ConfigParser()
+  >>> parser.read_string("""
+  ... [DEFAULT]
+  ... monty = python
+  ...
+  ... [phrases]
+  ... the = who
+  ... full = metal jacket
+  ... """)
+  >>> parser['phrases']['full']
+  'metal jacket'
+  >>> section = parser['phrases']
+  >>> section['the']
+  'who'
+  >>> section['british'] = '%(the)s %(full)s %(monty)s!'
+  >>> parser['phrases']['british']
+  'who metal jacket python!'
+  >>> 'british' in section
+  True
+
+The new API is implemented on top of the classical API so custom parser
+subclasses should be able to use it without modifications.
+
+The INI file structure accepted by config parsers can now be customized. Users
+can specify alternative option/value delimiters and comment prefixes, change the
+name of the *DEFAULT* section or switch the interpolation syntax.  Along with
+support for pluggable interpolation, an additional interpolation handler
+:class:`~configparser.ExtendedInterpolation` was introduced::
+
+  >>> parser = ConfigParser(interpolation=ExtendedInterpolation())
+  >>> parser.read_dict({'buildout': {'directory': '/home/ambv/zope9'},
+  ...                   'custom': {'prefix': '/usr/local'}})
+  >>> parser.read_string("""
+  ... [buildout]
+  ... parts =
+  ...   zope9
+  ...   instance
+  ... find-links =
+  ...   ${buildout:directory}/downloads/dist
+  ...
+  ... [zope9]
+  ... recipe = plone.recipe.zope9install
+  ... location = /opt/zope
+  ...
+  ... [instance]
+  ... recipe = plone.recipe.zope9instance
+  ... zope9-location = ${zope9:location}
+  ... zope-conf = ${custom:prefix}/etc/zope.conf
+  ... """)
+  >>> parser['buildout']['find-links']
+  '\n/home/ambv/zope9/downloads/dist'
+  >>> parser['instance']['zope-conf']
+  '/usr/local/etc/zope.conf'
+  >>> instance = parser['instance']
+  >>> instance['zope-conf']
+  '/usr/local/etc/zope.conf'
+  >>> instance['zope9-location']
+  '/opt/zope'
+
+A number of smaller features were also introduced, like support for specifying
+encoding in read operations, specifying fallback values for get-functions, or
+reading directly from dictionaries and strings.
+
+(All changes contributed by ??ukasz Langa.)
+
+.. XXX: Mention urllib.parse changes
+          Issue 9873 (Nick Coghlan):
+            - ASCII byte sequence support in URL parsing
+            - named tuple for urldefrag return value
+          Issue 5468 (Dan Mahn) for urlencode:
+            - bytes input support
+            - non-UTF8 percent encoding of non-ASCII characters
+          Issue 2987 for IPv6 (RFC2732) support in urlparse
+.. XXX: Any updates to the WSGI bytes versus text problem?
 
 Multi-threading
 ===============
@@ -582,34 +1384,24 @@
 
   (Contributed by Antoine Pitrou.)
 
-* Recursive locks (created with the :func:`threading.RLock` API) now benefit
-  from a C implementation which makes them as fast as regular locks, and between
-  10x and 15x faster than their previous pure Python implementation.
-
-  (Contributed by Antoine Pitrou; :issue:`3001`.)
-
 * Regular and recursive locks now accept an optional *timeout* argument to their
   :meth:`acquire` method.  (Contributed by Antoine Pitrou; :issue:`7316`.)
 
-  Similarly, :meth:`threading.Semaphore.acquire` also gains a *timeout*
+* Similarly, :meth:`threading.Semaphore.acquire` also gained a *timeout*
   argument.  (Contributed by Torsten Landschoff; :issue:`850728`.)
 
+* Regular and recursive lock acquisitions can now be interrupted by signals on
+  platforms using pthreads.  This means that Python programs that deadlock while
+  acquiring locks can be successfully killed by repeatedly sending SIGINT to the
+  process (by pressing :kbd:`Ctrl+C` in most shells).
+  (Contributed by Reid Kleckner; :issue:`8844`.)
+
 
 Optimizations
 =============
 
 A number of small performance enhancements have been added:
 
-* JSON decoding performance is improved and memory consumption is reduced
-  whenever the same string is repeated for multiple keys.
-
-  (Contributed by Antoine Pitrou; :issue:`7451`.)
-
-* JSON encoding now uses the C speedups also when the ``sort_keys`` argument
-  is true.
-
-  (Contributed by Raymond Hettinger and Antoine Pitrou, :issue:`10314`.)
-
 * Python's peephole optimizer now recognizes patterns such ``x in {1, 2, 3}`` as
   being a test for membership in a set of constants.  The optimizer recasts the
   :class:`set` as a :class:`frozenset` and stores the pre-built constant.
@@ -624,6 +1416,36 @@
 
   (Patch and additional tests by Dave Malcolm; :issue:`6690`).
 
+* Serializing and unserializing data using the :mod:`pickle` module is now
+  several times faster.
+
+  (Contributed by Alexandre Vassalotti, Antoine Pitrou
+  and the Unladen Swallow team in :issue:`9410` and :issue:`3873`.)
+
+* The `Timsort algorithm `_ used in
+  :meth:`list.sort` and :func:`sorted` now runs faster and uses less memory
+  when called with a :term:`key function`.  Previously, every element of
+  a list was wrapped with a temporary object that remembered the key value
+  associated with each element.  Now, an array of keys and values are
+  sorted in parallel.  This save the memory consumed by the sort wrappers,
+  and it saves time lost during comparisons which were delegated by the
+  sort wrappers.
+
+  (Patch by Daniel Stuzback in :issue:`9915`.)
+
+* JSON decoding performance is improved and memory consumption is reduced
+  whenever the same string is repeated for multiple keys.  Also, JSON encoding
+  now uses the C speedups when the ``sort_keys`` argument is true.
+
+  (Contributed by Antoine Pitrou in :issue:`7451` and by Raymond Hettinger and
+  Antoine Pitrou in :issue:`10314`.)
+
+* Recursive locks (created with the :func:`threading.RLock` API) now benefit
+  from a C implementation which makes them as fast as regular locks, and between
+  10x and 15x faster than their previous pure Python implementation.
+
+  (Contributed by Antoine Pitrou; :issue:`3001`.)
+
 * The fast-search algorithm in stringlib is now used by the :meth:`split`,
   :meth:`rsplit`, :meth:`splitlines` and :meth:`replace` methods on
   :class:`bytes`, :class:`bytearray` and :class:`str` objects. Likewise, the
@@ -632,20 +1454,52 @@
 
   (Patch by Florent Xicluna in :issue:`7622` and :issue:`7462`.)
 
-* Serializing and unserializing data using the :mod:`pickle` module is now
-  several times faster. (Contributed by Alexandre Vassalotti, Antoine Pitrou
-  and the Unladen Swallow team in :issue:`9410` and :issue:`3873`.)
+
+* String to integer conversions now work two "digits" at a time, reducing the
+  number of division and modulo operations.
+
+  (:issue:`6713` by Gawain Bolton, Mark Dickinson, and Victor Stinner.)
+
+There were several other minor optimizations. Set differencing now runs faster
+when one operand is much larger than the other (Patch by Andress Bennetts in
+:issue:`8685`).  The :meth:`array.repeat` method has a faster implementation
+(:issue:`1569291` by Alexander Belopolsky). The :class:`BaseHTTPRequestHandler`
+has more efficient buffering (:issue:`3709` by Andrew Schaaf).  The
+multi-argument form of :func:`operator.attrgetter` now function runs slightly
+faster (:issue:`10160` by Christos Georgiou).  And :class:`ConfigParser` loads
+multi-line arguments a bit faster (:issue:`7113` by ??ukasz Langa).
 
 
 Unicode
 =======
 
+Python has been updated to Unicode 6.0.0.  The new features of the
+Unicode Standard that will affect Python users include:
+
+* addition of 2,088 characters, including over 1,000 additional
+  symbols???chief among them the additional emoji symbols, which are
+  especially important for mobile phones;
+
+* changes to character properties for existing characters including
+
+  - a general category change to two Kannada characters (U+0CF1,
+    U+0CF2), which has the effect of making them newly eligible for
+    inclusion in identifiers;
+
+  - a general category change to one New Tai Lue numeric character
+    (U+19DA), which has the effect of disqualifying it from
+    inclusion in identifiers.
+
+  For more information, see `Unicode Character Database Changes
+  `_
+  at the `Unicode Consortium `_ web site.
+
 The :mod:`os` module has two new functions: :func:`~os.fsencode` and
 :func:`~os.fsdecode`. Add :data:`os.environb`: bytes version of
 :data:`os.environ`, :func:`os.getenvb` function and
 :data:`os.supports_bytes_environ` constant.
 
-``'mbcs'`` encoding doesn't ignore the error handler argument anymore. By
+``'mbcs'`` encoding doesn't ignore the error handler argument any more. By
 default (strict mode), it raises an UnicodeDecodeError on undecodable byte
 sequence and UnicodeEncodeError on unencodable character. To get the ``'mbcs'``
 encoding of Python 3.1, use ``'ignore'`` error handler to decode and
@@ -661,11 +1515,38 @@
 ``'mbcs'``), and the ``'surrogateescape'`` error handler on all operating
 systems.
 
+* Added the *cp720* Arabic DOS encoding (:issue:`1616979`).
+
+
+Documentation
+=============
+
+The documentation continues to be improved.
+
+A table of quick links has been added to the top of lengthy sections such as
+:ref:`built-in-funcs`.  In the case of :mod:`itertools`, the links are
+accompanied by tables of cheatsheet-style summaries to provide an overview and
+memory jog without having to read all of the docs.
+
+In some cases, the pure python source code can be helpful adjunct to the docs,
+so now some modules feature quick links to the latest version of the source
+code.  For example, the :mod:`functools` module documentation has a quick link
+at the top labeled :source:`functools Python source code `.
 
-.. IDLE
-   ====
+The docs now contain more examples and recipes.  In particular, :mod:`re` module
+has an extensive section, :ref:`re-examples`.  Likewise, the :mod:`itertools`
+module continues to be updated with new :ref:`itertools-recipes`.
 
-   * Stub
+The :mod:`datetime` module now has an auxiliary implementation in pure Python.
+No functionality was changed.  This just provides an easier-to-read
+alternate implementation.  (Contributed by Alexander Belopolsky.)
+
+
+IDLE
+====
+
+* The format menu now has an option to clean-up source files by stripping
+  trailing whitespace (:issue:`5150`).
 
 
 Build and C API Changes
@@ -693,11 +1574,51 @@
 
   (Contributed by Amaury Forgeot D'Arc; :issue:`9210`.)
 
-* Hash values are now values of a new type, Py_hash_t, which is defined to
-  be the same size as a pointer.  Previously they were of type long, which
-  on some 64-bit operating systems is still only 32 bits long.
+* Hash values are now values of a new type, :c:type:`Py_hash_t`, which is
+  defined to be the same size as a pointer.  Previously they were of type long,
+  which on some 64-bit operating systems is still only 32 bits long.  As a
+  result of this fix, :class:`set` and :class:`dict` can now hold more than
+  ``2**32`` entries on builds with 64-bit pointers (previously, they could grow
+  to that size but their performance degraded catastrophically).
+
+  (Suggested by Raymond Hettinger and implemented by Benjamin Peterson;
+  :issue:`9778`.)
+
+* A new macro :c:macro:`Py_VA_COPY` copies the state of the variable argument
+  list.  It is equivalent to C99 *va_copy* but available on all python platforms
+  (:issue:`2443`).
+
+* A new C API function :c:func:`PySys_SetArgvEx` allows an embedded
+  interpreter to set sys.argv without also modifying :attr:`sys.path`
+  (:issue:`5753`).
+
+* :c:macro:`PyEval_CallObject` is now only available in macro form.  The
+  function declaration, which was kept for backwards compatibility reasons, is
+  now removed -- the macro was introduced in 1997  (:issue:`8276`).
+
+* The is a new function :c:func:`PyLong_AsLongLongAndOverflow` which
+  is analogous to :c:func:`PyLong_AsLongAndOverflow`.  The both serve to
+  convert Python :class:`int` into a native fixed-width type while providing
+  detection of cases where the conversion won't fit (:issue:`7767`).
+
+* The :c:func:`PyUnicode_CompareWithASCIIString` now returns *not equal*
+  if the Python string in *NUL* terminated.
+
+* There is a new function :c:func:`PyErr_NewExceptionWithDoc` that is
+  like :c:func:`PyErr_NewException` but allows a docstring to be specified.
+  This lets C exceptions have the same self-documenting capabilities as
+  their pure Python counterparts (:issue:`7033`).
+
+* When compiled with the ``--with-valgrind`` option, the pymalloc
+  allocator will be automatically disabled when running under Valgrind.  This
+  gives improved memory leak detection when running under Valgrind, while taking
+  advantage of pymalloc at other times (:issue:`2422`).
+
+* Removed the "O?" format from the *PyArg_Parse* functions.  The format is no
+  longer used and it had never been documented (:issue:`8837`).
 
-  (Contributed by Benjamin Peterson; :issue:`9778`.)
+There were a number of other small changes to the C-API.  See the
+:file:`Misc/NEWS` file for a complete list.
 
 
 Porting to Python 3.2
@@ -706,11 +1627,42 @@
 This section lists previously described changes and other bugfixes that may
 require changes to your code:
 
+* The :mod:`configparser` module has a number of clean-ups.  The major change is
+  to replace the old :class:`ConfigParser` class with long-standing preferred
+  alternative :class:`SafeConfigParser`.  In addition there are a number of
+  smaller incompatibilites:
+
+  * The interpolation syntax is now validated on
+    :meth:`~configparser.ConfigParser.get` and
+    :meth:`~configparser.ConfigParser.set` operations. In the default
+    interpolation scheme, only two tokens with percent signs are valid: ``%(name)s``
+    and ``%%``, the latter being an escaped percent sign.
+
+  * The :meth:`~configparser.ConfigParser.set` and
+    :meth:`~configparser.ConfigParser.add_section` methods now verify that
+    values are actual strings.  Formerly, unsupported types could be introduced
+    unintentionally.
+
+  * Duplicate sections or options from a single source now raise either
+    :exc:`~configparser.DuplicateSectionError` or
+    :exc:`~configparser.DuplicateOptionError`.  Formerly, duplicates would
+    silently overwrite a previous entry.
+
+  * Inline comments are now disabled by default so now the **;** character
+    can be safely used in values.
+
+  * Comments now can be indented.  Consequently, for **;** or **#** to appear at
+    the start of a line in multiline values, it has to be interpolated.  This
+    keeps comment prefix characters in values from being mistaken as comments.
+
+  * ``""`` is now a valid value and is no longer automatically converted to an
+    empty string. For empty strings, use ``"option ="`` in a line.
+
 * The :mod:`nntplib` module was reworked extensively, meaning that its APIs
   are often incompatible with the 3.1 APIs.
 
-* :class:`bytearray` objects cannot be used anymore as filenames: convert them
-  to :class:`bytes`.
+* :class:`bytearray` objects can no longer be used as filenames; instead,
+  they should be converted to :class:`bytes`.
 
 * PyArg_Parse*() functions:
 
@@ -722,4 +1674,38 @@
   instead; the new type has a well-defined interface for passing typing safety
   information and a less complicated signature for calling a destructor.
 
- * Remove sys.setfilesystemencoding() function: it was broken by design.
+* The :func:`sys.setfilesystemencoding` function was removed because
+  it had a flawed design.
+
+* The :func:`random.seed` function and method now salt string seeds with an
+  sha512 hash function.  To access the previous version of *seed* in order to
+  reproduce Python 3.1 sequences, set the *version* argument to *1*,
+  ``random.seed(s, version=1)``.
+
+* The previously deprecated :func:`string.maketrans` function has been removed
+  in favor of the static methods, :meth:`bytes.maketrans` and
+  :meth:`bytearray.maketrans`.  This change solves the confusion around which
+  types were supported by the :mod:`string` module.  Now, :class:`str`,
+  :class:`bytes`, and :class:`bytearray` each have their own **maketrans** and
+  **translate** methods with intermediate translation tables of the appropriate
+  type.
+
+  (Contributed by Georg Brandl; :issue:`5675`.)
+
+* The previously deprecated :func:`contextlib.nested` function has been removed
+  in favor of a plain :keyword:`with` statement which can accept multiple
+  context managers.  The latter technique is faster (because it is built-in),
+  and it does a better job finalizing multiple context managers when one of them
+  raises an exception::
+
+    >>> with open('mylog.txt') as infile, open('a.out', 'w') as outfile:
+    ...     for line in infile:
+    ...         if '' in line:
+    ...             outfile.write(line)
+
+  (Contributed by Georg Brandl and Mattias Br??ndstr??m;
+  `appspot issue 53094 `_.)
+
+* :func:`struct.pack` no longer implicitly encodes unicode to UTF-8: use
+  explicit conversion instead and replace unicode literals by bytes literals.
+

Modified: python/branches/py3k-cdecimal/Include/Python.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/Python.h	(original)
+++ python/branches/py3k-cdecimal/Include/Python.h	Sun Jan  2 13:18:37 2011
@@ -66,6 +66,7 @@
 
 #include "object.h"
 #include "objimpl.h"
+#include "typeslots.h"
 
 #include "pydebug.h"
 
@@ -98,6 +99,8 @@
 #include "descrobject.h"
 #include "warnings.h"
 #include "weakrefobject.h"
+#include "structseq.h"
+
 
 #include "codecs.h"
 #include "pyerrors.h"
@@ -129,7 +132,9 @@
 #endif
 
 /* _Py_Mangle is defined in compile.c */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) _Py_Mangle(PyObject *p, PyObject *name);
+#endif
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/abstract.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/abstract.h	(original)
+++ python/branches/py3k-cdecimal/Include/abstract.h	Sun Jan  2 13:18:37 2011
@@ -387,7 +387,9 @@
      PyAPI_FUNC(Py_ssize_t) PyObject_Length(PyObject *o);
 #define PyObject_Length PyObject_Size
 
+#ifndef Py_LIMITED_API
      PyAPI_FUNC(Py_ssize_t) _PyObject_LengthHint(PyObject *o, Py_ssize_t);
+#endif
 
        /*
      Guess the size of object o using len(o) or o.__length_hint__().
@@ -765,9 +767,11 @@
      that can accept a char* naming integral's type.
        */
 
+#ifndef Py_LIMITED_API
      PyAPI_FUNC(PyObject *) _PyNumber_ConvertIntegralToInt(
          PyObject *integral,
          const char* error_format);
+#endif
 
        /*
     Returns the object converted to Py_ssize_t by going through
@@ -1057,11 +1061,13 @@
      Use __contains__ if possible, else _PySequence_IterSearch().
        */
 
+#ifndef Py_LIMITED_API
 #define PY_ITERSEARCH_COUNT    1
 #define PY_ITERSEARCH_INDEX    2
 #define PY_ITERSEARCH_CONTAINS 3
      PyAPI_FUNC(Py_ssize_t) _PySequence_IterSearch(PyObject *seq,
                                         PyObject *obj, int operation);
+#endif
     /*
       Iterate over seq.  Result depends on the operation:
       PY_ITERSEARCH_COUNT:  return # of times obj appears in seq; -1 if
@@ -1228,6 +1234,7 @@
       /* issubclass(object, typeorclass) */
 
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PyObject_RealIsInstance(PyObject *inst, PyObject *cls);
 
 PyAPI_FUNC(int) _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls);
@@ -1235,6 +1242,7 @@
 PyAPI_FUNC(char *const *) _PySequence_BytesToCharpArray(PyObject* self);
 
 PyAPI_FUNC(void) _Py_FreeCharPArray(char *const array[]);
+#endif
 
 /* For internal use by buffer API functions */
 PyAPI_FUNC(void) _Py_add_one_to_index_F(int nd, Py_ssize_t *index,

Modified: python/branches/py3k-cdecimal/Include/ast.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/ast.h	(original)
+++ python/branches/py3k-cdecimal/Include/ast.h	Sun Jan  2 13:18:37 2011
@@ -4,8 +4,11 @@
 extern "C" {
 #endif
 
-PyAPI_FUNC(mod_ty) PyAST_FromNode(const node *, PyCompilerFlags *flags,
-				  const char *, PyArena *);
+PyAPI_FUNC(mod_ty) PyAST_FromNode(
+    const node *n,
+    PyCompilerFlags *flags,
+    const char *filename,       /* decoded from the filesystem encoding */
+    PyArena *arena);
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/bytearrayobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/bytearrayobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/bytearrayobject.h	Sun Jan  2 13:18:37 2011
@@ -19,6 +19,7 @@
  */
 
 /* Object layout */
+#ifndef Py_LIMITED_API
 typedef struct {
     PyObject_VAR_HEAD
     /* XXX(nnorwitz): should ob_exports be Py_ssize_t? */
@@ -26,6 +27,7 @@
     Py_ssize_t ob_alloc; /* How many bytes allocated */
     char *ob_bytes;
 } PyByteArrayObject;
+#endif
 
 /* Type object */
 PyAPI_DATA(PyTypeObject) PyByteArray_Type;
@@ -44,12 +46,14 @@
 PyAPI_FUNC(int) PyByteArray_Resize(PyObject *, Py_ssize_t);
 
 /* Macros, trading safety for speed */
+#ifndef Py_LIMITED_API
 #define PyByteArray_AS_STRING(self) \
     (assert(PyByteArray_Check(self)), \
      Py_SIZE(self) ? ((PyByteArrayObject *)(self))->ob_bytes : _PyByteArray_empty_string)
 #define PyByteArray_GET_SIZE(self)  (assert(PyByteArray_Check(self)),Py_SIZE(self))
 
 PyAPI_DATA(char) _PyByteArray_empty_string[];
+#endif
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/bytes_methods.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/bytes_methods.h	(original)
+++ python/branches/py3k-cdecimal/Include/bytes_methods.h	Sun Jan  2 13:18:37 2011
@@ -1,3 +1,4 @@
+#ifndef Py_LIMITED_API
 #ifndef Py_BYTES_CTYPE_H
 #define Py_BYTES_CTYPE_H
 
@@ -42,3 +43,4 @@
 #define PyDoc_STRVAR_shared(name,str) const char name[] = PyDoc_STR(str)
 
 #endif /* !Py_BYTES_CTYPE_H */
+#endif /* !Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/bytesobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/bytesobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/bytesobject.h	Sun Jan  2 13:18:37 2011
@@ -27,6 +27,7 @@
 /* Caching the hash (ob_shash) saves recalculation of a string's hash value.
    This significantly speeds up dict lookups. */
 
+#ifndef Py_LIMITED_API
 typedef struct {
     PyObject_VAR_HEAD
     Py_hash_t ob_shash;
@@ -38,6 +39,7 @@
      *     ob_shash is the hash of the string or -1 if not computed yet.
      */
 } PyBytesObject;
+#endif
 
 PyAPI_DATA(PyTypeObject) PyBytes_Type;
 PyAPI_DATA(PyTypeObject) PyBytesIter_Type;
@@ -58,21 +60,27 @@
 PyAPI_FUNC(PyObject *) PyBytes_Repr(PyObject *, int);
 PyAPI_FUNC(void) PyBytes_Concat(PyObject **, PyObject *);
 PyAPI_FUNC(void) PyBytes_ConcatAndDel(PyObject **, PyObject *);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PyBytes_Resize(PyObject **, Py_ssize_t);
 PyAPI_FUNC(PyObject *) _PyBytes_FormatLong(PyObject*, int, int,
 						  int, char**, int*);
+#endif
 PyAPI_FUNC(PyObject *) PyBytes_DecodeEscape(const char *, Py_ssize_t,
 						   const char *, Py_ssize_t,
 						   const char *);
 
 /* Macro, trading safety for speed */
+#ifndef Py_LIMITED_API
 #define PyBytes_AS_STRING(op) (assert(PyBytes_Check(op)), \
                                 (((PyBytesObject *)(op))->ob_sval))
 #define PyBytes_GET_SIZE(op)  (assert(PyBytes_Check(op)),Py_SIZE(op))
+#endif
 
 /* _PyBytes_Join(sep, x) is like sep.join(x).  sep must be PyBytesObject*,
    x must be an iterable object. */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PyBytes_Join(PyObject *sep, PyObject *x);
+#endif
 
 /* Provides access to the internal data buffer and size of a string
    object or the default encoded version of an Unicode object. Passing
@@ -90,7 +98,7 @@
 /* Using the current locale, insert the thousands grouping
    into the string pointed to by buffer.  For the argument descriptions,
    see Objects/stringlib/localeutil.h */
-
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(Py_ssize_t) _PyBytes_InsertThousandsGroupingLocale(char *buffer,
                                                    Py_ssize_t n_buffer,
                                                    char *digits,
@@ -107,6 +115,7 @@
                                                    Py_ssize_t min_width,
                                                    const char *grouping,
                                                    const char *thousands_sep);
+#endif
 
 /* Flags used by string formatting */
 #define F_LJUST (1<<0)

Modified: python/branches/py3k-cdecimal/Include/cellobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/cellobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/cellobject.h	Sun Jan  2 13:18:37 2011
@@ -1,5 +1,5 @@
 /* Cell object interface */
-
+#ifndef Py_LIMITED_API
 #ifndef Py_CELLOBJECT_H
 #define Py_CELLOBJECT_H
 #ifdef __cplusplus
@@ -26,3 +26,4 @@
 }
 #endif
 #endif /* !Py_TUPLEOBJECT_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/ceval.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/ceval.h	(original)
+++ python/branches/py3k-cdecimal/Include/ceval.h	Sun Jan  2 13:18:37 2011
@@ -20,8 +20,10 @@
                                          const char *methodname,
                                          const char *format, ...);
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(void) PyEval_SetProfile(Py_tracefunc, PyObject *);
 PyAPI_FUNC(void) PyEval_SetTrace(Py_tracefunc, PyObject *);
+#endif
 
 struct _frame; /* Avoid including frameobject.h */
 
@@ -33,7 +35,9 @@
 /* Look at the current frame's (if any) code's co_flags, and turn on
    the corresponding compiler flags in cf->cf_flags.  Return 1 if any
    flag was set, else return 0. */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) PyEval_MergeCompilerFlags(PyCompilerFlags *cf);
+#endif
 
 PyAPI_FUNC(int) Py_AddPendingCall(int (*func)(void *), void *arg);
 PyAPI_FUNC(int) Py_MakePendingCalls(void);
@@ -167,8 +171,10 @@
 PyAPI_FUNC(void) PyEval_ReleaseThread(PyThreadState *tstate);
 PyAPI_FUNC(void) PyEval_ReInitThreads(void);
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(void) _PyEval_SetSwitchInterval(unsigned long microseconds);
 PyAPI_FUNC(unsigned long) _PyEval_GetSwitchInterval(void);
+#endif
 
 #define Py_BEGIN_ALLOW_THREADS { \
                         PyThreadState *_save; \
@@ -187,8 +193,10 @@
 
 #endif /* !WITH_THREAD */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PyEval_SliceIndex(PyObject *, Py_ssize_t *);
 PyAPI_FUNC(void) _PyEval_SignalAsyncExc(void);
+#endif
 
 
 #ifdef __cplusplus

Modified: python/branches/py3k-cdecimal/Include/classobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/classobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/classobject.h	Sun Jan  2 13:18:37 2011
@@ -2,6 +2,7 @@
 
 /* Revealing some structures (not for general use) */
 
+#ifndef Py_LIMITED_API
 #ifndef Py_CLASSOBJECT_H
 #define Py_CLASSOBJECT_H
 #ifdef __cplusplus
@@ -54,3 +55,4 @@
 }
 #endif
 #endif /* !Py_CLASSOBJECT_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/code.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/code.h	(original)
+++ python/branches/py3k-cdecimal/Include/code.h	Sun Jan  2 13:18:37 2011
@@ -1,5 +1,6 @@
 /* Definitions for bytecode */
 
+#ifndef Py_LIMITED_API
 #ifndef Py_CODE_H
 #define Py_CODE_H
 #ifdef __cplusplus
@@ -93,8 +94,10 @@
 /* Update *bounds to describe the first and one-past-the-last instructions in the
    same line as lasti.  Return the number of that line.
 */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PyCode_CheckLineNumber(PyCodeObject* co,
                                         int lasti, PyAddrPair *bounds);
+#endif
 
 PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts,
                                       PyObject *names, PyObject *lineno_obj);
@@ -103,3 +106,4 @@
 }
 #endif
 #endif /* !Py_CODE_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/codecs.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/codecs.h	(original)
+++ python/branches/py3k-cdecimal/Include/codecs.h	Sun Jan  2 13:18:37 2011
@@ -45,9 +45,11 @@
 
  */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PyCodec_Lookup(
        const char *encoding
        );
+#endif
 
 /* Codec registry encoding check API.
 

Modified: python/branches/py3k-cdecimal/Include/compile.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/compile.h	(original)
+++ python/branches/py3k-cdecimal/Include/compile.h	Sun Jan  2 13:18:37 2011
@@ -1,4 +1,4 @@
-
+#ifndef Py_LIMITED_API
 #ifndef Py_COMPILE_H
 #define Py_COMPILE_H
 
@@ -29,8 +29,13 @@
 #define FUTURE_BARRY_AS_BDFL "barry_as_FLUFL"
 
 struct _mod; /* Declare the existence of this type */
-PyAPI_FUNC(PyCodeObject *) PyAST_Compile(struct _mod *, const char *,
-					PyCompilerFlags *, PyArena *);
+#define PyAST_Compile(mod, s, f, ar) PyAST_CompileEx(mod, s, f, -1, ar)
+PyAPI_FUNC(PyCodeObject *) PyAST_CompileEx(
+    struct _mod *mod,
+    const char *filename,       /* decoded from the filesystem encoding */
+    PyCompilerFlags *flags,
+    int optimize,
+    PyArena *arena);
 PyAPI_FUNC(PyFutureFeatures *) PyFuture_FromAST(struct _mod *, const char *);
 
 
@@ -38,3 +43,4 @@
 }
 #endif
 #endif /* !Py_COMPILE_H */
+#endif /* !Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/complexobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/complexobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/complexobject.h	Sun Jan  2 13:18:37 2011
@@ -6,6 +6,7 @@
 extern "C" {
 #endif
 
+#ifndef Py_LIMITED_API
 typedef struct {
     double real;
     double imag;
@@ -28,7 +29,7 @@
 PyAPI_FUNC(Py_complex) c_quot(Py_complex, Py_complex);
 PyAPI_FUNC(Py_complex) c_pow(Py_complex, Py_complex);
 PyAPI_FUNC(double) c_abs(Py_complex);
-
+#endif
 
 /* Complex object interface */
 
@@ -36,29 +37,36 @@
 PyComplexObject represents a complex number with double-precision
 real and imaginary parts.
 */
-
+#ifndef Py_LIMITED_API
 typedef struct {
     PyObject_HEAD
     Py_complex cval;
-} PyComplexObject;     
+} PyComplexObject;
+#endif
 
 PyAPI_DATA(PyTypeObject) PyComplex_Type;
 
 #define PyComplex_Check(op) PyObject_TypeCheck(op, &PyComplex_Type)
 #define PyComplex_CheckExact(op) (Py_TYPE(op) == &PyComplex_Type)
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) PyComplex_FromCComplex(Py_complex);
+#endif
 PyAPI_FUNC(PyObject *) PyComplex_FromDoubles(double real, double imag);
 
 PyAPI_FUNC(double) PyComplex_RealAsDouble(PyObject *op);
 PyAPI_FUNC(double) PyComplex_ImagAsDouble(PyObject *op);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(Py_complex) PyComplex_AsCComplex(PyObject *op);
+#endif
 
 /* Format the object based on the format_spec, as defined in PEP 3101
    (Advanced String Formatting). */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PyComplex_FormatAdvanced(PyObject *obj,
                                                  Py_UNICODE *format_spec,
                                                  Py_ssize_t format_spec_len);
+#endif
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/datetime.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/datetime.h	(original)
+++ python/branches/py3k-cdecimal/Include/datetime.h	Sun Jan  2 13:18:37 2011
@@ -1,6 +1,6 @@
 /*  datetime.h
  */
-
+#ifndef Py_LIMITED_API
 #ifndef DATETIME_H
 #define DATETIME_H
 #ifdef __cplusplus
@@ -234,3 +234,4 @@
 }
 #endif
 #endif
+#endif /* !Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/descrobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/descrobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/descrobject.h	Sun Jan  2 13:18:37 2011
@@ -16,6 +16,7 @@
     void *closure;
 } PyGetSetDef;
 
+#ifndef Py_LIMITED_API
 typedef PyObject *(*wrapperfunc)(PyObject *self, PyObject *args,
                                  void *wrapped);
 
@@ -68,6 +69,7 @@
     struct wrapperbase *d_base;
     void *d_wrapped; /* This can be any function pointer */
 } PyWrapperDescrObject;
+#endif /* Py_LIMITED_API */
 
 PyAPI_DATA(PyTypeObject) PyClassMethodDescr_Type;
 PyAPI_DATA(PyTypeObject) PyGetSetDescr_Type;
@@ -78,13 +80,16 @@
 
 PyAPI_FUNC(PyObject *) PyDescr_NewMethod(PyTypeObject *, PyMethodDef *);
 PyAPI_FUNC(PyObject *) PyDescr_NewClassMethod(PyTypeObject *, PyMethodDef *);
+struct PyMemberDef; /* forward declaration for following prototype */
 PyAPI_FUNC(PyObject *) PyDescr_NewMember(PyTypeObject *,
                                                struct PyMemberDef *);
 PyAPI_FUNC(PyObject *) PyDescr_NewGetSet(PyTypeObject *,
                                                struct PyGetSetDef *);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) PyDescr_NewWrapper(PyTypeObject *,
                                                 struct wrapperbase *, void *);
 #define PyDescr_IsData(d) (Py_TYPE(d)->tp_descr_set != NULL)
+#endif
 
 PyAPI_FUNC(PyObject *) PyDictProxy_New(PyObject *);
 PyAPI_FUNC(PyObject *) PyWrapper_New(PyObject *, PyObject *);

Modified: python/branches/py3k-cdecimal/Include/dictobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/dictobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/dictobject.h	Sun Jan  2 13:18:37 2011
@@ -45,6 +45,7 @@
  * majority of dicts (consisting mostly of usually-small instance dicts and
  * usually-small dicts created to pass keyword arguments).
  */
+#ifndef Py_LIMITED_API
 #define PyDict_MINSIZE 8
 
 typedef struct {
@@ -84,6 +85,7 @@
     PyDictEntry *(*ma_lookup)(PyDictObject *mp, PyObject *key, Py_hash_t hash);
     PyDictEntry ma_smalltable[PyDict_MINSIZE];
 };
+#endif /* Py_LIMITED_API */
 
 PyAPI_DATA(PyTypeObject) PyDict_Type;
 PyAPI_DATA(PyTypeObject) PyDictIterKey_Type;
@@ -112,18 +114,22 @@
 PyAPI_FUNC(void) PyDict_Clear(PyObject *mp);
 PyAPI_FUNC(int) PyDict_Next(
     PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PyDict_Next(
     PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value, Py_hash_t *hash);
+#endif
 PyAPI_FUNC(PyObject *) PyDict_Keys(PyObject *mp);
 PyAPI_FUNC(PyObject *) PyDict_Values(PyObject *mp);
 PyAPI_FUNC(PyObject *) PyDict_Items(PyObject *mp);
 PyAPI_FUNC(Py_ssize_t) PyDict_Size(PyObject *mp);
 PyAPI_FUNC(PyObject *) PyDict_Copy(PyObject *mp);
 PyAPI_FUNC(int) PyDict_Contains(PyObject *mp, PyObject *key);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PyDict_Contains(PyObject *mp, PyObject *key, Py_hash_t hash);
 PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused);
 PyAPI_FUNC(void) _PyDict_MaybeUntrack(PyObject *mp);
 PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp);
+#endif
 
 /* PyDict_Update(mp, other) is equivalent to PyDict_Merge(mp, other, 1). */
 PyAPI_FUNC(int) PyDict_Update(PyObject *mp, PyObject *other);

Modified: python/branches/py3k-cdecimal/Include/dtoa.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/dtoa.h	(original)
+++ python/branches/py3k-cdecimal/Include/dtoa.h	Sun Jan  2 13:18:37 2011
@@ -1,3 +1,4 @@
+#ifndef Py_LIMITED_API
 #ifndef PY_NO_SHORT_FLOAT_REPR
 #ifdef __cplusplus
 extern "C" {
@@ -13,3 +14,4 @@
 }
 #endif
 #endif
+#endif

Modified: python/branches/py3k-cdecimal/Include/eval.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/eval.h	(original)
+++ python/branches/py3k-cdecimal/Include/eval.h	Sun Jan  2 13:18:37 2011
@@ -7,9 +7,9 @@
 extern "C" {
 #endif
 
-PyAPI_FUNC(PyObject *) PyEval_EvalCode(PyCodeObject *, PyObject *, PyObject *);
+PyAPI_FUNC(PyObject *) PyEval_EvalCode(PyObject *, PyObject *, PyObject *);
 
-PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyCodeObject *co,
+PyAPI_FUNC(PyObject *) PyEval_EvalCodeEx(PyObject *co,
 					PyObject *globals,
 					PyObject *locals,
 					PyObject **args, int argc,
@@ -17,7 +17,9 @@
 					PyObject **defs, int defc,
 					PyObject *kwdefs, PyObject *closure);
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PyEval_CallTracing(PyObject *func, PyObject *args);
+#endif
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/fileobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/fileobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/fileobject.h	Sun Jan  2 13:18:37 2011
@@ -14,7 +14,9 @@
 PyAPI_FUNC(int) PyFile_WriteObject(PyObject *, PyObject *, int);
 PyAPI_FUNC(int) PyFile_WriteString(const char *, PyObject *);
 PyAPI_FUNC(int) PyObject_AsFileDescriptor(PyObject *);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(char *) Py_UniversalNewlineFgets(char *, int, FILE*, PyObject *);
+#endif
 
 /* The default encoding used by the platform file system APIs
    If non-NULL, this is different than the default encoding for strings
@@ -26,6 +28,7 @@
 
    The std printer acts as a preliminary sys.stderr until the new io
    infrastructure is in place. */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) PyFile_NewStdPrinter(int);
 PyAPI_DATA(PyTypeObject) PyStdPrinter_Type;
 
@@ -39,6 +42,7 @@
 #else
 #define _PyVerify_fd(A) (1) /* dummy */
 #endif
+#endif /* Py_LIMITED_API */
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/floatobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/floatobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/floatobject.h	Sun Jan  2 13:18:37 2011
@@ -11,10 +11,12 @@
 extern "C" {
 #endif
 
+#ifndef Py_LIMITED_API
 typedef struct {
     PyObject_HEAD
     double ob_fval;
 } PyFloatObject;
+#endif
 
 PyAPI_DATA(PyTypeObject) PyFloat_Type;
 
@@ -45,8 +47,11 @@
 /* Extract C double from Python float.  The macro version trades safety for
    speed. */
 PyAPI_FUNC(double) PyFloat_AsDouble(PyObject *);
+#ifndef Py_LIMITED_API
 #define PyFloat_AS_DOUBLE(op) (((PyFloatObject *)(op))->ob_fval)
+#endif
 
+#ifndef Py_LIMITED_API
 /* _PyFloat_{Pack,Unpack}{4,8}
  *
  * The struct and pickle (at least) modules need an efficient platform-
@@ -110,6 +115,7 @@
 PyAPI_FUNC(PyObject *) _PyFloat_FormatAdvanced(PyObject *obj,
 					       Py_UNICODE *format_spec,
 					       Py_ssize_t format_spec_len);
+#endif /* Py_LIMITED_API */
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/frameobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/frameobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/frameobject.h	Sun Jan  2 13:18:37 2011
@@ -1,6 +1,7 @@
 
 /* Frame object interface */
 
+#ifndef Py_LIMITED_API
 #ifndef Py_FRAMEOBJECT_H
 #define Py_FRAMEOBJECT_H
 #ifdef __cplusplus
@@ -85,3 +86,4 @@
 }
 #endif
 #endif /* !Py_FRAMEOBJECT_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/funcobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/funcobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/funcobject.h	Sun Jan  2 13:18:37 2011
@@ -1,6 +1,6 @@
 
 /* Function object interface */
-
+#ifndef Py_LIMITED_API
 #ifndef Py_FUNCOBJECT_H
 #define Py_FUNCOBJECT_H
 #ifdef __cplusplus
@@ -84,3 +84,4 @@
 }
 #endif
 #endif /* !Py_FUNCOBJECT_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/genobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/genobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/genobject.h	Sun Jan  2 13:18:37 2011
@@ -1,6 +1,7 @@
 
 /* Generator object interface */
 
+#ifndef Py_LIMITED_API
 #ifndef Py_GENOBJECT_H
 #define Py_GENOBJECT_H
 #ifdef __cplusplus
@@ -38,3 +39,4 @@
 }
 #endif
 #endif /* !Py_GENOBJECT_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/import.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/import.h	(original)
+++ python/branches/py3k-cdecimal/Include/import.h	Sun Jan  2 13:18:37 2011
@@ -30,6 +30,7 @@
 PyAPI_FUNC(void) PyImport_Cleanup(void);
 PyAPI_FUNC(int) PyImport_ImportFrozenModule(char *);
 
+#ifndef Py_LIMITED_API
 #ifdef WITH_THREAD
 PyAPI_FUNC(void) _PyImport_AcquireLock(void);
 PyAPI_FUNC(int) _PyImport_ReleaseLock(void);
@@ -49,13 +50,15 @@
     char *name;
     PyObject* (*initfunc)(void);
 };
+PyAPI_DATA(struct _inittab *) PyImport_Inittab;
+PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab);
+#endif /* Py_LIMITED_API */
 
 PyAPI_DATA(PyTypeObject) PyNullImporter_Type;
-PyAPI_DATA(struct _inittab *) PyImport_Inittab;
 
 PyAPI_FUNC(int) PyImport_AppendInittab(const char *name, PyObject* (*initfunc)(void));
-PyAPI_FUNC(int) PyImport_ExtendInittab(struct _inittab *newtab);
 
+#ifndef Py_LIMITED_API
 struct _frozen {
     char *name;
     unsigned char *code;
@@ -66,6 +69,7 @@
    collection of frozen modules: */
 
 PyAPI_DATA(struct _frozen *) PyImport_FrozenModules;
+#endif
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/listobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/listobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/listobject.h	Sun Jan  2 13:18:37 2011
@@ -19,6 +19,7 @@
 extern "C" {
 #endif
 
+#ifndef Py_LIMITED_API
 typedef struct {
     PyObject_VAR_HEAD
     /* Vector of pointers to list elements.  list[0] is ob_item[0], etc. */
@@ -37,6 +38,7 @@
      */
     Py_ssize_t allocated;
 } PyListObject;
+#endif
 
 PyAPI_DATA(PyTypeObject) PyList_Type;
 PyAPI_DATA(PyTypeObject) PyListIter_Type;
@@ -58,12 +60,16 @@
 PyAPI_FUNC(int) PyList_Sort(PyObject *);
 PyAPI_FUNC(int) PyList_Reverse(PyObject *);
 PyAPI_FUNC(PyObject *) PyList_AsTuple(PyObject *);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PyList_Extend(PyListObject *, PyObject *);
+#endif
 
 /* Macro, trading safety for speed */
+#ifndef Py_LIMITED_API
 #define PyList_GET_ITEM(op, i) (((PyListObject *)(op))->ob_item[i])
 #define PyList_SET_ITEM(op, i, v) (((PyListObject *)(op))->ob_item[i] = (v))
 #define PyList_GET_SIZE(op)    Py_SIZE(op)
+#endif
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/longintrepr.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/longintrepr.h	(original)
+++ python/branches/py3k-cdecimal/Include/longintrepr.h	Sun Jan  2 13:18:37 2011
@@ -1,3 +1,4 @@
+#ifndef Py_LIMITED_API
 #ifndef Py_LONGINTREPR_H
 #define Py_LONGINTREPR_H
 #ifdef __cplusplus
@@ -99,3 +100,4 @@
 }
 #endif
 #endif /* !Py_LONGINTREPR_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/longobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/longobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/longobject.h	Sun Jan  2 13:18:37 2011
@@ -50,7 +50,9 @@
 #endif /* SIZEOF_PID_T */
 
 /* Used by Python/mystrtoul.c. */
+#ifndef Py_LIMITED_API
 PyAPI_DATA(unsigned char) _PyLong_DigitValue[256];
+#endif
 
 /* _PyLong_Frexp returns a double x and an exponent e such that the
    true value is approximately equal to x * 2**e.  e is >= 0.  x is
@@ -58,7 +60,9 @@
    zeroes); otherwise, 0.5 <= abs(x) < 1.0.  On overflow, which is
    possible if the number of bits doesn't fit into a Py_ssize_t, sets
    OverflowError and returns -1.0 for x, 0 for e. */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(double) _PyLong_Frexp(PyLongObject *a, Py_ssize_t *e);
+#endif
 
 PyAPI_FUNC(double) PyLong_AsDouble(PyObject *);
 PyAPI_FUNC(PyObject *) PyLong_FromVoidPtr(void *);
@@ -74,8 +78,11 @@
 #endif /* HAVE_LONG_LONG */
 
 PyAPI_FUNC(PyObject *) PyLong_FromString(char *, char **, int);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) PyLong_FromUnicode(Py_UNICODE*, Py_ssize_t, int);
+#endif
 
+#ifndef Py_LIMITED_API
 /* _PyLong_Sign.  Return 0 if v is 0, -1 if v < 0, +1 if v > 0.
    v must not be NULL, and must be a normalized long.
    There are no error cases.
@@ -150,6 +157,7 @@
 PyAPI_FUNC(PyObject *) _PyLong_FormatAdvanced(PyObject *obj,
 					      Py_UNICODE *format_spec,
 					      Py_ssize_t format_spec_len);
+#endif /* Py_LIMITED_API */
 
 /* These aren't really part of the long object, but they're handy. The
    functions are in Python/mystrtoul.c.

Modified: python/branches/py3k-cdecimal/Include/marshal.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/marshal.h	(original)
+++ python/branches/py3k-cdecimal/Include/marshal.h	Sun Jan  2 13:18:37 2011
@@ -13,10 +13,12 @@
 PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int);
 PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int);
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(long) PyMarshal_ReadLongFromFile(FILE *);
 PyAPI_FUNC(int) PyMarshal_ReadShortFromFile(FILE *);
 PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromFile(FILE *);
 PyAPI_FUNC(PyObject *) PyMarshal_ReadLastObjectFromFile(FILE *);
+#endif
 PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(char *, Py_ssize_t);
 
 #ifdef __cplusplus

Modified: python/branches/py3k-cdecimal/Include/memoryobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/memoryobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/memoryobject.h	Sun Jan  2 13:18:37 2011
@@ -10,10 +10,12 @@
 
 #define PyMemoryView_Check(op) (Py_TYPE(op) == &PyMemoryView_Type)
 
+#ifndef Py_LIMITED_API
 /* Get a pointer to the underlying Py_buffer of a memoryview object. */
 #define PyMemoryView_GET_BUFFER(op) (&((PyMemoryViewObject *)(op))->view)
 /* Get a pointer to the PyObject from which originates a memoryview object. */
 #define PyMemoryView_GET_BASE(op) (((PyMemoryViewObject *)(op))->view.obj)
+#endif
 
 
 PyAPI_FUNC(PyObject *) PyMemoryView_GetContiguous(PyObject *base, 
@@ -61,11 +63,12 @@
 /* The struct is declared here so that macros can work, but it shouldn't
    be considered public. Don't access those fields directly, use the macros
    and functions instead! */
+#ifndef Py_LIMITED_API
 typedef struct {
     PyObject_HEAD
     Py_buffer view;
 } PyMemoryViewObject;
-
+#endif
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/methodobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/methodobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/methodobject.h	Sun Jan  2 13:18:37 2011
@@ -26,12 +26,14 @@
 
 /* Macros for direct access to these values. Type checks are *not*
    done, so use with care. */
+#ifndef Py_LIMITED_API
 #define PyCFunction_GET_FUNCTION(func) \
         (((PyCFunctionObject *)func) -> m_ml -> ml_meth)
 #define PyCFunction_GET_SELF(func) \
 	(((PyCFunctionObject *)func) -> m_self)
 #define PyCFunction_GET_FLAGS(func) \
 	(((PyCFunctionObject *)func) -> m_ml -> ml_flags)
+#endif
 PyAPI_FUNC(PyObject *) PyCFunction_Call(PyObject *, PyObject *, PyObject *);
 
 struct PyMethodDef {
@@ -68,12 +70,14 @@
 
 #define METH_COEXIST   0x0040
 
+#ifndef Py_LIMITED_API
 typedef struct {
     PyObject_HEAD
     PyMethodDef *m_ml; /* Description of the C function to call */
     PyObject    *m_self; /* Passed as 'self' arg to the C func, can be NULL */
     PyObject    *m_module; /* The __module__ attribute, can be anything */
 } PyCFunctionObject;
+#endif
 
 PyAPI_FUNC(int) PyCFunction_ClearFreeList(void);
 

Modified: python/branches/py3k-cdecimal/Include/modsupport.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/modsupport.h	(original)
+++ python/branches/py3k-cdecimal/Include/modsupport.h	Sun Jan  2 13:18:37 2011
@@ -31,7 +31,9 @@
 PyAPI_FUNC(int) PyArg_UnpackTuple(PyObject *, const char *, Py_ssize_t, Py_ssize_t, ...);
 PyAPI_FUNC(PyObject *) Py_BuildValue(const char *, ...);
 PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PyArg_NoKeywords(const char *funcname, PyObject *kw);
+#endif
 
 PyAPI_FUNC(int) PyArg_VaParse(PyObject *, const char *, va_list);
 PyAPI_FUNC(int) PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
@@ -92,6 +94,12 @@
    9-Jan-1995	GvR	Initial version (incompatible with older API)
 */
 
+/* The PYTHON_ABI_VERSION is introduced in PEP 384. For the lifetime of
+   Python 3, it will stay at the value of 3; changes to the limited API
+   must be performed in a strictly backwards-compatible manner. */
+#define PYTHON_ABI_VERSION 3
+#define PYTHON_ABI_STRING "3"
+
 #ifdef Py_TRACE_REFS
  /* When we are tracing reference counts, rename PyModule_Create2 so
     modules compiled with incompatible settings will generate a
@@ -102,10 +110,17 @@
 PyAPI_FUNC(PyObject *) PyModule_Create2(struct PyModuleDef*,
                                      int apiver);
 
+#ifdef Py_LIMITED_API
+#define PyModule_Create(module) \
+	PyModule_Create2(module, PYTHON_ABI_VERSION)
+#else
 #define PyModule_Create(module) \
 	PyModule_Create2(module, PYTHON_API_VERSION)
+#endif
 
+#ifndef Py_LIMITED_API
 PyAPI_DATA(char *) _Py_PackageContext;
+#endif
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/moduleobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/moduleobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/moduleobject.h	Sun Jan  2 13:18:37 2011
@@ -17,7 +17,9 @@
 PyAPI_FUNC(const char *) PyModule_GetName(PyObject *);
 PyAPI_FUNC(const char *) PyModule_GetFilename(PyObject *);
 PyAPI_FUNC(PyObject *) PyModule_GetFilenameObject(PyObject *);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(void) _PyModule_Clear(PyObject *);
+#endif
 PyAPI_FUNC(struct PyModuleDef*) PyModule_GetDef(PyObject*);
 PyAPI_FUNC(void*) PyModule_GetState(PyObject*);
 

Modified: python/branches/py3k-cdecimal/Include/object.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/object.h	(original)
+++ python/branches/py3k-cdecimal/Include/object.h	Sun Jan  2 13:18:37 2011
@@ -61,6 +61,10 @@
 #define Py_REF_DEBUG
 #endif
 
+#if defined(Py_LIMITED_API) && defined(Py_REF_DEBUG)
+#error Py_LIMITED_API is incompatible with Py_DEBUG, Py_TRACE_REFS, and Py_REF_DEBUG
+#endif
+
 #ifdef Py_TRACE_REFS
 /* Define pointers to support a doubly-linked list of all live heap objects. */
 #define _PyObject_HEAD_EXTRA            \
@@ -196,6 +200,7 @@
 typedef int (*visitproc)(PyObject *, void *);
 typedef int (*traverseproc)(PyObject *, visitproc, void *);
 
+#ifndef Py_LIMITED_API
 typedef struct {
     /* Number implementations must check *both*
        arguments for proper type and implement the necessary conversions
@@ -265,10 +270,17 @@
      getbufferproc bf_getbuffer;
      releasebufferproc bf_releasebuffer;
 } PyBufferProcs;
+#endif /* Py_LIMITED_API */
 
 typedef void (*freefunc)(void *);
 typedef void (*destructor)(PyObject *);
+#ifndef Py_LIMITED_API
+/* We can't provide a full compile-time check that limited-API
+   users won't implement tp_print. However, not defining printfunc
+   and making tp_print of a different function pointer type
+   should at least cause a warning in most cases. */
 typedef int (*printfunc)(PyObject *, FILE *, int);
+#endif
 typedef PyObject *(*getattrfunc)(PyObject *, char *);
 typedef PyObject *(*getattrofunc)(PyObject *, PyObject *);
 typedef int (*setattrfunc)(PyObject *, char *, PyObject *);
@@ -284,6 +296,9 @@
 typedef PyObject *(*newfunc)(struct _typeobject *, PyObject *, PyObject *);
 typedef PyObject *(*allocfunc)(struct _typeobject *, Py_ssize_t);
 
+#ifdef Py_LIMITED_API
+typedef struct _typeobject PyTypeObject; /* opaque */
+#else
 typedef struct _typeobject {
     PyObject_VAR_HEAD
     const char *tp_name; /* For printing, in format "." */
@@ -371,8 +386,25 @@
     struct _typeobject *tp_next;
 #endif
 } PyTypeObject;
+#endif
+
+typedef struct{
+    int slot;    /* slot id, see below */
+    void *pfunc; /* function pointer */
+} PyType_Slot;
+
+typedef struct{
+    const char* name;
+    const char* doc;
+    int basicsize;
+    int itemsize;
+    int flags;
+    PyType_Slot *slots; /* terminated by slot==0. */
+} PyType_Spec;
 
+PyAPI_FUNC(PyObject*) PyType_FromSpec(PyType_Spec*);
 
+#ifndef Py_LIMITED_API
 /* The *real* layout of a type object when allocated on the heap */
 typedef struct _heaptypeobject {
     /* Note: there's a dependency on the order of these members
@@ -393,7 +425,7 @@
 /* access macro to the members which are floating "behind" the object */
 #define PyHeapType_GET_MEMBERS(etype) \
     ((PyMemberDef *)(((char *)etype) + Py_TYPE(etype)->tp_basicsize))
-
+#endif
 
 /* Generic type check */
 PyAPI_FUNC(int) PyType_IsSubtype(PyTypeObject *, PyTypeObject *);
@@ -412,15 +444,19 @@
 PyAPI_FUNC(PyObject *) PyType_GenericAlloc(PyTypeObject *, Py_ssize_t);
 PyAPI_FUNC(PyObject *) PyType_GenericNew(PyTypeObject *,
                                                PyObject *, PyObject *);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PyType_Lookup(PyTypeObject *, PyObject *);
 PyAPI_FUNC(PyObject *) _PyObject_LookupSpecial(PyObject *, char *, PyObject **);
+#endif
 PyAPI_FUNC(unsigned int) PyType_ClearCache(void);
 PyAPI_FUNC(void) PyType_Modified(PyTypeObject *);
 
 /* Generic operations on objects */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
 PyAPI_FUNC(void) _Py_BreakPoint(void);
 PyAPI_FUNC(void) _PyObject_Dump(PyObject *);
+#endif
 PyAPI_FUNC(PyObject *) PyObject_Repr(PyObject *);
 PyAPI_FUNC(PyObject *) PyObject_Str(PyObject *);
 PyAPI_FUNC(PyObject *) PyObject_ASCII(PyObject *);
@@ -433,9 +469,13 @@
 PyAPI_FUNC(PyObject *) PyObject_GetAttr(PyObject *, PyObject *);
 PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
 PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *);
+#endif
 PyAPI_FUNC(PyObject *) PyObject_SelfIter(PyObject *);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PyObject_NextNotImplemented(PyObject *);
+#endif
 PyAPI_FUNC(PyObject *) PyObject_GenericGetAttr(PyObject *, PyObject *);
 PyAPI_FUNC(int) PyObject_GenericSetAttr(PyObject *,
                                               PyObject *, PyObject *);
@@ -469,8 +509,10 @@
 PyAPI_FUNC(void) Py_ReprLeave(PyObject *);
 
 /* Helpers for hash functions */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(Py_hash_t) _Py_HashDouble(double);
 PyAPI_FUNC(Py_hash_t) _Py_HashPointer(void*);
+#endif
 
 /* Helper for passing objects to printf and the like */
 #define PyObject_REPR(obj) _PyUnicode_AsString(PyObject_Repr(obj))
@@ -649,9 +691,13 @@
 
 #define _Py_ForgetReference(op) _Py_INC_TPFREES(op)
 
+#ifdef Py_LIMITED_API
+PyAPI_FUNC(void) _Py_Dealloc(PyObject *);
+#else
 #define _Py_Dealloc(op) (                               \
     _Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA          \
     (*Py_TYPE(op)->tp_dealloc)((PyObject *)(op)))
+#endif
 #endif /* !Py_TRACE_REFS */
 
 #define Py_INCREF(op) (                         \

Modified: python/branches/py3k-cdecimal/Include/objimpl.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/objimpl.h	(original)
+++ python/branches/py3k-cdecimal/Include/objimpl.h	Sun Jan  2 13:18:37 2011
@@ -246,6 +246,7 @@
 #define _PyObject_GC_Del PyObject_GC_Del
 
 /* GC information is stored BEFORE the object structure. */
+#ifndef Py_LIMITED_API
 typedef union _gc_head {
     struct {
         union _gc_head *gc_next;
@@ -298,7 +299,7 @@
 #define _PyObject_GC_MAY_BE_TRACKED(obj) \
     (PyObject_IS_GC(obj) && \
         (!PyTuple_CheckExact(obj) || _PyObject_GC_IS_TRACKED(obj)))
-
+#endif /* Py_LIMITED_API */
 
 PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t);
 PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *);

Modified: python/branches/py3k-cdecimal/Include/parsetok.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/parsetok.h	(original)
+++ python/branches/py3k-cdecimal/Include/parsetok.h	Sun Jan  2 13:18:37 2011
@@ -1,6 +1,6 @@
 
 /* Parser-tokenizer link interface */
-
+#ifndef Py_LIMITED_API
 #ifndef Py_PARSETOK_H
 #define Py_PARSETOK_H
 #ifdef __cplusplus
@@ -9,10 +9,10 @@
 
 typedef struct {
     int error;
-    const char *filename;
+    const char *filename;       /* decoded from the filesystem encoding */
     int lineno;
     int offset;
-    char *text;
+    char *text;                 /* UTF-8-encoded string */
     int token;
     int expected;
 } perrdetail;
@@ -39,23 +39,32 @@
 
 PyAPI_FUNC(node *) PyParser_ParseStringFlags(const char *, grammar *, int,
                                               perrdetail *, int);
-PyAPI_FUNC(node *) PyParser_ParseFileFlags(FILE *, const char *, 
+PyAPI_FUNC(node *) PyParser_ParseFileFlags(FILE *, const char *,
 					   const char*, grammar *,
 						 int, char *, char *,
 						 perrdetail *, int);
-PyAPI_FUNC(node *) PyParser_ParseFileFlagsEx(FILE *, const char *,
-					   const char*, grammar *,
-						 int, char *, char *,
-						 perrdetail *, int *);
+PyAPI_FUNC(node *) PyParser_ParseFileFlagsEx(
+    FILE *fp,
+    const char *filename,       /* decoded from the filesystem encoding */
+    const char *enc,
+    grammar *g,
+    int start,
+    char *ps1,
+    char *ps2,
+    perrdetail *err_ret,
+    int *flags);
 
 PyAPI_FUNC(node *) PyParser_ParseStringFlagsFilename(const char *,
 					      const char *,
 					      grammar *, int,
                                               perrdetail *, int);
-PyAPI_FUNC(node *) PyParser_ParseStringFlagsFilenameEx(const char *,
-					      const char *,
-					      grammar *, int,
-                                              perrdetail *, int *);
+PyAPI_FUNC(node *) PyParser_ParseStringFlagsFilenameEx(
+    const char *s,
+    const char *filename,       /* decoded from the filesystem encoding */
+    grammar *g,
+    int start,
+    perrdetail *err_ret,
+    int *flags);
 
 /* Note that he following function is defined in pythonrun.c not parsetok.c. */
 PyAPI_FUNC(void) PyParser_SetError(perrdetail *);
@@ -64,3 +73,4 @@
 }
 #endif
 #endif /* !Py_PARSETOK_H */
+#endif /* !Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/patchlevel.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/patchlevel.h	(original)
+++ python/branches/py3k-cdecimal/Include/patchlevel.h	Sun Jan  2 13:18:37 2011
@@ -19,11 +19,11 @@
 #define PY_MAJOR_VERSION	3
 #define PY_MINOR_VERSION	2
 #define PY_MICRO_VERSION	0
-#define PY_RELEASE_LEVEL	PY_RELEASE_LEVEL_ALPHA
-#define PY_RELEASE_SERIAL	4
+#define PY_RELEASE_LEVEL	PY_RELEASE_LEVEL_BETA
+#define PY_RELEASE_SERIAL	2
 
 /* Version as a string */
-#define PY_VERSION      	"3.2a4+"
+#define PY_VERSION      	"3.2b2+"
 /*--end constants--*/
 
 /* Subversion Revision number of this file (not of the repository) */

Modified: python/branches/py3k-cdecimal/Include/pyarena.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pyarena.h	(original)
+++ python/branches/py3k-cdecimal/Include/pyarena.h	Sun Jan  2 13:18:37 2011
@@ -1,6 +1,7 @@
 /* An arena-like memory interface for the compiler.
  */
 
+#ifndef Py_LIMITED_API
 #ifndef Py_PYARENA_H
 #define Py_PYARENA_H
 
@@ -60,3 +61,4 @@
 #endif
 
 #endif /* !Py_PYARENA_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/pyatomic.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pyatomic.h	(original)
+++ python/branches/py3k-cdecimal/Include/pyatomic.h	Sun Jan  2 13:18:37 2011
@@ -1,3 +1,4 @@
+#ifndef Py_LIMITED_API
 #ifndef Py_ATOMIC_H
 #define Py_ATOMIC_H
 /* XXX: When compilers start offering a stdatomic.h with lock-free
@@ -177,3 +178,4 @@
 #endif
 
 #endif  /* Py_ATOMIC_H */
+#endif  /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/pyctype.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pyctype.h	(original)
+++ python/branches/py3k-cdecimal/Include/pyctype.h	Sun Jan  2 13:18:37 2011
@@ -1,3 +1,4 @@
+#ifndef Py_LIMITED_API
 #ifndef PYCTYPE_H
 #define PYCTYPE_H
 
@@ -29,3 +30,4 @@
 #define Py_TOUPPER(c) (_Py_ctype_toupper[Py_CHARMASK(c)])
 
 #endif /* !PYCTYPE_H */
+#endif /* !Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/pydebug.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pydebug.h	(original)
+++ python/branches/py3k-cdecimal/Include/pydebug.h	Sun Jan  2 13:18:37 2011
@@ -1,4 +1,4 @@
-
+#ifndef Py_LIMITED_API
 #ifndef Py_PYDEBUG_H
 #define Py_PYDEBUG_H
 #ifdef __cplusplus
@@ -7,6 +7,7 @@
 
 PyAPI_DATA(int) Py_DebugFlag;
 PyAPI_DATA(int) Py_VerboseFlag;
+PyAPI_DATA(int) Py_QuietFlag;
 PyAPI_DATA(int) Py_InteractiveFlag;
 PyAPI_DATA(int) Py_InspectFlag;
 PyAPI_DATA(int) Py_OptimizeFlag;
@@ -31,3 +32,4 @@
 }
 #endif
 #endif /* !Py_PYDEBUG_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/pyerrors.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pyerrors.h	(original)
+++ python/branches/py3k-cdecimal/Include/pyerrors.h	Sun Jan  2 13:18:37 2011
@@ -6,6 +6,7 @@
 
 /* Error objects */
 
+#ifndef Py_LIMITED_API
 /* PyException_HEAD defines the initial segment of every exception class. */
 #define PyException_HEAD PyObject_HEAD PyObject *dict;\
              PyObject *args; PyObject *traceback;\
@@ -55,6 +56,7 @@
     PyObject *winerror;
 } PyWindowsErrorObject;
 #endif
+#endif
 
 /* Error handling definitions */
 
@@ -68,8 +70,9 @@
 PyAPI_FUNC(void) PyErr_Clear(void);
 PyAPI_FUNC(void) PyErr_Fetch(PyObject **, PyObject **, PyObject **);
 PyAPI_FUNC(void) PyErr_Restore(PyObject *, PyObject *, PyObject *);
+PyAPI_FUNC(void) Py_FatalError(const char *message);
 
-#ifdef Py_DEBUG
+#if defined(Py_DEBUG) || defined(Py_LIMITED_API)
 #define _PyErr_OCCURRED() PyErr_Occurred()
 #else
 #define _PyErr_OCCURRED() (_PyThreadState_Current->curexc_type)
@@ -183,7 +186,7 @@
     PyObject *exc,
     const char *filename   /* decoded from the filesystem encoding */
     );
-#ifdef MS_WINDOWS
+#if defined(MS_WINDOWS) && !defined(Py_LIMITED_API)
 PyAPI_FUNC(PyObject *) PyErr_SetFromErrnoWithUnicodeFilename(
     PyObject *, const Py_UNICODE *);
 #endif /* MS_WINDOWS */
@@ -198,16 +201,26 @@
 PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilenameObject(
     int, const char *);
 PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithFilename(
-    int, const char *);
+    int ierr,
+    const char *filename        /* decoded from the filesystem encoding */
+    );
+#ifndef Py_LIMITED_API
+/* XXX redeclare to use WSTRING */
 PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErrWithUnicodeFilename(
     int, const Py_UNICODE *);
+#endif
 PyAPI_FUNC(PyObject *) PyErr_SetFromWindowsErr(int);
 PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilenameObject(
     PyObject *,int, PyObject *);
 PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithFilename(
-    PyObject *,int, const char *);
+    PyObject *exc,
+    int ierr,
+    const char *filename        /* decoded from the filesystem encoding */
+    );
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErrWithUnicodeFilename(
     PyObject *,int, const Py_UNICODE *);
+#endif
 PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErr(PyObject *, int);
 #endif /* MS_WINDOWS */
 
@@ -230,27 +243,57 @@
 PyAPI_FUNC(void) PyErr_SetInterrupt(void);
 
 /* In signalmodule.c */
+#ifndef Py_LIMITED_API
 int PySignal_SetWakeupFd(int fd);
+#endif
 
 /* Support for adding program text to SyntaxErrors */
-PyAPI_FUNC(void) PyErr_SyntaxLocation(const char *, int);
-PyAPI_FUNC(void) PyErr_SyntaxLocationEx(const char *, int, int);
-PyAPI_FUNC(PyObject *) PyErr_ProgramText(const char *, int);
+PyAPI_FUNC(void) PyErr_SyntaxLocation(
+    const char *filename,       /* decoded from the filesystem encoding */
+    int lineno);
+PyAPI_FUNC(void) PyErr_SyntaxLocationEx(
+    const char *filename,       /* decoded from the filesystem encoding */
+    int lineno,
+    int col_offset);
+PyAPI_FUNC(PyObject *) PyErr_ProgramText(
+    const char *filename,       /* decoded from the filesystem encoding */
+    int lineno);
 
 /* The following functions are used to create and modify unicode
    exceptions from C */
 
 /* create a UnicodeDecodeError object */
 PyAPI_FUNC(PyObject *) PyUnicodeDecodeError_Create(
-    const char *, const char *, Py_ssize_t, Py_ssize_t, Py_ssize_t, const char *);
+    const char *encoding,       /* UTF-8 encoded string */
+    const char *object,
+    Py_ssize_t length,
+    Py_ssize_t start,
+    Py_ssize_t end,
+    const char *reason          /* UTF-8 encoded string */
+    );
 
 /* create a UnicodeEncodeError object */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_Create(
-    const char *, const Py_UNICODE *, Py_ssize_t, Py_ssize_t, Py_ssize_t, const char *);
+    const char *encoding,       /* UTF-8 encoded string */
+    const Py_UNICODE *object,
+    Py_ssize_t length,
+    Py_ssize_t start,
+    Py_ssize_t end,
+    const char *reason          /* UTF-8 encoded string */
+    );
+#endif
 
 /* create a UnicodeTranslateError object */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) PyUnicodeTranslateError_Create(
-    const Py_UNICODE *, Py_ssize_t, Py_ssize_t, Py_ssize_t, const char *);
+    const Py_UNICODE *object,
+    Py_ssize_t length,
+    Py_ssize_t start,
+    Py_ssize_t end,
+    const char *reason          /* UTF-8 encoded string */
+    );
+#endif
 
 /* get the encoding attribute */
 PyAPI_FUNC(PyObject *) PyUnicodeEncodeError_GetEncoding(PyObject *);
@@ -293,11 +336,17 @@
 /* assign a new value to the reason attribute
    return 0 on success, -1 on failure */
 PyAPI_FUNC(int) PyUnicodeEncodeError_SetReason(
-    PyObject *, const char *);
+    PyObject *exc,
+    const char *reason          /* UTF-8 encoded string */
+    );
 PyAPI_FUNC(int) PyUnicodeDecodeError_SetReason(
-    PyObject *, const char *);
+    PyObject *exc,
+    const char *reason          /* UTF-8 encoded string */
+    );
 PyAPI_FUNC(int) PyUnicodeTranslateError_SetReason(
-    PyObject *, const char *);
+    PyObject *exc,
+    const char *reason          /* UTF-8 encoded string */
+    );
 
 
 /* These APIs aren't really part of the error implementation, but

Modified: python/branches/py3k-cdecimal/Include/pygetopt.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pygetopt.h	(original)
+++ python/branches/py3k-cdecimal/Include/pygetopt.h	Sun Jan  2 13:18:37 2011
@@ -5,9 +5,11 @@
 extern "C" {
 #endif
 
+#ifndef Py_LIMITED_API
 PyAPI_DATA(int) _PyOS_opterr;
 PyAPI_DATA(int) _PyOS_optind;
 PyAPI_DATA(wchar_t *) _PyOS_optarg;
+#endif
 
 PyAPI_FUNC(int) _PyOS_GetOpt(int argc, wchar_t **argv, wchar_t *optstring);
 

Modified: python/branches/py3k-cdecimal/Include/pymath.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pymath.h	(original)
+++ python/branches/py3k-cdecimal/Include/pymath.h	Sun Jan  2 13:18:37 2011
@@ -67,6 +67,7 @@
    nothing. */
 
 /* we take double rounding as evidence of x87 usage */
+#ifndef Py_LIMITED_API
 #ifndef Py_FORCE_DOUBLE
 #  ifdef X87_DOUBLE_ROUNDING
 PyAPI_FUNC(double) _Py_force_double(double);
@@ -75,11 +76,14 @@
 #    define Py_FORCE_DOUBLE(X) (X)
 #  endif
 #endif
+#endif
 
+#ifndef Py_LIMITED_API
 #ifdef HAVE_GCC_ASM_FOR_X87
 PyAPI_FUNC(unsigned short) _Py_get_387controlword(void);
 PyAPI_FUNC(void) _Py_set_387controlword(unsigned short);
 #endif
+#endif
 
 /* Py_IS_NAN(X)
  * Return 1 if float or double arg is a NaN, else 0.

Modified: python/branches/py3k-cdecimal/Include/pystate.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pystate.h	(original)
+++ python/branches/py3k-cdecimal/Include/pystate.h	Sun Jan  2 13:18:37 2011
@@ -13,6 +13,9 @@
 struct _ts; /* Forward */
 struct _is; /* Forward */
 
+#ifdef Py_LIMITED_API
+typedef struct _is PyInterpreterState;
+#else
 typedef struct _is {
 
     struct _is *next;
@@ -37,12 +40,14 @@
 #endif
 
 } PyInterpreterState;
+#endif
 
 
 /* State unique per thread */
 
 struct _frame; /* Avoid including frameobject.h */
 
+#ifndef Py_LIMITED_API
 /* Py_tracefunc return -1 when raising an exception, or 0 for success. */
 typedef int (*Py_tracefunc)(PyObject *, struct _frame *, int, PyObject *);
 
@@ -54,7 +59,11 @@
 #define PyTrace_C_CALL 4
 #define PyTrace_C_EXCEPTION 5
 #define PyTrace_C_RETURN 6
+#endif
 
+#ifdef Py_LIMITED_API
+typedef struct _ts PyThreadState;
+#else
 typedef struct _ts {
     /* See Python/ceval.c for comments explaining most fields */
 
@@ -106,6 +115,7 @@
     /* XXX signal handlers should also be here */
 
 } PyThreadState;
+#endif
 
 
 PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_New(void);
@@ -133,9 +143,11 @@
 
 /* Assuming the current thread holds the GIL, this is the
    PyThreadState for the current thread. */
+#ifndef Py_LIMITED_API
 PyAPI_DATA(_Py_atomic_address) _PyThreadState_Current;
+#endif
 
-#ifdef Py_DEBUG
+#if defined(Py_DEBUG) || defined(Py_LIMITED_API)
 #define PyThreadState_GET() PyThreadState_Get()
 #else
 #define PyThreadState_GET() \
@@ -190,19 +202,25 @@
 /* The implementation of sys._current_frames()  Returns a dict mapping
    thread id to that thread's current frame.
 */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PyThread_CurrentFrames(void);
+#endif
 
 /* Routines for advanced debuggers, requested by David Beazley.
    Don't use unless you know what you are doing! */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Head(void);
 PyAPI_FUNC(PyInterpreterState *) PyInterpreterState_Next(PyInterpreterState *);
 PyAPI_FUNC(PyThreadState *) PyInterpreterState_ThreadHead(PyInterpreterState *);
 PyAPI_FUNC(PyThreadState *) PyThreadState_Next(PyThreadState *);
 
 typedef struct _frame *(*PyThreadFrameGetter)(PyThreadState *self_);
+#endif
 
 /* hook for PyEval_GetFrame(), requested for Psyco */
+#ifndef Py_LIMITED_API
 PyAPI_DATA(PyThreadFrameGetter) _PyThreadState_GetFrame;
+#endif
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/pystrtod.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pystrtod.h	(original)
+++ python/branches/py3k-cdecimal/Include/pystrtod.h	Sun Jan  2 13:18:37 2011
@@ -18,7 +18,9 @@
                                          int flags,
                                          int *type);
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(double) _Py_parse_inf_or_nan(const char *p, char **endptr);
+#endif
 
 
 /* PyOS_double_to_string's "flags" parameter can be set to 0 or more of: */

Modified: python/branches/py3k-cdecimal/Include/pythonrun.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pythonrun.h	(original)
+++ python/branches/py3k-cdecimal/Include/pythonrun.h	Sun Jan  2 13:18:37 2011
@@ -16,9 +16,11 @@
 #define PyCF_ONLY_AST 0x0400
 #define PyCF_IGNORE_COOKIE 0x0800
 
+#ifndef Py_LIMITED_API
 typedef struct {
     int cf_flags;  /* bitmask of CO_xxx flags relevant to future */
 } PyCompilerFlags;
+#endif
 
 PyAPI_FUNC(void) Py_SetProgramName(wchar_t *);
 PyAPI_FUNC(wchar_t *) Py_GetProgramName(void);
@@ -33,41 +35,87 @@
 PyAPI_FUNC(PyThreadState *) Py_NewInterpreter(void);
 PyAPI_FUNC(void) Py_EndInterpreter(PyThreadState *);
 
-PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *, const char *, PyCompilerFlags *);
-PyAPI_FUNC(int) PyRun_AnyFileExFlags(FILE *, const char *, int, PyCompilerFlags *);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) PyRun_SimpleStringFlags(const char *, PyCompilerFlags *);
-PyAPI_FUNC(int) PyRun_SimpleFileExFlags(FILE *, const char *, int, PyCompilerFlags *);
-PyAPI_FUNC(int) PyRun_InteractiveOneFlags(FILE *, const char *, PyCompilerFlags *);
-PyAPI_FUNC(int) PyRun_InteractiveLoopFlags(FILE *, const char *, PyCompilerFlags *);
-
-PyAPI_FUNC(struct _mod *) PyParser_ASTFromString(const char *, const char *,
-                                                 int, PyCompilerFlags *flags,
-                                                 PyArena *);
-PyAPI_FUNC(struct _mod *) PyParser_ASTFromFile(FILE *, const char *,
-                                               const char*, int,
-                                               char *, char *,
-                                               PyCompilerFlags *, int *,
-                                               PyArena *);
+PyAPI_FUNC(int) PyRun_AnyFileFlags(FILE *, const char *, PyCompilerFlags *);
+PyAPI_FUNC(int) PyRun_AnyFileExFlags(
+    FILE *fp,
+    const char *filename,       /* decoded from the filesystem encoding */
+    int closeit,
+    PyCompilerFlags *flags);
+PyAPI_FUNC(int) PyRun_SimpleFileExFlags(
+    FILE *fp,
+    const char *filename,       /* decoded from the filesystem encoding */
+    int closeit,
+    PyCompilerFlags *flags);
+PyAPI_FUNC(int) PyRun_InteractiveOneFlags(
+    FILE *fp,
+    const char *filename,       /* decoded from the filesystem encoding */
+    PyCompilerFlags *flags);
+PyAPI_FUNC(int) PyRun_InteractiveLoopFlags(
+    FILE *fp,
+    const char *filename,       /* decoded from the filesystem encoding */
+    PyCompilerFlags *flags);
+
+PyAPI_FUNC(struct _mod *) PyParser_ASTFromString(
+    const char *s,
+    const char *filename,       /* decoded from the filesystem encoding */
+    int start,
+    PyCompilerFlags *flags,
+    PyArena *arena);
+PyAPI_FUNC(struct _mod *) PyParser_ASTFromFile(
+    FILE *fp,
+    const char *filename,       /* decoded from the filesystem encoding */
+    const char* enc,
+    int start,
+    char *ps1,
+    char *ps2,
+    PyCompilerFlags *flags,
+    int *errcode,
+    PyArena *arena);
+#endif
+
+#ifndef PyParser_SimpleParseString
 #define PyParser_SimpleParseString(S, B) \
     PyParser_SimpleParseStringFlags(S, B, 0)
 #define PyParser_SimpleParseFile(FP, S, B) \
     PyParser_SimpleParseFileFlags(FP, S, B, 0)
+#endif
 PyAPI_FUNC(struct _node *) PyParser_SimpleParseStringFlags(const char *, int,
                                                           int);
 PyAPI_FUNC(struct _node *) PyParser_SimpleParseFileFlags(FILE *, const char *,
                                                         int, int);
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) PyRun_StringFlags(const char *, int, PyObject *,
                                          PyObject *, PyCompilerFlags *);
 
-PyAPI_FUNC(PyObject *) PyRun_FileExFlags(FILE *, const char *, int,
-                                         PyObject *, PyObject *, int,
-                                         PyCompilerFlags *);
-
-#define Py_CompileString(str, p, s) Py_CompileStringFlags(str, p, s, NULL)
-PyAPI_FUNC(PyObject *) Py_CompileStringFlags(const char *, const char *, int,
-                                             PyCompilerFlags *);
-PyAPI_FUNC(struct symtable *) Py_SymtableString(const char *, const char *, int);
+PyAPI_FUNC(PyObject *) PyRun_FileExFlags(
+    FILE *fp,
+    const char *filename,       /* decoded from the filesystem encoding */
+    int start,
+    PyObject *globals,
+    PyObject *locals,
+    int closeit,
+    PyCompilerFlags *flags);
+#endif
+
+#ifdef Py_LIMITED_API
+PyAPI_FUNC(PyObject *) Py_CompileString(const char *, const char *, int);
+#else
+#define Py_CompileString(str, p, s) Py_CompileStringExFlags(str, p, s, NULL, -1)
+#define Py_CompileStringFlags(str, p, s, f) Py_CompileStringExFlags(str, p, s, f, -1)
+PyAPI_FUNC(PyObject *) Py_CompileStringExFlags(
+    const char *str,
+    const char *filename,       /* decoded from the filesystem encoding */
+    int start,
+    PyCompilerFlags *flags,
+    int optimize);
+#endif
+PyAPI_FUNC(struct symtable *) Py_SymtableString(
+    const char *str,
+    const char *filename,       /* decoded from the filesystem encoding */
+    int start);
 
 PyAPI_FUNC(void) PyErr_Print(void);
 PyAPI_FUNC(void) PyErr_PrintEx(int);
@@ -76,19 +124,24 @@
 /* Py_PyAtExit is for the atexit module, Py_AtExit is for low-level
  * exit functions.
  */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(void) _Py_PyAtExit(void (*func)(void));
+#endif
 PyAPI_FUNC(int) Py_AtExit(void (*func)(void));
 
 PyAPI_FUNC(void) Py_Exit(int);
 
 /* Restore signals that the interpreter has called SIG_IGN on to SIG_DFL. */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(void) _Py_RestoreSignals(void);
 
 PyAPI_FUNC(int) Py_FdIsInteractive(FILE *, const char *);
+#endif
 
 /* Bootstrap */
 PyAPI_FUNC(int) Py_Main(int argc, wchar_t **argv);
 
+#ifndef Py_LIMITED_API
 /* Use macros for a bunch of old variants */
 #define PyRun_String(str, s, g, l) PyRun_StringFlags(str, s, g, l, NULL)
 #define PyRun_AnyFile(fp, name) PyRun_AnyFileExFlags(fp, name, 0, NULL)
@@ -107,6 +160,7 @@
     PyRun_FileExFlags(fp, p, s, g, l, c, NULL)
 #define PyRun_FileFlags(fp, p, s, g, l, flags) \
     PyRun_FileExFlags(fp, p, s, g, l, 0, flags)
+#endif
 
 /* In getpath.c */
 PyAPI_FUNC(wchar_t *) Py_GetProgramFullPath(void);
@@ -114,6 +168,9 @@
 PyAPI_FUNC(wchar_t *) Py_GetExecPrefix(void);
 PyAPI_FUNC(wchar_t *) Py_GetPath(void);
 PyAPI_FUNC(void)      Py_SetPath(const wchar_t *);
+#ifdef MS_WINDOWS
+int _Py_CheckPython3();
+#endif
 
 /* In their own files */
 PyAPI_FUNC(const char *) Py_GetVersion(void);
@@ -121,11 +178,14 @@
 PyAPI_FUNC(const char *) Py_GetCopyright(void);
 PyAPI_FUNC(const char *) Py_GetCompiler(void);
 PyAPI_FUNC(const char *) Py_GetBuildInfo(void);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(const char *) _Py_svnversion(void);
 PyAPI_FUNC(const char *) Py_SubversionRevision(void);
 PyAPI_FUNC(const char *) Py_SubversionShortBranch(void);
+#endif
 
 /* Internal -- various one-time initializations */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PyBuiltin_Init(void);
 PyAPI_FUNC(PyObject *) _PySys_Init(void);
 PyAPI_FUNC(void) _PyImport_Init(void);
@@ -134,8 +194,10 @@
 PyAPI_FUNC(int) _PyFrame_Init(void);
 PyAPI_FUNC(void) _PyFloat_Init(void);
 PyAPI_FUNC(int) PyByteArray_Init(void);
+#endif
 
 /* Various internal finalizers */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(void) _PyExc_Fini(void);
 PyAPI_FUNC(void) _PyImport_Fini(void);
 PyAPI_FUNC(void) PyMethod_Fini(void);
@@ -150,12 +212,17 @@
 PyAPI_FUNC(void) PyFloat_Fini(void);
 PyAPI_FUNC(void) PyOS_FiniInterrupts(void);
 PyAPI_FUNC(void) _PyGC_Fini(void);
+#endif
 
 /* Stuff with no proper home (yet) */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(char *) PyOS_Readline(FILE *, FILE *, char *);
+#endif
 PyAPI_DATA(int) (*PyOS_InputHook)(void);
 PyAPI_DATA(char) *(*PyOS_ReadlineFunctionPointer)(FILE *, FILE *, char *);
+#ifndef Py_LIMITED_API
 PyAPI_DATA(PyThreadState*) _PyOS_ReadlineTState;
+#endif
 
 /* Stack size, in "pointers" (so we get extra safety margins
    on 64-bit platforms).  On a 32-bit platform, this translates

Modified: python/branches/py3k-cdecimal/Include/pythread.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pythread.h	(original)
+++ python/branches/py3k-cdecimal/Include/pythread.h	Sun Jan  2 13:18:37 2011
@@ -9,6 +9,14 @@
 extern "C" {
 #endif
 
+/* Return status codes for Python lock acquisition.  Chosen for maximum
+ * backwards compatibility, ie failure -> 0, success -> 1.  */
+typedef enum PyLockStatus {
+    PY_LOCK_FAILURE = 0,
+    PY_LOCK_ACQUIRED = 1,
+    PY_LOCK_INTR
+} PyLockStatus;
+
 PyAPI_FUNC(void) PyThread_init_thread(void);
 PyAPI_FUNC(long) PyThread_start_new_thread(void (*)(void *), void *);
 PyAPI_FUNC(void) PyThread_exit_thread(void);
@@ -49,11 +57,18 @@
    even when the lock can't be acquired.
    If microseconds > 0, the call waits up to the specified duration.
    If microseconds < 0, the call waits until success (or abnormal failure)
-   
+
    microseconds must be less than PY_TIMEOUT_MAX. Behaviour otherwise is
-   undefined. */
-PyAPI_FUNC(int) PyThread_acquire_lock_timed(PyThread_type_lock,
-					    PY_TIMEOUT_T microseconds);
+   undefined.
+
+   If intr_flag is true and the acquire is interrupted by a signal, then the
+   call will return PY_LOCK_INTR.  The caller may reattempt to acquire the
+   lock.
+*/
+PyAPI_FUNC(PyLockStatus) PyThread_acquire_lock_timed(PyThread_type_lock,
+                                                     PY_TIMEOUT_T microseconds,
+                                                     int intr_flag);
+
 PyAPI_FUNC(void) PyThread_release_lock(PyThread_type_lock);
 
 PyAPI_FUNC(size_t) PyThread_get_stacksize(void);

Modified: python/branches/py3k-cdecimal/Include/pytime.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/pytime.h	(original)
+++ python/branches/py3k-cdecimal/Include/pytime.h	Sun Jan  2 13:18:37 2011
@@ -1,3 +1,4 @@
+#ifndef Py_LIMITED_API
 #ifndef Py_PYTIME_H
 #define Py_PYTIME_H
 
@@ -44,3 +45,4 @@
 #endif
 
 #endif /* Py_PYTIME_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/setobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/setobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/setobject.h	Sun Jan  2 13:18:37 2011
@@ -18,7 +18,7 @@
 hold a search finger.  The hash field of Unused or Dummy slots has
 no meaning otherwise.
 */
-
+#ifndef Py_LIMITED_API
 #define PySet_MINSIZE 8
 
 typedef struct {
@@ -56,6 +56,7 @@
     Py_hash_t hash;                  /* only used by frozenset objects */
     PyObject *weakreflist;      /* List of weak references */
 };
+#endif /* Py_LIMITED_API */
 
 PyAPI_DATA(PyTypeObject) PySet_Type;
 PyAPI_DATA(PyTypeObject) PyFrozenSet_Type;
@@ -85,14 +86,20 @@
 PyAPI_FUNC(PyObject *) PySet_New(PyObject *);
 PyAPI_FUNC(PyObject *) PyFrozenSet_New(PyObject *);
 PyAPI_FUNC(Py_ssize_t) PySet_Size(PyObject *anyset);
+#ifndef Py_LIMITED_API
 #define PySet_GET_SIZE(so) (((PySetObject *)(so))->used)
+#endif
 PyAPI_FUNC(int) PySet_Clear(PyObject *set);
 PyAPI_FUNC(int) PySet_Contains(PyObject *anyset, PyObject *key);
 PyAPI_FUNC(int) PySet_Discard(PyObject *set, PyObject *key);
 PyAPI_FUNC(int) PySet_Add(PyObject *set, PyObject *key);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash);
+#endif
 PyAPI_FUNC(PyObject *) PySet_Pop(PyObject *set);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PySet_Update(PyObject *set, PyObject *iterable);
+#endif
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/sliceobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/sliceobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/sliceobject.h	Sun Jan  2 13:18:37 2011
@@ -18,11 +18,12 @@
 names are from range).  After much talk with Guido, it was decided to
 let these be any arbitrary python type.  Py_None stands for omitted values.
 */
-
+#ifndef Py_LIMITED_API
 typedef struct {
     PyObject_HEAD
     PyObject *start, *stop, *step;	/* not NULL */
 } PySliceObject;
+#endif
 
 PyAPI_DATA(PyTypeObject) PySlice_Type;
 PyAPI_DATA(PyTypeObject) PyEllipsis_Type;
@@ -31,10 +32,12 @@
 
 PyAPI_FUNC(PyObject *) PySlice_New(PyObject* start, PyObject* stop,
                                   PyObject* step);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PySlice_FromIndices(Py_ssize_t start, Py_ssize_t stop);
-PyAPI_FUNC(int) PySlice_GetIndices(PySliceObject *r, Py_ssize_t length,
+#endif
+PyAPI_FUNC(int) PySlice_GetIndices(PyObject *r, Py_ssize_t length,
                                   Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step);
-PyAPI_FUNC(int) PySlice_GetIndicesEx(PySliceObject *r, Py_ssize_t length,
+PyAPI_FUNC(int) PySlice_GetIndicesEx(PyObject *r, Py_ssize_t length,
 				    Py_ssize_t *start, Py_ssize_t *stop, 
 				    Py_ssize_t *step, Py_ssize_t *slicelength);
 

Modified: python/branches/py3k-cdecimal/Include/structseq.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/structseq.h	(original)
+++ python/branches/py3k-cdecimal/Include/structseq.h	Sun Jan  2 13:18:37 2011
@@ -21,18 +21,25 @@
 
 extern char* PyStructSequence_UnnamedField;
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type,
                                            PyStructSequence_Desc *desc);
+#endif
+PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc);
 
 PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type);
 
+#ifndef Py_LIMITED_API
 typedef PyTupleObject PyStructSequence;
 
 /* Macro, *only* to be used to fill in brand new objects */
 #define PyStructSequence_SET_ITEM(op, i, v) PyTuple_SET_ITEM(op, i, v)
 
 #define PyStructSequence_GET_ITEM(op, i) PyTuple_GET_ITEM(op, i)
+#endif
 
+PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*);
+PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t);
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/symtable.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/symtable.h	(original)
+++ python/branches/py3k-cdecimal/Include/symtable.h	Sun Jan  2 13:18:37 2011
@@ -1,3 +1,4 @@
+#ifndef Py_LIMITED_API
 #ifndef Py_SYMTABLE_H
 #define Py_SYMTABLE_H
 
@@ -15,7 +16,8 @@
 struct _symtable_entry;
 
 struct symtable {
-    const char *st_filename;        /* name of file being compiled */
+    const char *st_filename;        /* name of file being compiled,
+                                       decoded from the filesystem encoding */
     struct _symtable_entry *st_cur; /* current symbol table entry */
     struct _symtable_entry *st_top; /* symbol table entry for module */
     PyObject *st_blocks;            /* dict: map AST node addresses
@@ -59,8 +61,10 @@
 
 PyAPI_FUNC(int) PyST_GetScope(PySTEntryObject *, PyObject *);
 
-PyAPI_FUNC(struct symtable *) PySymtable_Build(mod_ty, const char *,
-                                              PyFutureFeatures *);
+PyAPI_FUNC(struct symtable *) PySymtable_Build(
+    mod_ty mod,
+    const char *filename,       /* decoded from the filesystem encoding */
+    PyFutureFeatures *future);
 PyAPI_FUNC(PySTEntryObject *) PySymtable_Lookup(struct symtable *, void *);
 
 PyAPI_FUNC(void) PySymtable_Free(struct symtable *);
@@ -102,3 +106,4 @@
 }
 #endif
 #endif /* !Py_SYMTABLE_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/sysmodule.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/sysmodule.h	(original)
+++ python/branches/py3k-cdecimal/Include/sysmodule.h	Sun Jan  2 13:18:37 2011
@@ -20,7 +20,9 @@
 PyAPI_FUNC(void) PySys_FormatStdout(const char *format, ...);
 PyAPI_FUNC(void) PySys_FormatStderr(const char *format, ...);
 
+#ifndef Py_LIMITED_API
 PyAPI_DATA(PyObject *) _PySys_TraceFunc, *_PySys_ProfileFunc;
+#endif
 
 PyAPI_FUNC(void) PySys_ResetWarnOptions(void);
 PyAPI_FUNC(void) PySys_AddWarnOption(const wchar_t *);

Modified: python/branches/py3k-cdecimal/Include/timefuncs.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/timefuncs.h	(original)
+++ python/branches/py3k-cdecimal/Include/timefuncs.h	Sun Jan  2 13:18:37 2011
@@ -14,7 +14,9 @@
  * to fit in a time_t.  ValueError is set on return iff the return
  * value is (time_t)-1 and PyErr_Occurred().
  */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(time_t) _PyTime_DoubleToTimet(double x);
+#endif
 
 
 #ifdef __cplusplus

Modified: python/branches/py3k-cdecimal/Include/token.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/token.h	(original)
+++ python/branches/py3k-cdecimal/Include/token.h	Sun Jan  2 13:18:37 2011
@@ -1,6 +1,6 @@
 
 /* Token types */
-
+#ifndef Py_LIMITED_API
 #ifndef Py_TOKEN_H
 #define Py_TOKEN_H
 #ifdef __cplusplus
@@ -85,3 +85,4 @@
 }
 #endif
 #endif /* !Py_TOKEN_H */
+#endif /* Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/traceback.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/traceback.h	(original)
+++ python/branches/py3k-cdecimal/Include/traceback.h	Sun Jan  2 13:18:37 2011
@@ -8,7 +8,7 @@
 struct _frame;
 
 /* Traceback interface */
-
+#ifndef Py_LIMITED_API
 typedef struct _traceback {
     PyObject_HEAD
     struct _traceback *tb_next;
@@ -16,10 +16,13 @@
     int tb_lasti;
     int tb_lineno;
 } PyTracebackObject;
+#endif
 
 PyAPI_FUNC(int) PyTraceBack_Here(struct _frame *);
 PyAPI_FUNC(int) PyTraceBack_Print(PyObject *, PyObject *);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _Py_DisplaySourceLine(PyObject *, PyObject *, int, int);
+#endif
 
 /* Reveal traceback type so we can typecheck traceback objects */
 PyAPI_DATA(PyTypeObject) PyTraceBack_Type;

Modified: python/branches/py3k-cdecimal/Include/tupleobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/tupleobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/tupleobject.h	Sun Jan  2 13:18:37 2011
@@ -21,6 +21,7 @@
 returned item's reference count.
 */
 
+#ifndef Py_LIMITED_API
 typedef struct {
     PyObject_VAR_HEAD
     PyObject *ob_item[1];
@@ -30,6 +31,7 @@
      * the tuple is not yet visible outside the function that builds it.
      */
 } PyTupleObject;
+#endif
 
 PyAPI_DATA(PyTypeObject) PyTuple_Type;
 PyAPI_DATA(PyTypeObject) PyTupleIter_Type;
@@ -43,16 +45,22 @@
 PyAPI_FUNC(PyObject *) PyTuple_GetItem(PyObject *, Py_ssize_t);
 PyAPI_FUNC(int) PyTuple_SetItem(PyObject *, Py_ssize_t, PyObject *);
 PyAPI_FUNC(PyObject *) PyTuple_GetSlice(PyObject *, Py_ssize_t, Py_ssize_t);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) _PyTuple_Resize(PyObject **, Py_ssize_t);
+#endif
 PyAPI_FUNC(PyObject *) PyTuple_Pack(Py_ssize_t, ...);
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(void) _PyTuple_MaybeUntrack(PyObject *);
+#endif
 
 /* Macro, trading safety for speed */
+#ifndef Py_LIMITED_API
 #define PyTuple_GET_ITEM(op, i) (((PyTupleObject *)(op))->ob_item[i])
 #define PyTuple_GET_SIZE(op)    Py_SIZE(op)
 
 /* Macro, *only* to be used to fill in brand new tuples */
 #define PyTuple_SET_ITEM(op, i, v) (((PyTupleObject *)(op))->ob_item[i] = v)
+#endif
 
 PyAPI_FUNC(int) PyTuple_ClearFreeList(void);
 

Modified: python/branches/py3k-cdecimal/Include/ucnhash.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/ucnhash.h	(original)
+++ python/branches/py3k-cdecimal/Include/ucnhash.h	Sun Jan  2 13:18:37 2011
@@ -1,5 +1,5 @@
 /* Unicode name database interface */
-
+#ifndef Py_LIMITED_API
 #ifndef Py_UCNHASH_H
 #define Py_UCNHASH_H
 #ifdef __cplusplus
@@ -31,3 +31,4 @@
 }
 #endif
 #endif /* !Py_UCNHASH_H */
+#endif /* !Py_LIMITED_API */

Modified: python/branches/py3k-cdecimal/Include/unicodeobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/unicodeobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/unicodeobject.h	Sun Jan  2 13:18:37 2011
@@ -131,7 +131,9 @@
    Python and represents a single Unicode element in the Unicode
    type. */
 
+#ifndef Py_LIMITED_API
 typedef PY_UNICODE_TYPE Py_UNICODE;
+#endif
 
 /* --- UCS-2/UCS-4 Name Mangling ------------------------------------------ */
 
@@ -318,6 +320,7 @@
    _Py_ascii_whitespace (see below) with an inlined check.
 
  */
+#ifndef Py_LIMITED_API
 #define Py_UNICODE_ISSPACE(ch) \
     ((ch) < 128U ? _Py_ascii_whitespace[(ch)] : _PyUnicode_IsWhitespace(ch))
 
@@ -362,6 +365,7 @@
     ((*((string)->str + (offset)) == *((substring)->str)) && \
     ((*((string)->str + (offset) + (substring)->length-1) == *((substring)->str + (substring)->length-1))) && \
      !memcmp((string)->str + (offset), (substring)->str, (substring)->length*sizeof(Py_UNICODE)))
+#endif /* Py_LIMITED_API */
 
 #ifdef __cplusplus
 extern "C" {
@@ -369,6 +373,7 @@
 
 /* --- Unicode Type ------------------------------------------------------- */
 
+#ifndef Py_LIMITED_API
 typedef struct {
     PyObject_HEAD
     Py_ssize_t length;          /* Length of raw Unicode data in buffer */
@@ -381,6 +386,7 @@
                                    string, or NULL; this is used for
                                    implementing the buffer protocol */
 } PyUnicodeObject;
+#endif
 
 PyAPI_DATA(PyTypeObject) PyUnicode_Type;
 PyAPI_DATA(PyTypeObject) PyUnicodeIter_Type;
@@ -394,6 +400,7 @@
 #define PyUnicode_CheckExact(op) (Py_TYPE(op) == &PyUnicode_Type)
 
 /* Fast access macros */
+#ifndef Py_LIMITED_API
 #define PyUnicode_GET_SIZE(op) \
     (assert(PyUnicode_Check(op)),(((PyUnicodeObject *)(op))->length))
 #define PyUnicode_GET_DATA_SIZE(op) \
@@ -402,6 +409,7 @@
     (assert(PyUnicode_Check(op)),(((PyUnicodeObject *)(op))->str))
 #define PyUnicode_AS_DATA(op) \
     (assert(PyUnicode_Check(op)),((const char *)((PyUnicodeObject *)(op))->str))
+#endif
 
 /* --- Constants ---------------------------------------------------------- */
 
@@ -426,29 +434,33 @@
 
    The buffer is copied into the new object. */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_FromUnicode(
     const Py_UNICODE *u,        /* Unicode buffer */
     Py_ssize_t size             /* size of buffer */
     );
+#endif
 
 /* Similar to PyUnicode_FromUnicode(), but u points to UTF-8 encoded bytes */
 PyAPI_FUNC(PyObject*) PyUnicode_FromStringAndSize(
-    const char *u,        /* char buffer */
-    Py_ssize_t size       /* size of buffer */
+    const char *u,             /* UTF-8 encoded string */
+    Py_ssize_t size            /* size of buffer */
     );
 
 /* Similar to PyUnicode_FromUnicode(), but u points to null-terminated
    UTF-8 encoded bytes */
 PyAPI_FUNC(PyObject*) PyUnicode_FromString(
-    const char *u        /* string */
+    const char *u              /* UTF-8 encoded string */
     );
 
 /* Return a read-only pointer to the Unicode object's internal
    Py_UNICODE buffer. */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(Py_UNICODE *) PyUnicode_AsUnicode(
     PyObject *unicode           /* Unicode object */
     );
+#endif
 
 /* Get the length of the Unicode object. */
 
@@ -456,8 +468,10 @@
     PyObject *unicode           /* Unicode object */
     );
 
+#ifndef Py_LIMITED_API
 /* Get the maximum ordinal for a Unicode character. */
 PyAPI_FUNC(Py_UNICODE) PyUnicode_GetMax(void);
+#endif
 
 /* Resize an already allocated Unicode object to the new size length.
 
@@ -527,16 +541,22 @@
     ...
     );
 
+#ifndef Py_LIMITED_API
 /* Format the object based on the format_spec, as defined in PEP 3101
    (Advanced String Formatting). */
 PyAPI_FUNC(PyObject *) _PyUnicode_FormatAdvanced(PyObject *obj,
                                                  Py_UNICODE *format_spec,
                                                  Py_ssize_t format_spec_len);
+#endif
 
 PyAPI_FUNC(void) PyUnicode_InternInPlace(PyObject **);
 PyAPI_FUNC(void) PyUnicode_InternImmortal(PyObject **);
-PyAPI_FUNC(PyObject *) PyUnicode_InternFromString(const char *);
+PyAPI_FUNC(PyObject *) PyUnicode_InternFromString(
+    const char *u              /* UTF-8 encoded string */
+    );
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(void) _Py_ReleaseInternedUnicodeStrings(void);
+#endif
 
 /* Use only if you know it's a string */
 #define PyUnicode_CHECK_INTERNED(op) (((PyUnicodeObject *)(op))->state)
@@ -568,7 +588,7 @@
    error. */
 
 PyAPI_FUNC(Py_ssize_t) PyUnicode_AsWideChar(
-    PyUnicodeObject *unicode,   /* Unicode object */
+    PyObject *unicode,          /* Unicode object */
     register wchar_t *w,        /* wchar_t buffer */
     Py_ssize_t size             /* size of buffer */
     );
@@ -646,9 +666,11 @@
 
 */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) _PyUnicode_AsDefaultEncodedString(
     PyObject *unicode,
     const char *errors);
+#endif
 
 /* Returns a pointer to the default encoding (UTF-8) of the
    Unicode object unicode and the size of the encoded representation
@@ -664,9 +686,11 @@
 
 */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(char *) _PyUnicode_AsStringAndSize(
     PyObject *unicode,
     Py_ssize_t *size);
+#endif
 
 /* Returns a pointer to the default encoding (UTF-8) of the
    Unicode object unicode.
@@ -682,7 +706,9 @@
 
 */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(char *) _PyUnicode_AsString(PyObject *unicode);
+#endif
 
 /* Returns "utf-8".  */
 
@@ -721,12 +747,14 @@
 /* Encodes a Py_UNICODE buffer of the given size and returns a
    Python string object. */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_Encode(
     const Py_UNICODE *s,        /* Unicode char buffer */
     Py_ssize_t size,            /* number of Py_UNICODE chars to encode */
     const char *encoding,       /* encoding */
     const char *errors          /* error handling */
     );
+#endif
 
 /* Encodes a Unicode object and returns the result as Python
    object. */
@@ -776,6 +804,7 @@
     Py_ssize_t *consumed        /* bytes consumed */
     );
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF7(
     const Py_UNICODE *data,     /* Unicode char buffer */
     Py_ssize_t length,          /* number of Py_UNICODE chars to encode */
@@ -783,6 +812,7 @@
     int base64WhiteSpace,       /* Encode whitespace (sp, ht, nl, cr) in base64 */
     const char *errors          /* error handling */
     );
+#endif
 
 /* --- UTF-8 Codecs ------------------------------------------------------- */
 
@@ -803,11 +833,13 @@
     PyObject *unicode           /* Unicode object */
     );
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF8(
     const Py_UNICODE *data,     /* Unicode char buffer */
     Py_ssize_t length,          /* number of Py_UNICODE chars to encode */
     const char *errors          /* error handling */
     );
+#endif
 
 /* --- UTF-32 Codecs ------------------------------------------------------ */
 
@@ -876,12 +908,14 @@
 
 */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF32(
     const Py_UNICODE *data,     /* Unicode char buffer */
     Py_ssize_t length,          /* number of Py_UNICODE chars to encode */
     const char *errors,         /* error handling */
     int byteorder               /* byteorder to use 0=BOM+native;-1=LE,1=BE */
     );
+#endif
 
 /* --- UTF-16 Codecs ------------------------------------------------------ */
 
@@ -954,12 +988,14 @@
 
 */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_EncodeUTF16(
     const Py_UNICODE *data,     /* Unicode char buffer */
     Py_ssize_t length,          /* number of Py_UNICODE chars to encode */
     const char *errors,         /* error handling */
     int byteorder               /* byteorder to use 0=BOM+native;-1=LE,1=BE */
     );
+#endif
 
 /* --- Unicode-Escape Codecs ---------------------------------------------- */
 
@@ -973,10 +1009,12 @@
     PyObject *unicode           /* Unicode object */
     );
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_EncodeUnicodeEscape(
     const Py_UNICODE *data,     /* Unicode char buffer */
     Py_ssize_t length           /* Number of Py_UNICODE chars to encode */
     );
+#endif
 
 /* --- Raw-Unicode-Escape Codecs ------------------------------------------ */
 
@@ -990,20 +1028,24 @@
     PyObject *unicode           /* Unicode object */
     );
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_EncodeRawUnicodeEscape(
     const Py_UNICODE *data,     /* Unicode char buffer */
     Py_ssize_t length           /* Number of Py_UNICODE chars to encode */
     );
+#endif
 
 /* --- Unicode Internal Codec ---------------------------------------------
 
     Only for internal use in _codecsmodule.c */
 
+#ifndef Py_LIMITED_API
 PyObject *_PyUnicode_DecodeUnicodeInternal(
     const char *string,
     Py_ssize_t length,
     const char *errors
     );
+#endif
 
 /* --- Latin-1 Codecs -----------------------------------------------------
 
@@ -1021,11 +1063,13 @@
     PyObject *unicode           /* Unicode object */
     );
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_EncodeLatin1(
     const Py_UNICODE *data,     /* Unicode char buffer */
     Py_ssize_t length,          /* Number of Py_UNICODE chars to encode */
     const char *errors          /* error handling */
     );
+#endif
 
 /* --- ASCII Codecs -------------------------------------------------------
 
@@ -1043,11 +1087,13 @@
     PyObject *unicode           /* Unicode object */
     );
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_EncodeASCII(
     const Py_UNICODE *data,     /* Unicode char buffer */
     Py_ssize_t length,          /* Number of Py_UNICODE chars to encode */
     const char *errors          /* error handling */
     );
+#endif
 
 /* --- Character Map Codecs -----------------------------------------------
 
@@ -1085,6 +1131,7 @@
                                    (unicode ordinal -> char ordinal) */
     );
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_EncodeCharmap(
     const Py_UNICODE *data,     /* Unicode char buffer */
     Py_ssize_t length,          /* Number of Py_UNICODE chars to encode */
@@ -1092,6 +1139,7 @@
                                    (unicode ordinal -> char ordinal) */
     const char *errors          /* error handling */
     );
+#endif
 
 /* Translate a Py_UNICODE buffer of the given length by applying a
    character mapping table to it and return the resulting Unicode
@@ -1106,12 +1154,14 @@
 
 */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject *) PyUnicode_TranslateCharmap(
     const Py_UNICODE *data,     /* Unicode char buffer */
     Py_ssize_t length,          /* Number of Py_UNICODE chars to encode */
     PyObject *table,            /* Translate table */
     const char *errors          /* error handling */
     );
+#endif
 
 #ifdef MS_WIN32
 
@@ -1134,11 +1184,13 @@
     PyObject *unicode           /* Unicode object */
     );
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) PyUnicode_EncodeMBCS(
     const Py_UNICODE *data,     /* Unicode char buffer */
     Py_ssize_t length,          /* Number of Py_UNICODE chars to encode */
     const char *errors          /* error handling */
     );
+#endif
 
 #endif /* MS_WIN32 */
 
@@ -1166,12 +1218,27 @@
 
 */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(int) PyUnicode_EncodeDecimal(
     Py_UNICODE *s,              /* Unicode buffer */
     Py_ssize_t length,          /* Number of Py_UNICODE chars to encode */
     char *output,               /* Output buffer; must have size >= length */
     const char *errors          /* error handling */
     );
+#endif
+
+/* Transforms code points that have decimal digit property to the
+   corresponding ASCII digit code points.
+
+   Returns a new Unicode string on success, NULL on failure.
+*/
+
+#ifndef Py_LIMITED_API
+PyAPI_FUNC(PyObject*) PyUnicode_TransformDecimalToASCII(
+    Py_UNICODE *s,              /* Unicode buffer */
+    Py_ssize_t length           /* Number of Py_UNICODE chars to transform */
+    );
+#endif
 
 /* --- File system encoding ---------------------------------------------- */
 
@@ -1390,7 +1457,7 @@
 
 PyAPI_FUNC(int) PyUnicode_CompareWithASCIIString(
     PyObject *left,
-    const char *right
+    const char *right           /* ASCII-encoded string */
     );
 
 /* Rich compare two strings and return one of the following:
@@ -1438,26 +1505,31 @@
 
 PyAPI_FUNC(int) PyUnicode_IsIdentifier(PyObject *s);
 
+#ifndef Py_LIMITED_API
 /* Externally visible for str.strip(unicode) */
 PyAPI_FUNC(PyObject *) _PyUnicode_XStrip(
     PyUnicodeObject *self,
     int striptype,
     PyObject *sepobj
     );
+#endif
 
 /* Using the current locale, insert the thousands grouping
    into the string pointed to by buffer.  For the argument descriptions,
    see Objects/stringlib/localeutil.h */
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGroupingLocale(Py_UNICODE *buffer,
                                                    Py_ssize_t n_buffer,
                                                    Py_UNICODE *digits,
                                                    Py_ssize_t n_digits,
                                                    Py_ssize_t min_width);
+#endif
 
 /* Using explicit passed-in values, insert the thousands grouping
    into the string pointed to by buffer.  For the argument descriptions,
    see Objects/stringlib/localeutil.h */
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(Py_ssize_t) _PyUnicode_InsertThousandsGrouping(Py_UNICODE *buffer,
                                                    Py_ssize_t n_buffer,
                                                    Py_UNICODE *digits,
@@ -1465,10 +1537,12 @@
                                                    Py_ssize_t min_width,
                                                    const char *grouping,
                                                    const char *thousands_sep);
+#endif
 /* === Characters Type APIs =============================================== */
 
 /* Helper array used by Py_UNICODE_ISSPACE(). */
 
+#ifndef Py_LIMITED_API
 PyAPI_DATA(const unsigned char) _Py_ascii_whitespace[];
 
 /* These should not be used directly. Use the Py_UNICODE_IS* and
@@ -1594,6 +1668,7 @@
 PyAPI_FUNC(Py_UNICODE*) PyUnicode_AsUnicodeCopy(
     PyObject *unicode
     );
+#endif /* Py_LIMITED_API */
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/warnings.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/warnings.h	(original)
+++ python/branches/py3k-cdecimal/Include/warnings.h	Sun Jan  2 13:18:37 2011
@@ -4,15 +4,31 @@
 extern "C" {
 #endif
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(PyObject*) _PyWarnings_Init(void);
+#endif
 
-PyAPI_FUNC(int) PyErr_WarnEx(PyObject *, const char *, Py_ssize_t);
-PyAPI_FUNC(int) PyErr_WarnFormat(PyObject *, Py_ssize_t, const char *, ...);
-PyAPI_FUNC(int) PyErr_WarnExplicit(PyObject *, const char *, const char *, int,
-                                    const char *, PyObject *);
+PyAPI_FUNC(int) PyErr_WarnEx(
+    PyObject *category,
+    const char *message,        /* UTF-8 encoded string */
+    Py_ssize_t stack_level);
+PyAPI_FUNC(int) PyErr_WarnFormat(
+    PyObject *category,
+    Py_ssize_t stack_level,
+    const char *format,         /* ASCII-encoded string  */
+    ...);
+PyAPI_FUNC(int) PyErr_WarnExplicit(
+    PyObject *category,
+    const char *message,        /* UTF-8 encoded string */
+    const char *filename,       /* decoded from the filesystem encoding */
+    int lineno,
+    const char *module,         /* UTF-8 encoded string */
+    PyObject *registry);
 
 /* DEPRECATED: Use PyErr_WarnEx() instead. */
+#ifndef Py_LIMITED_API
 #define PyErr_Warn(category, msg) PyErr_WarnEx(category, msg, 1)
+#endif
 
 #ifdef __cplusplus
 }

Modified: python/branches/py3k-cdecimal/Include/weakrefobject.h
==============================================================================
--- python/branches/py3k-cdecimal/Include/weakrefobject.h	(original)
+++ python/branches/py3k-cdecimal/Include/weakrefobject.h	Sun Jan  2 13:18:37 2011
@@ -12,6 +12,7 @@
 /* PyWeakReference is the base struct for the Python ReferenceType, ProxyType,
  * and CallableProxyType.
  */
+#ifndef Py_LIMITED_API
 struct _PyWeakReference {
     PyObject_HEAD
 
@@ -37,6 +38,7 @@
     PyWeakReference *wr_prev;
     PyWeakReference *wr_next;
 };
+#endif
 
 PyAPI_DATA(PyTypeObject) _PyWeakref_RefType;
 PyAPI_DATA(PyTypeObject) _PyWeakref_ProxyType;
@@ -62,9 +64,11 @@
                                                 PyObject *callback);
 PyAPI_FUNC(PyObject *) PyWeakref_GetObject(PyObject *ref);
 
+#ifndef Py_LIMITED_API
 PyAPI_FUNC(Py_ssize_t) _PyWeakref_GetWeakrefCount(PyWeakReference *head);
 
 PyAPI_FUNC(void) _PyWeakref_ClearRef(PyWeakReference *self);
+#endif
 
 #define PyWeakref_GET_OBJECT(ref) (((PyWeakReference *)(ref))->wr_object)
 

Modified: python/branches/py3k-cdecimal/LICENSE
==============================================================================
--- python/branches/py3k-cdecimal/LICENSE	(original)
+++ python/branches/py3k-cdecimal/LICENSE	Sun Jan  2 13:18:37 2011
@@ -68,7 +68,7 @@
     3.1             3.0.1       2009        PSF         yes
     3.1.1           3.1         2009        PSF         yes
     3.1.2           3.1         2010        PSF         yes
-    3.2             3.1         2010        PSF         yes
+    3.2             3.1         2011        PSF         yes
 
 Footnotes:
 
@@ -103,9 +103,9 @@
 analyze, test, perform and/or display publicly, prepare derivative works,
 distribute, and otherwise use Python alone or in any derivative version,
 provided, however, that PSF's License Agreement and PSF's notice of copyright,
-i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-Python Software Foundation; All Rights Reserved" are retained in Python alone or
-in any derivative version prepared by Licensee.
+i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+2011 Python Software Foundation; All Rights Reserved" are retained in Python
+alone or in any derivative version prepared by Licensee.
 
 3. In the event Licensee prepares a derivative work that is based on
 or incorporates Python or any part thereof, and wants to make

Modified: python/branches/py3k-cdecimal/Lib/_abcoll.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/_abcoll.py	(original)
+++ python/branches/py3k-cdecimal/Lib/_abcoll.py	Sun Jan  2 13:18:37 2011
@@ -90,7 +90,8 @@
     @classmethod
     def __subclasshook__(cls, C):
         if cls is Iterator:
-            if any("__next__" in B.__dict__ for B in C.__mro__):
+            if (any("__next__" in B.__dict__ for B in C.__mro__) and
+                any("__iter__" in B.__dict__ for B in C.__mro__)):
                 return True
         return NotImplemented
 

Modified: python/branches/py3k-cdecimal/Lib/_pyio.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/_pyio.py	(original)
+++ python/branches/py3k-cdecimal/Lib/_pyio.py	Sun Jan  2 13:18:37 2011
@@ -676,7 +676,7 @@
     """
 
     def __init__(self, raw):
-        self.raw = raw
+        self._raw = raw
 
     ### Positioning ###
 
@@ -720,8 +720,8 @@
         if self.raw is None:
             raise ValueError("raw stream already detached")
         self.flush()
-        raw = self.raw
-        self.raw = None
+        raw = self._raw
+        self._raw = None
         return raw
 
     ### Inquiries ###
@@ -736,6 +736,10 @@
         return self.raw.writable()
 
     @property
+    def raw(self):
+        return self._raw
+
+    @property
     def closed(self):
         return self.raw.closed
 
@@ -1465,7 +1469,7 @@
             if not isinstance(errors, str):
                 raise ValueError("invalid errors: %r" % errors)
 
-        self.buffer = buffer
+        self._buffer = buffer
         self._line_buffering = line_buffering
         self._encoding = encoding
         self._errors = errors
@@ -1520,6 +1524,10 @@
     def line_buffering(self):
         return self._line_buffering
 
+    @property
+    def buffer(self):
+        return self._buffer
+
     def seekable(self):
         return self._seekable
 
@@ -1734,8 +1742,8 @@
         if self.buffer is None:
             raise ValueError("buffer is already detached")
         self.flush()
-        buffer = self.buffer
-        self.buffer = None
+        buffer = self._buffer
+        self._buffer = None
         return buffer
 
     def seek(self, cookie, whence=0):

Modified: python/branches/py3k-cdecimal/Lib/_weakrefset.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/_weakrefset.py	(original)
+++ python/branches/py3k-cdecimal/Lib/_weakrefset.py	Sun Jan  2 13:18:37 2011
@@ -66,7 +66,11 @@
         return sum(x() is not None for x in self.data)
 
     def __contains__(self, item):
-        return ref(item) in self.data
+        try:
+            wr = ref(item)
+        except TypeError:
+            return False
+        return wr in self.data
 
     def __reduce__(self):
         return (self.__class__, (list(self),),

Modified: python/branches/py3k-cdecimal/Lib/argparse.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/argparse.py	(original)
+++ python/branches/py3k-cdecimal/Lib/argparse.py	Sun Jan  2 13:18:37 2011
@@ -88,7 +88,7 @@
 import sys as _sys
 import textwrap as _textwrap
 
-from gettext import gettext as _
+from gettext import gettext as _, ngettext
 
 
 def _callable(obj):
@@ -1023,9 +1023,13 @@
 
     class _ChoicesPseudoAction(Action):
 
-        def __init__(self, name, help):
+        def __init__(self, name, aliases, help):
+            metavar = dest = name
+            if aliases:
+                metavar += ' (%s)' % ', '.join(aliases)
             sup = super(_SubParsersAction._ChoicesPseudoAction, self)
-            sup.__init__(option_strings=[], dest=name, help=help)
+            sup.__init__(option_strings=[], dest=dest, help=help,
+                         metavar=metavar)
 
     def __init__(self,
                  option_strings,
@@ -1053,15 +1057,22 @@
         if kwargs.get('prog') is None:
             kwargs['prog'] = '%s %s' % (self._prog_prefix, name)
 
+        aliases = kwargs.pop('aliases', ())
+
         # create a pseudo-action to hold the choice help
         if 'help' in kwargs:
             help = kwargs.pop('help')
-            choice_action = self._ChoicesPseudoAction(name, help)
+            choice_action = self._ChoicesPseudoAction(name, aliases, help)
             self._choices_actions.append(choice_action)
 
         # create the parser and add it to the map
         parser = self._parser_class(**kwargs)
         self._name_parser_map[name] = parser
+
+        # make parser available under aliases also
+        for alias in aliases:
+            self._name_parser_map[alias] = parser
+
         return parser
 
     def _get_subactions(self):
@@ -1079,8 +1090,9 @@
         try:
             parser = self._name_parser_map[parser_name]
         except KeyError:
-            tup = parser_name, ', '.join(self._name_parser_map)
-            msg = _('unknown parser %r (choices: %s)' % tup)
+            args = {'parser_name': parser_name,
+                    'choices': ', '.join(self._name_parser_map)}
+            msg = _('unknown parser %(parser_name)r (choices: %(choices)s)') % args
             raise ArgumentError(self, msg)
 
         # parse all the remaining options into the namespace
@@ -1121,7 +1133,7 @@
             elif 'w' in self._mode:
                 return _sys.stdout
             else:
-                msg = _('argument "-" with mode %r' % self._mode)
+                msg = _('argument "-" with mode %r') % self._mode
                 raise ValueError(msg)
 
         # all other arguments are used as file names
@@ -1380,10 +1392,11 @@
         for option_string in args:
             # error on strings that don't start with an appropriate prefix
             if not option_string[0] in self.prefix_chars:
-                msg = _('invalid option string %r: '
-                        'must start with a character %r')
-                tup = option_string, self.prefix_chars
-                raise ValueError(msg % tup)
+                args = {'option': option_string,
+                        'prefix_chars': self.prefix_chars}
+                msg = _('invalid option string %(option)r: '
+                        'must start with a character %(prefix_chars)r')
+                raise ValueError(msg % args)
 
             # strings starting with two prefix characters are long options
             option_strings.append(option_string)
@@ -1436,7 +1449,9 @@
             conflict_handler(action, confl_optionals)
 
     def _handle_conflict_error(self, action, conflicting_actions):
-        message = _('conflicting option string(s): %s')
+        message = ngettext('conflicting option string: %s',
+                           'conflicting option strings: %s',
+                           len(conflicting_actions))
         conflict_string = ', '.join([option_string
                                      for option_string, action
                                      in conflicting_actions])
@@ -1993,7 +2008,9 @@
                 OPTIONAL: _('expected at most one argument'),
                 ONE_OR_MORE: _('expected at least one argument'),
             }
-            default = _('expected %s argument(s)') % action.nargs
+            default = ngettext('expected %s argument',
+                               'expected %s arguments',
+                               action.nargs) % action.nargs
             msg = nargs_errors.get(action.nargs, default)
             raise ArgumentError(action, msg)
 
@@ -2049,8 +2066,9 @@
         if len(option_tuples) > 1:
             options = ', '.join([option_string
                 for action, option_string, explicit_arg in option_tuples])
-            tup = arg_string, options
-            self.error(_('ambiguous option: %s could match %s') % tup)
+            args = {'option': arg_string, 'matches': options}
+            msg = _('ambiguous option: %(option)s could match %(matches)s')
+            self.error(msg % args)
 
         # if exactly one action matched, this segmentation is good,
         # so return the parsed action
@@ -2229,8 +2247,9 @@
         # TypeErrors or ValueErrors also indicate errors
         except (TypeError, ValueError):
             name = getattr(action.type, '__name__', repr(action.type))
-            msg = _('invalid %s value: %r')
-            raise ArgumentError(action, msg % (name, arg_string))
+            args = {'type': name, 'value': arg_string}
+            msg = _('invalid %(type)s value: %(value)r')
+            raise ArgumentError(action, msg % args)
 
         # return the converted value
         return result
@@ -2238,9 +2257,10 @@
     def _check_value(self, action, value):
         # converted value must be one of the choices (if specified)
         if action.choices is not None and value not in action.choices:
-            tup = value, ', '.join(map(repr, action.choices))
-            msg = _('invalid choice: %r (choose from %s)') % tup
-            raise ArgumentError(action, msg)
+            args = {'value': value,
+                    'choices': ', '.join(map(repr, action.choices))}
+            msg = _('invalid choice: %(value)r (choose from %(choices)s)')
+            raise ArgumentError(action, msg % args)
 
     # =======================
     # Help-formatting methods
@@ -2332,4 +2352,5 @@
         should either exit or raise an exception.
         """
         self.print_usage(_sys.stderr)
-        self.exit(2, _('%s: error: %s\n') % (self.prog, message))
+        args = {'prog': self.prog, 'message': message}
+        self.exit(2, _('%(prog)s: error: %(message)s\n') % args)

Modified: python/branches/py3k-cdecimal/Lib/bdb.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/bdb.py	(original)
+++ python/branches/py3k-cdecimal/Lib/bdb.py	Sun Jan  2 13:18:37 2011
@@ -3,16 +3,14 @@
 import fnmatch
 import sys
 import os
-import types
 
-__all__ = ["BdbQuit","Bdb","Breakpoint"]
+__all__ = ["BdbQuit", "Bdb", "Breakpoint"]
 
 class BdbQuit(Exception):
-    """Exception to give up completely"""
+    """Exception to give up completely."""
 
 
 class Bdb:
-
     """Generic Python debugger base class.
 
     This class takes care of details of the trace facility;
@@ -120,14 +118,14 @@
 
     def break_here(self, frame):
         filename = self.canonic(frame.f_code.co_filename)
-        if not filename in self.breaks:
+        if filename not in self.breaks:
             return False
         lineno = frame.f_lineno
-        if not lineno in self.breaks[filename]:
+        if lineno not in self.breaks[filename]:
             # The line itself has no breakpoint, but maybe the line is the
             # first line of a function with breakpoint set by function name.
             lineno = frame.f_code.co_firstlineno
-            if not lineno in self.breaks[filename]:
+            if lineno not in self.breaks[filename]:
                 return False
 
         # flag says ok to delete temp. bp
@@ -170,7 +168,7 @@
     def _set_stopinfo(self, stopframe, returnframe, stoplineno=0):
         self.stopframe = stopframe
         self.returnframe = returnframe
-        self.quitting = 0
+        self.quitting = False
         # stoplineno >= 0 means: stop at line >= the stoplineno
         # stoplineno -1 means: don't stop at all
         self.stoplineno = stoplineno
@@ -227,7 +225,7 @@
     def set_quit(self):
         self.stopframe = self.botframe
         self.returnframe = None
-        self.quitting = 1
+        self.quitting = True
         sys.settrace(None)
 
     # Derived classes and clients can call the following methods
@@ -237,47 +235,47 @@
     # Call self.get_*break*() to see the breakpoints or better
     # for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().
 
-    def set_break(self, filename, lineno, temporary=0, cond = None,
+    def set_break(self, filename, lineno, temporary=False, cond=None,
                   funcname=None):
         filename = self.canonic(filename)
         import linecache # Import as late as possible
         line = linecache.getline(filename, lineno)
         if not line:
-            return 'Line %s:%d does not exist' % (filename,
-                                   lineno)
-        if not filename in self.breaks:
-            self.breaks[filename] = []
-        list = self.breaks[filename]
-        if not lineno in list:
+            return 'Line %s:%d does not exist' % (filename, lineno)
+        list = self.breaks.setdefault(filename, [])
+        if lineno not in list:
             list.append(lineno)
         bp = Breakpoint(filename, lineno, temporary, cond, funcname)
 
+    def _prune_breaks(self, filename, lineno):
+        if (filename, lineno) not in Breakpoint.bplist:
+            self.breaks[filename].remove(lineno)
+        if not self.breaks[filename]:
+            del self.breaks[filename]
+
     def clear_break(self, filename, lineno):
         filename = self.canonic(filename)
-        if not filename in self.breaks:
+        if filename not in self.breaks:
             return 'There are no breakpoints in %s' % filename
         if lineno not in self.breaks[filename]:
-            return 'There is no breakpoint at %s:%d' % (filename,
-                                    lineno)
+            return 'There is no breakpoint at %s:%d' % (filename, lineno)
         # If there's only one bp in the list for that file,line
         # pair, then remove the breaks entry
         for bp in Breakpoint.bplist[filename, lineno][:]:
             bp.deleteMe()
-        if (filename, lineno) not in Breakpoint.bplist:
-            self.breaks[filename].remove(lineno)
-        if not self.breaks[filename]:
-            del self.breaks[filename]
+        self._prune_breaks(filename, lineno)
 
     def clear_bpbynumber(self, arg):
         try:
             bp = self.get_bpbynumber(arg)
         except ValueError as err:
             return str(err)
-        self.clear_break(bp.file, bp.line)
+        bp.deleteMe()
+        self._prune_breaks(bp.file, bp.line)
 
     def clear_all_file_breaks(self, filename):
         filename = self.canonic(filename)
-        if not filename in self.breaks:
+        if filename not in self.breaks:
             return 'There are no breakpoints in %s' % filename
         for line in self.breaks[filename]:
             blist = Breakpoint.bplist[filename, line]
@@ -350,31 +348,30 @@
             i = max(0, len(stack) - 1)
         return stack, i
 
-    #
-
     def format_stack_entry(self, frame_lineno, lprefix=': '):
         import linecache, reprlib
         frame, lineno = frame_lineno
         filename = self.canonic(frame.f_code.co_filename)
         s = '%s(%r)' % (filename, lineno)
         if frame.f_code.co_name:
-            s = s + frame.f_code.co_name
+            s += frame.f_code.co_name
         else:
-            s = s + ""
+            s += ""
         if '__args__' in frame.f_locals:
             args = frame.f_locals['__args__']
         else:
             args = None
         if args:
-            s = s + reprlib.repr(args)
+            s += reprlib.repr(args)
         else:
-            s = s + '()'
+            s += '()'
         if '__return__' in frame.f_locals:
             rv = frame.f_locals['__return__']
-            s = s + '->'
-            s = s + reprlib.repr(rv)
+            s += '->'
+            s += reprlib.repr(rv)
         line = linecache.getline(filename, lineno, frame.f_globals)
-        if line: s = s + lprefix + line.strip()
+        if line:
+            s += lprefix + line.strip()
         return s
 
     # The following methods can be called by clients to use
@@ -394,7 +391,7 @@
         except BdbQuit:
             pass
         finally:
-            self.quitting = 1
+            self.quitting = True
             sys.settrace(None)
 
     def runeval(self, expr, globals=None, locals=None):
@@ -410,7 +407,7 @@
         except BdbQuit:
             pass
         finally:
-            self.quitting = 1
+            self.quitting = True
             sys.settrace(None)
 
     def runctx(self, cmd, globals, locals):
@@ -428,7 +425,7 @@
         except BdbQuit:
             pass
         finally:
-            self.quitting = 1
+            self.quitting = True
             sys.settrace(None)
         return res
 
@@ -438,8 +435,7 @@
 
 
 class Breakpoint:
-
-    """Breakpoint class
+    """Breakpoint class.
 
     Implements temporary breakpoints, ignore counts, disabling and
     (re)-enabling, and conditionals.
@@ -461,7 +457,7 @@
                 # index 0 is unused, except for marking an
                 # effective break .... see effective()
 
-    def __init__(self, file, line, temporary=0, cond=None, funcname=None):
+    def __init__(self, file, line, temporary=False, cond=None, funcname=None):
         self.funcname = funcname
         # Needed if funcname is not None.
         self.func_first_executable_line = None
@@ -469,11 +465,11 @@
         self.line = line
         self.temporary = temporary
         self.cond = cond
-        self.enabled = 1
+        self.enabled = True
         self.ignore = 0
         self.hits = 0
         self.number = Breakpoint.next
-        Breakpoint.next = Breakpoint.next + 1
+        Breakpoint.next += 1
         # Build the two lists
         self.bpbynumber.append(self)
         if (file, line) in self.bplist:
@@ -481,7 +477,6 @@
         else:
             self.bplist[file, line] = [self]
 
-
     def deleteMe(self):
         index = (self.file, self.line)
         self.bpbynumber[self.number] = None   # No longer in list
@@ -491,10 +486,10 @@
             del self.bplist[index]
 
     def enable(self):
-        self.enabled = 1
+        self.enabled = True
 
     def disable(self):
-        self.enabled = 0
+        self.enabled = False
 
     def bpprint(self, out=None):
         if out is None:
@@ -565,49 +560,44 @@
     that indicates if it is ok to delete a temporary bp.
 
     """
-    possibles = Breakpoint.bplist[file,line]
-    for i in range(0, len(possibles)):
-        b = possibles[i]
-        if b.enabled == 0:
+    possibles = Breakpoint.bplist[file, line]
+    for b in possibles:
+        if not b.enabled:
             continue
         if not checkfuncname(b, frame):
             continue
         # Count every hit when bp is enabled
-        b.hits = b.hits + 1
+        b.hits += 1
         if not b.cond:
-            # If unconditional, and ignoring,
-            # go on to next, else break
+            # If unconditional, and ignoring go on to next, else break
             if b.ignore > 0:
-                b.ignore = b.ignore -1
+                b.ignore -= 1
                 continue
             else:
-                # breakpoint and marker that's ok
-                # to delete if temporary
-                return (b,1)
+                # breakpoint and marker that it's ok to delete if temporary
+                return (b, True)
         else:
             # Conditional bp.
             # Ignore count applies only to those bpt hits where the
             # condition evaluates to true.
             try:
-                val = eval(b.cond, frame.f_globals,
-                       frame.f_locals)
+                val = eval(b.cond, frame.f_globals, frame.f_locals)
                 if val:
                     if b.ignore > 0:
-                        b.ignore = b.ignore -1
+                        b.ignore -= 1
                         # continue
                     else:
-                        return (b,1)
+                        return (b, True)
                 # else:
                 #   continue
             except:
-                # if eval fails, most conservative
-                # thing is to stop on breakpoint
-                # regardless of ignore count.
-                # Don't delete temporary,
-                # as another hint to user.
-                return (b,0)
+                # if eval fails, most conservative thing is to stop on
+                # breakpoint regardless of ignore count.  Don't delete
+                # temporary, as another hint to user.
+                return (b, False)
     return (None, None)
 
+
 # -------------------- testing --------------------
 
 class Tdb(Bdb):
@@ -640,5 +630,3 @@
 def test():
     t = Tdb()
     t.run('import bdb; bdb.foo(10)')
-
-# end

Modified: python/branches/py3k-cdecimal/Lib/codecs.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/codecs.py	(original)
+++ python/branches/py3k-cdecimal/Lib/codecs.py	Sun Jan  2 13:18:37 2011
@@ -396,6 +396,8 @@
 
 class StreamReader(Codec):
 
+    charbuffertype = str
+
     def __init__(self, stream, errors='strict'):
 
         """ Creates a StreamReader instance.
@@ -417,9 +419,8 @@
         self.stream = stream
         self.errors = errors
         self.bytebuffer = b""
-        # For str->str decoding this will stay a str
-        # For str->unicode decoding the first read will promote it to unicode
-        self.charbuffer = ""
+        self._empty_charbuffer = self.charbuffertype()
+        self.charbuffer = self._empty_charbuffer
         self.linebuffer = None
 
     def decode(self, input, errors='strict'):
@@ -455,7 +456,7 @@
         """
         # If we have lines cached, first merge them back into characters
         if self.linebuffer:
-            self.charbuffer = "".join(self.linebuffer)
+            self.charbuffer = self._empty_charbuffer.join(self.linebuffer)
             self.linebuffer = None
 
         # read until we get the required number of characters (if available)
@@ -498,7 +499,7 @@
         if chars < 0:
             # Return everything we've got
             result = self.charbuffer
-            self.charbuffer = ""
+            self.charbuffer = self._empty_charbuffer
         else:
             # Return the first chars characters
             result = self.charbuffer[:chars]
@@ -529,7 +530,7 @@
             return line
 
         readsize = size or 72
-        line = ""
+        line = self._empty_charbuffer
         # If size is given, we call read() only once
         while True:
             data = self.read(readsize, firstline=True)
@@ -537,7 +538,8 @@
                 # If we're at a "\r" read one extra character (which might
                 # be a "\n") to get a proper line ending. If the stream is
                 # temporarily exhausted we return the wrong line ending.
-                if data.endswith("\r"):
+                if (isinstance(data, str) and data.endswith("\r")) or \
+                   (isinstance(data, bytes) and data.endswith(b"\r")):
                     data += self.read(size=1, chars=1)
 
             line += data
@@ -563,7 +565,8 @@
                 line0withoutend = lines[0].splitlines(False)[0]
                 if line0withend != line0withoutend: # We really have a line end
                     # Put the rest back together and keep it until the next call
-                    self.charbuffer = "".join(lines[1:]) + self.charbuffer
+                    self.charbuffer = self._empty_charbuffer.join(lines[1:]) + \
+                                      self.charbuffer
                     if keepends:
                         line = line0withend
                     else:
@@ -574,7 +577,7 @@
                 if line and not keepends:
                     line = line.splitlines(False)[0]
                 break
-            if readsize<8000:
+            if readsize < 8000:
                 readsize *= 2
         return line
 
@@ -603,7 +606,7 @@
 
         """
         self.bytebuffer = b""
-        self.charbuffer = ""
+        self.charbuffer = self._empty_charbuffer
         self.linebuffer = None
 
     def seek(self, offset, whence=0):

Modified: python/branches/py3k-cdecimal/Lib/collections.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/collections.py	(original)
+++ python/branches/py3k-cdecimal/Lib/collections.py	Sun Jan  2 13:18:37 2011
@@ -22,7 +22,7 @@
 class _Link(object):
     __slots__ = 'prev', 'next', 'key', '__weakref__'
 
-class OrderedDict(dict, MutableMapping):
+class OrderedDict(dict):
     'Dictionary that remembers insertion order'
     # An inherited dict maps keys to values.
     # The inherited dict provides __getitem__, __len__, __contains__, and get.
@@ -52,7 +52,7 @@
             self.__root = root = _proxy(self.__hardroot)
             root.prev = root.next = root
             self.__map = {}
-        self.update(*args, **kwds)
+        self.__update(*args, **kwds)
 
     def __setitem__(self, key, value,
                     dict_setitem=dict.__setitem__, proxy=_proxy, Link=_Link):
@@ -171,14 +171,30 @@
         size += sizeof(self.__root) * n         # proxy objects
         return size
 
-    setdefault = MutableMapping.setdefault
-    update = MutableMapping.update
-    pop = MutableMapping.pop
+    update = __update = MutableMapping.update
     keys = MutableMapping.keys
     values = MutableMapping.values
     items = MutableMapping.items
     __ne__ = MutableMapping.__ne__
 
+    __marker = object()
+
+    def pop(self, key, default=__marker):
+        if key in self:
+            result = self[key]
+            del self[key]
+            return result
+        if default is self.__marker:
+            raise KeyError(key)
+        return default
+
+    def setdefault(self, key, default=None):
+        'OD.setdefault(k[,d]) -> OD.get(k,d), also set OD[k]=d if k not in OD'
+        if key in self:
+            return self[key]
+        self[key] = default
+        return default
+
     @_recursive_repr()
     def __repr__(self):
         'od.__repr__() <==> repr(od)'
@@ -334,21 +350,32 @@
 ###  Counter
 ########################################################################
 
+def _count_elements(mapping, iterable):
+    'Tally elements from the iterable.'
+    mapping_get = mapping.get
+    for elem in iterable:
+        mapping[elem] = mapping_get(elem, 0) + 1
+
+try:                                    # Load C helper function if available
+    from _collections import _count_elements
+except ImportError:
+    pass
+
 class Counter(dict):
     '''Dict subclass for counting hashable items.  Sometimes called a bag
     or multiset.  Elements are stored as dictionary keys and their counts
     are stored as dictionary values.
 
-    >>> c = Counter('abracadabra')      # count elements from a string
+    >>> c = Counter('abcdeabcdabcaba')  # count elements from a string
 
     >>> c.most_common(3)                # three most common elements
-    [('a', 5), ('r', 2), ('b', 2)]
+    [('a', 5), ('b', 4), ('c', 3)]
     >>> sorted(c)                       # list all unique elements
-    ['a', 'b', 'c', 'd', 'r']
+    ['a', 'b', 'c', 'd', 'e']
     >>> ''.join(sorted(c.elements()))   # list elements with repetitions
-    'aaaaabbcdrr'
+    'aaaaabbbbcccdde'
     >>> sum(c.values())                 # total of all counts
-    11
+    15
 
     >>> c['a']                          # count of letter 'a'
     5
@@ -356,8 +383,8 @@
     ...     c[elem] += 1                # by adding 1 to each element's count
     >>> c['a']                          # now there are seven 'a'
     7
-    >>> del c['r']                      # remove all 'r'
-    >>> c['r']                          # now there are zero 'r'
+    >>> del c['b']                      # remove all 'b'
+    >>> c['b']                          # now there are zero 'b'
     0
 
     >>> d = Counter('simsalabim')       # make another counter
@@ -396,6 +423,7 @@
         >>> c = Counter(a=4, b=2)                   # a new counter from keyword args
 
         '''
+        super().__init__()
         self.update(iterable, **kwds)
 
     def __missing__(self, key):
@@ -407,8 +435,8 @@
         '''List the n most common elements and their counts from the most
         common to the least.  If n is None, then list all element counts.
 
-        >>> Counter('abracadabra').most_common(3)
-        [('a', 5), ('r', 2), ('b', 2)]
+        >>> Counter('abcdeabcdabcaba').most_common(3)
+        [('a', 5), ('b', 4), ('c', 3)]
 
         '''
         # Emulate Bag.sortedByCount from Smalltalk
@@ -474,11 +502,9 @@
                     for elem, count in iterable.items():
                         self[elem] = count + self_get(elem, 0)
                 else:
-                    dict.update(self, iterable) # fast path when counter is empty
+                    super().update(iterable) # fast path when counter is empty
             else:
-                self_get = self.get
-                for elem in iterable:
-                    self[elem] = 1 + self_get(elem, 0)
+                _count_elements(self, iterable)
         if kwds:
             self.update(kwds)
 
@@ -516,7 +542,7 @@
     def __delitem__(self, elem):
         'Like dict.__delitem__() but does not raise KeyError for missing values.'
         if elem in self:
-            dict.__delitem__(self, elem)
+            super().__delitem__(elem)
 
     def __repr__(self):
         if not self:

Modified: python/branches/py3k-cdecimal/Lib/compileall.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/compileall.py	(original)
+++ python/branches/py3k-cdecimal/Lib/compileall.py	Sun Jan  2 13:18:37 2011
@@ -19,19 +19,20 @@
 
 __all__ = ["compile_dir","compile_file","compile_path"]
 
-def compile_dir(dir, maxlevels=10, ddir=None,
-                force=False, rx=None, quiet=False, legacy=False):
+def compile_dir(dir, maxlevels=10, ddir=None, force=False, rx=None,
+                quiet=False, legacy=False, optimize=-1):
     """Byte-compile all modules in the given directory tree.
 
     Arguments (only dir is required):
 
     dir:       the directory to byte-compile
     maxlevels: maximum recursion level (default 10)
-    ddir:      if given, purported directory name (this is the
-               directory name that will show up in error messages)
+    ddir:      the directory that will be prepended to the path to the
+               file as it is compiled into each byte-code file.
     force:     if True, force compilation, even if timestamps are up-to-date
     quiet:     if True, be quiet during compilation
     legacy:    if True, produce legacy pyc paths instead of PEP 3147 paths
+    optimize:  optimization level or -1 for level of the interpreter
     """
     if not quiet:
         print('Listing', dir, '...')
@@ -51,7 +52,8 @@
         else:
             dfile = None
         if not os.path.isdir(fullname):
-            if not compile_file(fullname, ddir, force, rx, quiet, legacy):
+            if not compile_file(fullname, ddir, force, rx, quiet,
+                                legacy, optimize):
                 success = 0
         elif (maxlevels > 0 and name != os.curdir and name != os.pardir and
               os.path.isdir(fullname) and not os.path.islink(fullname)):
@@ -60,15 +62,19 @@
                 success = 0
     return success
 
-def compile_file(fullname, ddir=None, force=0, rx=None, quiet=False,
-                 legacy=False):
-    """Byte-compile file.
+def compile_file(fullname, ddir=None, force=False, rx=None, quiet=False,
+                 legacy=False, optimize=-1):
+    """Byte-compile one file.
+
+    Arguments (only fullname is required):
+
     fullname:  the file to byte-compile
-    ddir:      if given, purported directory name (this is the
-               directory name that will show up in error messages)
+    ddir:      if given, the directory name compiled in to the
+               byte-code file.
     force:     if True, force compilation, even if timestamps are up-to-date
     quiet:     if True, be quiet during compilation
     legacy:    if True, produce legacy pyc paths instead of PEP 3147 paths
+    optimize:  optimization level or -1 for level of the interpreter
     """
     success = 1
     name = os.path.basename(fullname)
@@ -84,7 +90,11 @@
         if legacy:
             cfile = fullname + ('c' if __debug__ else 'o')
         else:
-            cfile = imp.cache_from_source(fullname)
+            if optimize >= 0:
+                cfile = imp.cache_from_source(fullname,
+                                              debug_override=not optimize)
+            else:
+                cfile = imp.cache_from_source(fullname)
             cache_dir = os.path.dirname(cfile)
         head, tail = name[:-3], name[-3:]
         if tail == '.py':
@@ -101,7 +111,8 @@
             if not quiet:
                 print('Compiling', fullname, '...')
             try:
-                ok = py_compile.compile(fullname, cfile, dfile, True)
+                ok = py_compile.compile(fullname, cfile, dfile, True,
+                                        optimize=optimize)
             except py_compile.PyCompileError as err:
                 if quiet:
                     print('*** Error compiling', fullname, '...')
@@ -126,7 +137,7 @@
     return success
 
 def compile_path(skip_curdir=1, maxlevels=0, force=False, quiet=False,
-                 legacy=False):
+                 legacy=False, optimize=-1):
     """Byte-compile all module on sys.path.
 
     Arguments (all optional):
@@ -136,6 +147,7 @@
     force: as for compile_dir() (default False)
     quiet: as for compile_dir() (default False)
     legacy: as for compile_dir() (default False)
+    optimize: as for compile_dir() (default -1)
     """
     success = 1
     for dir in sys.path:
@@ -144,7 +156,7 @@
         else:
             success = success and compile_dir(dir, maxlevels, None,
                                               force, quiet=quiet,
-                                              legacy=legacy)
+                                              legacy=legacy, optimize=optimize)
     return success
 
 
@@ -154,60 +166,73 @@
 
     parser = argparse.ArgumentParser(
         description='Utilities to support installing Python libraries.')
-    parser.add_argument('-l', action='store_const', default=10, const=0,
-                        dest='maxlevels', help="don't recurse down")
+    parser.add_argument('-l', action='store_const', const=0,
+                        default=10, dest='maxlevels',
+                        help="don't recurse into subdirectories")
     parser.add_argument('-f', action='store_true', dest='force',
                         help='force rebuild even if timestamps are up to date')
     parser.add_argument('-q', action='store_true', dest='quiet',
-                        help='reduce output')
+                        help='output only error messages')
     parser.add_argument('-b', action='store_true', dest='legacy',
-                        help='produce legacy byte-compiled file paths')
+                        help='use legacy (pre-PEP3147) compiled file locations')
     parser.add_argument('-d', metavar='DESTDIR',  dest='ddir', default=None,
-                        help=('purported directory name for error messages; '
-                              'if no directory arguments, -l sys.path '
-                              'is assumed.'))
+                        help=('directory to prepend to file paths for use in '
+                              'compile time tracebacks and in runtime '
+                              'tracebacks in cases where the source file is '
+                              'unavailable'))
     parser.add_argument('-x', metavar='REGEXP', dest='rx', default=None,
-                        help=('skip files matching the regular expression.\n\t'
+                        help=('skip files matching the regular expression. '
                               'The regexp is searched for in the full path '
-                              'of the file'))
+                              'to each file considered for compilation.'))
     parser.add_argument('-i', metavar='FILE', dest='flist',
-                        help='expand the list with the content of FILE.')
-    parser.add_argument('compile_dest', metavar='FILE|DIR', nargs='?')
+                        help=('add all the files and directories listed in '
+                              'FILE to the list considered for compilation. '
+                              'If "-", names are read from stdin.'))
+    parser.add_argument('compile_dest', metavar='FILE|DIR', nargs='*',
+                        help=('zero or more file and directory names '
+                              'to compile; if no arguments given, defaults '
+                              'to the equivalent of -l sys.path'))
     args = parser.parse_args()
 
-    if (args.ddir and args.compile_dest != 1 and
-        not os.path.isdir(args.compile_dest)):
-        raise argparse.ArgumentError(
-            "-d destdir requires exactly one directory argument")
+    compile_dests = args.compile_dest
+
+    if (args.ddir and (len(compile_dests) != 1
+            or not os.path.isdir(compile_dests[0]))):
+        parser.exit('-d destdir requires exactly one directory argument')
     if args.rx:
         import re
         args.rx = re.compile(args.rx)
 
     # if flist is provided then load it
-    compile_dests = [args.compile_dest]
     if args.flist:
-        with open(args.flist) as f:
-            files = f.read().split()
-            compile_dests.extend(files)
+        try:
+            with (sys.stdin if args.flist=='-' else open(args.flist)) as f:
+                for line in f:
+                    compile_dests.append(line.strip())
+        except EnvironmentError:
+            print("Error reading file list {}".format(args.flist))
+            return False
 
+    success = True
     try:
         if compile_dests:
             for dest in compile_dests:
-                if os.path.isdir(dest):
+                if os.path.isfile(dest):
+                    if not compile_file(dest, args.ddir, args.force, args.rx,
+                                        args.quiet, args.legacy):
+                        success = False
+                else:
                     if not compile_dir(dest, args.maxlevels, args.ddir,
                                        args.force, args.rx, args.quiet,
                                        args.legacy):
-                        return 0
-                else:
-                    if not compile_file(dest, args.ddir, args.force, args.rx,
-                                        args.quiet, args.legacy):
-                        return 0
+                        success = False
+            return success
         else:
             return compile_path(legacy=args.legacy)
     except KeyboardInterrupt:
         print("\n[interrupted]")
-        return 0
-    return 1
+        return False
+    return True
 
 
 if __name__ == '__main__':

Modified: python/branches/py3k-cdecimal/Lib/concurrent/futures/_base.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/concurrent/futures/_base.py	(original)
+++ python/branches/py3k-cdecimal/Lib/concurrent/futures/_base.py	Sun Jan  2 13:18:37 2011
@@ -41,8 +41,6 @@
 
 # Logger for internal use by the futures package.
 LOGGER = logging.getLogger("concurrent.futures")
-STDERR_HANDLER = logging.StreamHandler()
-LOGGER.addHandler(STDERR_HANDLER)
 
 class Error(Exception):
     """Base class for all future-related exceptions."""

Modified: python/branches/py3k-cdecimal/Lib/concurrent/futures/process.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/concurrent/futures/process.py	(original)
+++ python/branches/py3k-cdecimal/Lib/concurrent/futures/process.py	Sun Jan  2 13:18:37 2011
@@ -118,7 +118,7 @@
 def _process_worker(call_queue, result_queue, shutdown):
     """Evaluates calls from call_queue and places the results in result_queue.
 
-    This worker is run in a seperate process.
+    This worker is run in a separate process.
 
     Args:
         call_queue: A multiprocessing.Queue of _CallItems that will be read and

Modified: python/branches/py3k-cdecimal/Lib/configparser.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/configparser.py	(original)
+++ python/branches/py3k-cdecimal/Lib/configparser.py	Sun Jan  2 13:18:37 2011
@@ -4,29 +4,20 @@
 and followed by "name: value" entries, with continuations and such in
 the style of RFC 822.
 
-The option values can contain format strings which refer to other values in
-the same section, or values in a special [DEFAULT] section.
-
-For example:
-
-    something: %(dir)s/whatever
-
-would resolve the "%(dir)s" to the value of dir.  All reference
-expansions are done late, on demand.
-
 Intrinsic defaults can be specified by passing them into the
 ConfigParser constructor as a dictionary.
 
 class:
 
 ConfigParser -- responsible for parsing a list of
-                configuration files, and managing the parsed database.
+                    configuration files, and managing the parsed database.
 
     methods:
 
     __init__(defaults=None, dict_type=_default_dict, allow_no_value=False,
-             delimiters=('=', ':'), comment_prefixes=_COMPATIBLE,
-             strict=False, empty_lines_in_values=True):
+             delimiters=('=', ':'), comment_prefixes=('#', ';'),
+             inline_comment_prefixes=None, strict=True,
+             empty_lines_in_values=True):
         Create the parser. When `defaults' is given, it is initialized into the
         dictionary or intrinsic defaults. The keys must be strings, the values
         must be appropriate for %()s string interpolation.
@@ -39,11 +30,15 @@
         that divide keys from values.
 
         When `comment_prefixes' is given, it will be used as the set of
-        substrings that prefix comments in a line.
+        substrings that prefix comments in empty lines. Comments can be
+        indented.
+
+        When `inline_comment_prefixes' is given, it will be used as the set of
+        substrings that prefix comments in non-empty lines.
 
         When `strict` is True, the parser won't allow for any section or option
         duplicates while reading from a single source (file, string or
-        dictionary). Default is False.
+        dictionary). Default is True.
 
         When `empty_lines_in_values' is False (default: True), each empty line
         marks the end of an option. Otherwise, internal empty lines of
@@ -103,8 +98,10 @@
         insensitively defined as 0, false, no, off for False, and 1, true,
         yes, on for True).  Returns False or True.
 
-    items(section, raw=False, vars=None)
-        Return a list of tuples with (name, value) for each option
+    items(section=_UNSET, raw=False, vars=None)
+        If section is given, return a list of tuples with (section_name,
+        section_proxy) for each section, including DEFAULTSECT. Otherwise,
+        return a list of tuples with (name, value) for each option
         in the section.
 
     remove_section(section)
@@ -275,9 +272,8 @@
 class InterpolationSyntaxError(InterpolationError):
     """Raised when the source text contains invalid syntax.
 
-    Current implementation raises this exception only for SafeConfigParser
-    instances when the source text into which substitutions are made
-    does not conform to the required syntax.
+    Current implementation raises this exception when the source text into
+    which substitutions are made does not conform to the required syntax.
     """
 
 
@@ -316,7 +312,7 @@
     def filename(self):
         """Deprecated, use `source'."""
         warnings.warn(
-            "This 'filename' attribute will be removed in future versions.  "
+            "The 'filename' attribute will be removed in future versions.  "
             "Use 'source' instead.",
             DeprecationWarning, stacklevel=2
         )
@@ -351,17 +347,210 @@
         self.args = (filename, lineno, line)
 
 
-# Used in parsers to denote selecting a backwards-compatible inline comment
-# character behavior (; and # are comments at the start of a line, but ; only
-# inline)
-_COMPATIBLE = object()
-
 # Used in parser getters to indicate the default behaviour when a specific
 # option is not found it to raise an exception. Created to enable `None' as
 # a valid fallback value.
 _UNSET = object()
 
 
+class Interpolation:
+    """Dummy interpolation that passes the value through with no changes."""
+
+    def before_get(self, parser, section, option, value, defaults):
+        return value
+
+    def before_set(self, parser, section, option, value):
+        return value
+
+    def before_read(self, parser, section, option, value):
+        return value
+
+    def before_write(self, parser, section, option, value):
+        return value
+
+
+class BasicInterpolation(Interpolation):
+    """Interpolation as implemented in the classic ConfigParser.
+
+    The option values can contain format strings which refer to other values in
+    the same section, or values in the special default section.
+
+    For example:
+
+        something: %(dir)s/whatever
+
+    would resolve the "%(dir)s" to the value of dir.  All reference
+    expansions are done late, on demand. If a user needs to use a bare % in
+    a configuration file, she can escape it by writing %%. Other other % usage
+    is considered a user error and raises `InterpolationSyntaxError'."""
+
+    _KEYCRE = re.compile(r"%\(([^)]+)\)s")
+
+    def before_get(self, parser, section, option, value, defaults):
+        L = []
+        self._interpolate_some(parser, option, L, value, section, defaults, 1)
+        return ''.join(L)
+
+    def before_set(self, parser, section, option, value):
+        tmp_value = value.replace('%%', '') # escaped percent signs
+        tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax
+        if '%' in tmp_value:
+            raise ValueError("invalid interpolation syntax in %r at "
+                             "position %d" % (value, tmp_value.find('%')))
+        return value
+
+    def _interpolate_some(self, parser, option, accum, rest, section, map,
+                          depth):
+        if depth > MAX_INTERPOLATION_DEPTH:
+            raise InterpolationDepthError(option, section, rest)
+        while rest:
+            p = rest.find("%")
+            if p < 0:
+                accum.append(rest)
+                return
+            if p > 0:
+                accum.append(rest[:p])
+                rest = rest[p:]
+            # p is no longer used
+            c = rest[1:2]
+            if c == "%":
+                accum.append("%")
+                rest = rest[2:]
+            elif c == "(":
+                m = self._KEYCRE.match(rest)
+                if m is None:
+                    raise InterpolationSyntaxError(option, section,
+                        "bad interpolation variable reference %r" % rest)
+                var = parser.optionxform(m.group(1))
+                rest = rest[m.end():]
+                try:
+                    v = map[var]
+                except KeyError:
+                    raise InterpolationMissingOptionError(
+                        option, section, rest, var)
+                if "%" in v:
+                    self._interpolate_some(parser, option, accum, v,
+                                           section, map, depth + 1)
+                else:
+                    accum.append(v)
+            else:
+                raise InterpolationSyntaxError(
+                    option, section,
+                    "'%%' must be followed by '%%' or '(', "
+                    "found: %r" % (rest,))
+
+
+class ExtendedInterpolation(Interpolation):
+    """Advanced variant of interpolation, supports the syntax used by
+    `zc.buildout'. Enables interpolation between sections."""
+
+    _KEYCRE = re.compile(r"\$\{([^}]+)\}")
+
+    def before_get(self, parser, section, option, value, defaults):
+        L = []
+        self._interpolate_some(parser, option, L, value, section, defaults, 1)
+        return ''.join(L)
+
+    def before_set(self, parser, section, option, value):
+        tmp_value = value.replace('$$', '') # escaped dollar signs
+        tmp_value = self._KEYCRE.sub('', tmp_value) # valid syntax
+        if '$' in tmp_value:
+            raise ValueError("invalid interpolation syntax in %r at "
+                             "position %d" % (value, tmp_value.find('%')))
+        return value
+
+    def _interpolate_some(self, parser, option, accum, rest, section, map,
+                          depth):
+        if depth > MAX_INTERPOLATION_DEPTH:
+            raise InterpolationDepthError(option, section, rest)
+        while rest:
+            p = rest.find("$")
+            if p < 0:
+                accum.append(rest)
+                return
+            if p > 0:
+                accum.append(rest[:p])
+                rest = rest[p:]
+            # p is no longer used
+            c = rest[1:2]
+            if c == "$":
+                accum.append("$")
+                rest = rest[2:]
+            elif c == "{":
+                m = self._KEYCRE.match(rest)
+                if m is None:
+                    raise InterpolationSyntaxError(option, section,
+                        "bad interpolation variable reference %r" % rest)
+                path = parser.optionxform(m.group(1)).split(':')
+                rest = rest[m.end():]
+                sect = section
+                opt = option
+                try:
+                    if len(path) == 1:
+                        opt = path[0]
+                        v = map[opt]
+                    elif len(path) == 2:
+                        sect = path[0]
+                        opt = path[1]
+                        v = parser.get(sect, opt, raw=True)
+                    else:
+                        raise InterpolationSyntaxError(
+                            option, section,
+                            "More than one ':' found: %r" % (rest,))
+                except (KeyError, NoSectionError, NoOptionError):
+                    raise InterpolationMissingOptionError(
+                        option, section, rest, ":".join(path))
+                if "$" in v:
+                    self._interpolate_some(parser, opt, accum, v, sect,
+                                           dict(parser.items(sect, raw=True)),
+                                           depth + 1)
+                else:
+                    accum.append(v)
+            else:
+                raise InterpolationSyntaxError(
+                    option, section,
+                    "'$' must be followed by '$' or '{', "
+                    "found: %r" % (rest,))
+
+
+class LegacyInterpolation(Interpolation):
+    """Deprecated interpolation used in old versions of ConfigParser.
+    Use BasicInterpolation or ExtendedInterpolation instead."""
+
+    _KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
+
+    def before_get(self, parser, section, option, value, vars):
+        rawval = value
+        depth = MAX_INTERPOLATION_DEPTH
+        while depth:                    # Loop through this until it's done
+            depth -= 1
+            if value and "%(" in value:
+                replace = functools.partial(self._interpolation_replace,
+                                            parser=parser)
+                value = self._KEYCRE.sub(replace, value)
+                try:
+                    value = value % vars
+                except KeyError as e:
+                    raise InterpolationMissingOptionError(
+                        option, section, rawval, e.args[0])
+            else:
+                break
+        if value and "%(" in value:
+            raise InterpolationDepthError(option, section, rawval)
+        return value
+
+    def before_set(self, parser, section, option, value):
+        return value
+
+    @staticmethod
+    def _interpolation_replace(match, parser):
+        s = match.group(1)
+        if s is None:
+            return match.group()
+        else:
+            return "%%(%s)s" % parser.optionxform(s)
+
+
 class RawConfigParser(MutableMapping):
     """ConfigParser that does not do interpolation."""
 
@@ -388,7 +577,8 @@
                                            # space/tab
         (?P.*))?$                   # everything up to eol
         """
-
+    # Interpolation algorithm to be used if the user does not specify another
+    _DEFAULT_INTERPOLATION = Interpolation()
     # Compiled regular expression for matching sections
     SECTCRE = re.compile(_SECT_TMPL, re.VERBOSE)
     # Compiled regular expression for matching options with typical separators
@@ -404,9 +594,11 @@
 
     def __init__(self, defaults=None, dict_type=_default_dict,
                  allow_no_value=False, *, delimiters=('=', ':'),
-                 comment_prefixes=_COMPATIBLE, strict=False,
-                 empty_lines_in_values=True,
-                 default_section=DEFAULTSECT):
+                 comment_prefixes=('#', ';'), inline_comment_prefixes=None,
+                 strict=True, empty_lines_in_values=True,
+                 default_section=DEFAULTSECT,
+                 interpolation=_UNSET):
+
         self._dict = dict_type
         self._sections = self._dict()
         self._defaults = self._dict()
@@ -426,16 +618,16 @@
             else:
                 self._optcre = re.compile(self._OPT_TMPL.format(delim=d),
                                           re.VERBOSE)
-        if comment_prefixes is _COMPATIBLE:
-            self._startonly_comment_prefixes = ('#',)
-            self._comment_prefixes = (';',)
-        else:
-            self._startonly_comment_prefixes = ()
-            self._comment_prefixes = tuple(comment_prefixes or ())
+        self._comment_prefixes = tuple(comment_prefixes or ())
+        self._inline_comment_prefixes = tuple(inline_comment_prefixes or ())
         self._strict = strict
         self._allow_no_value = allow_no_value
         self._empty_lines_in_values = empty_lines_in_values
-        self._default_section=default_section
+        if interpolation is _UNSET:
+            self._interpolation = self._DEFAULT_INTERPOLATION
+        else:
+            self._interpolation = interpolation
+        self.default_section=default_section
 
     def defaults(self):
         return self._defaults
@@ -451,8 +643,8 @@
         Raise DuplicateSectionError if a section by the specified name
         already exists. Raise ValueError if name is DEFAULT.
         """
-        if section == self._default_section:
-            raise ValueError('Invalid section name: %s' % section)
+        if section == self.default_section:
+            raise ValueError('Invalid section name: %r' % section)
 
         if section in self._sections:
             raise DuplicateSectionError(section)
@@ -526,19 +718,23 @@
         that should be present in the section. If the used dictionary type
         preserves order, sections and their keys will be added in order.
 
+        All types held in the dictionary are converted to strings during
+        reading, including section names, option names and keys.
+
         Optional second argument is the `source' specifying the name of the
         dictionary being read.
         """
         elements_added = set()
         for section, keys in dictionary.items():
+            section = str(section)
             try:
                 self.add_section(section)
             except (DuplicateSectionError, ValueError):
                 if self._strict and section in elements_added:
                     raise
-                elements_added.add(section)
+            elements_added.add(section)
             for key, value in keys.items():
-                key = self.optionxform(key)
+                key = self.optionxform(str(key))
                 if value is not None:
                     value = str(value)
                 if self._strict and (section, key) in elements_added:
@@ -555,7 +751,7 @@
         )
         self.read_file(fp, source=filename)
 
-    def get(self, section, option, *, vars=None, fallback=_UNSET):
+    def get(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
         """Get an option value for a given section.
 
         If `vars' is provided, it must be a dictionary. The option is looked up
@@ -563,7 +759,12 @@
         If the key is not found and `fallback' is provided, it is used as
         a fallback value. `None' can be provided as a `fallback' value.
 
-        Arguments `vars' and `fallback' are keyword only.
+        If interpolation is enabled and the optional argument `raw' is False,
+        all interpolations are expanded in the return values.
+
+        Arguments `raw', `vars', and `fallback' are keyword only.
+
+        The section DEFAULT is special.
         """
         try:
             d = self._unify_values(section, vars)
@@ -574,61 +775,90 @@
                 return fallback
         option = self.optionxform(option)
         try:
-            return d[option]
+            value = d[option]
         except KeyError:
             if fallback is _UNSET:
                 raise NoOptionError(option, section)
             else:
                 return fallback
 
-    def items(self, section):
-        try:
-            d2 = self._sections[section]
-        except KeyError:
-            if section != self._default_section:
-                raise NoSectionError(section)
-            d2 = self._dict()
-        d = self._defaults.copy()
-        d.update(d2)
-        return d.items()
+        if raw or value is None:
+            return value
+        else:
+            return self._interpolation.before_get(self, section, option, value,
+                                                  d)
 
     def _get(self, section, conv, option, **kwargs):
         return conv(self.get(section, option, **kwargs))
 
-    def getint(self, section, option, *, vars=None, fallback=_UNSET):
+    def getint(self, section, option, *, raw=False, vars=None,
+               fallback=_UNSET):
         try:
-            return self._get(section, int, option, vars=vars)
+            return self._get(section, int, option, raw=raw, vars=vars)
         except (NoSectionError, NoOptionError):
             if fallback is _UNSET:
                 raise
             else:
                 return fallback
 
-    def getfloat(self, section, option, *, vars=None, fallback=_UNSET):
+    def getfloat(self, section, option, *, raw=False, vars=None,
+                 fallback=_UNSET):
         try:
-            return self._get(section, float, option, vars=vars)
+            return self._get(section, float, option, raw=raw, vars=vars)
         except (NoSectionError, NoOptionError):
             if fallback is _UNSET:
                 raise
             else:
                 return fallback
 
-    def getboolean(self, section, option, *, vars=None, fallback=_UNSET):
+    def getboolean(self, section, option, *, raw=False, vars=None,
+                   fallback=_UNSET):
         try:
             return self._get(section, self._convert_to_boolean, option,
-                             vars=vars)
+                             raw=raw, vars=vars)
         except (NoSectionError, NoOptionError):
             if fallback is _UNSET:
                 raise
             else:
                 return fallback
 
+    def items(self, section=_UNSET, raw=False, vars=None):
+        """Return a list of (name, value) tuples for each option in a section.
+
+        All % interpolations are expanded in the return values, based on the
+        defaults passed into the constructor, unless the optional argument
+        `raw' is true.  Additional substitutions may be provided using the
+        `vars' argument, which must be a dictionary whose contents overrides
+        any pre-existing defaults.
+
+        The section DEFAULT is special.
+        """
+        if section is _UNSET:
+            return super().items()
+        d = self._defaults.copy()
+        try:
+            d.update(self._sections[section])
+        except KeyError:
+            if section != self.default_section:
+                raise NoSectionError(section)
+        # Update with the entry specific variables
+        if vars:
+            for key, value in vars.items():
+                d[self.optionxform(key)] = value
+        value_getter = lambda option: self._interpolation.before_get(self,
+            section, option, d[option], d)
+        if raw:
+            value_getter = lambda option: d[option]
+        return [(option, value_getter(option)) for option in d.keys()]
+
     def optionxform(self, optionstr):
         return optionstr.lower()
 
     def has_option(self, section, option):
-        """Check for the existence of a given option in a given section."""
-        if not section or section == self._default_section:
+        """Check for the existence of a given option in a given section.
+        If the specified `section' is None or an empty string, DEFAULT is
+        assumed. If the specified `section' does not exist, returns False."""
+        if not section or section == self.default_section:
             option = self.optionxform(option)
             return option in self._defaults
         elif section not in self._sections:
@@ -640,7 +870,10 @@
 
     def set(self, section, option, value=None):
         """Set an option."""
-        if not section or section == self._default_section:
+        if value:
+            value = self._interpolation.before_set(self, section, option,
+                                                   value)
+        if not section or section == self.default_section:
             sectdict = self._defaults
         else:
             try:
@@ -660,7 +893,7 @@
         else:
             d = self._delimiters[0]
         if self._defaults:
-            self._write_section(fp, self._default_section,
+            self._write_section(fp, self.default_section,
                                     self._defaults.items(), d)
         for section in self._sections:
             self._write_section(fp, section,
@@ -670,6 +903,8 @@
         """Write a single section to the specified `fp'."""
         fp.write("[{}]\n".format(section_name))
         for key, value in section_items:
+            value = self._interpolation.before_write(self, section_name, key,
+                                                     value)
             if value is not None or not self._allow_no_value:
                 value = delimiter + str(value).replace('\n', '\n\t')
             else:
@@ -679,7 +914,7 @@
 
     def remove_option(self, section, option):
         """Remove an option."""
-        if not section or section == self._default_section:
+        if not section or section == self.default_section:
             sectdict = self._defaults
         else:
             try:
@@ -701,7 +936,7 @@
         return existed
 
     def __getitem__(self, key):
-        if key != self._default_section and not self.has_section(key):
+        if key != self.default_section and not self.has_section(key):
             raise KeyError(key)
         return self._proxies[key]
 
@@ -715,21 +950,21 @@
         self.read_dict({key: value})
 
     def __delitem__(self, key):
-        if key == self._default_section:
+        if key == self.default_section:
             raise ValueError("Cannot remove the default section.")
         if not self.has_section(key):
             raise KeyError(key)
         self.remove_section(key)
 
     def __contains__(self, key):
-        return key == self._default_section or self.has_section(key)
+        return key == self.default_section or self.has_section(key)
 
     def __len__(self):
         return len(self._sections) + 1 # the default section
 
     def __iter__(self):
         # XXX does it break when underlying container state changed?
-        return itertools.chain((self._default_section,), self._sections.keys())
+        return itertools.chain((self.default_section,), self._sections.keys())
 
     def _read(self, fp, fpname):
         """Parse a sectioned configuration file.
@@ -756,18 +991,18 @@
         indent_level = 0
         e = None                              # None, or an exception
         for lineno, line in enumerate(fp, start=1):
-            # strip full line comments
             comment_start = None
-            for prefix in self._startonly_comment_prefixes:
-                if line.strip().startswith(prefix):
-                    comment_start = 0
-                    break
             # strip inline comments
-            for prefix in self._comment_prefixes:
+            for prefix in self._inline_comment_prefixes:
                 index = line.find(prefix)
                 if index == 0 or (index > 0 and line[index-1].isspace()):
                     comment_start = index
                     break
+            # strip full line comments
+            for prefix in self._comment_prefixes:
+                if line.strip().startswith(prefix):
+                    comment_start = 0
+                    break
             value = line[:comment_start].strip()
             if not value:
                 if self._empty_lines_in_values:
@@ -801,7 +1036,7 @@
                                                         lineno)
                         cursect = self._sections[sectname]
                         elements_added.add(sectname)
-                    elif sectname == self._default_section:
+                    elif sectname == self.default_section:
                         cursect = self._defaults
                     else:
                         cursect = self._dict()
@@ -830,13 +1065,10 @@
                         # match if it would set optval to None
                         if optval is not None:
                             optval = optval.strip()
-                            # allow empty values
-                            if optval == '""':
-                                optval = ''
                             cursect[optname] = [optval]
                         else:
                             # valueless option handling
-                            cursect[optname] = optval
+                            cursect[optname] = None
                     else:
                         # a non-fatal parsing error occurred. set up the
                         # exception but keep going. the exception will be
@@ -849,12 +1081,16 @@
         self._join_multiline_values()
 
     def _join_multiline_values(self):
-        all_sections = itertools.chain((self._defaults,),
-                                       self._sections.values())
-        for options in all_sections:
+        defaults = self.default_section, self._defaults
+        all_sections = itertools.chain((defaults,),
+                                       self._sections.items())
+        for section, options in all_sections:
             for name, val in options.items():
                 if isinstance(val, list):
-                    options[name] = '\n'.join(val).rstrip()
+                    val = '\n'.join(val).rstrip()
+                options[name] = self._interpolation.before_read(self,
+                                                                section,
+                                                                name, val)
 
     def _handle_error(self, exc, fpname, lineno, line):
         if not exc:
@@ -871,7 +1107,7 @@
         try:
             d.update(self._sections[section])
         except KeyError:
-            if section != self._default_section:
+            if section != self.default_section:
                 raise NoSectionError(section)
         # Update with the entry specific variables
         if vars:
@@ -888,7 +1124,7 @@
             raise ValueError('Not a boolean: %s' % value)
         return self.BOOLEAN_STATES[value.lower()]
 
-    def _validate_value_type(self, value):
+    def _validate_value_types(self, *, section="", option="", value=""):
         """Raises a TypeError for non-string values.
 
         The only legal non-string value if we allow valueless
@@ -898,205 +1134,48 @@
         - we allow valueless options but the value is not None
 
         For compatibility reasons this method is not used in classic set()
-        for RawConfigParsers and ConfigParsers. It is invoked in every
-        case for mapping protocol access and in SafeConfigParser.set().
+        for RawConfigParsers. It is invoked in every case for mapping protocol
+        access and in ConfigParser.set().
         """
+        if not isinstance(section, str):
+            raise TypeError("section names must be strings")
+        if not isinstance(option, str):
+            raise TypeError("option keys must be strings")
         if not self._allow_no_value or value:
             if not isinstance(value, str):
                 raise TypeError("option values must be strings")
 
 
-
 class ConfigParser(RawConfigParser):
     """ConfigParser implementing interpolation."""
 
-    def get(self, section, option, *, raw=False, vars=None, fallback=_UNSET):
-        """Get an option value for a given section.
-
-        If `vars' is provided, it must be a dictionary. The option is looked up
-        in `vars' (if provided), `section', and in `DEFAULTSECT' in that order.
-        If the key is not found and `fallback' is provided, it is used as
-        a fallback value. `None' can be provided as a `fallback' value.
-
-        All % interpolations are expanded in the return values, unless the
-        optional argument `raw' is true.  Values for interpolation keys are
-        looked up in the same manner as the option.
-
-        Arguments `raw', `vars', and `fallback' are keyword only.
-
-        The section DEFAULT is special.
-        """
-        try:
-            d = self._unify_values(section, vars)
-        except NoSectionError:
-            if fallback is _UNSET:
-                raise
-            else:
-                return fallback
-        option = self.optionxform(option)
-        try:
-            value = d[option]
-        except KeyError:
-            if fallback is _UNSET:
-                raise NoOptionError(option, section)
-            else:
-                return fallback
-
-        if raw or value is None:
-            return value
-        else:
-            return self._interpolate(section, option, value, d)
-
-    def getint(self, section, option, *, raw=False, vars=None,
-               fallback=_UNSET):
-        try:
-            return self._get(section, int, option, raw=raw, vars=vars)
-        except (NoSectionError, NoOptionError):
-            if fallback is _UNSET:
-                raise
-            else:
-                return fallback
-
-    def getfloat(self, section, option, *, raw=False, vars=None,
-                 fallback=_UNSET):
-        try:
-            return self._get(section, float, option, raw=raw, vars=vars)
-        except (NoSectionError, NoOptionError):
-            if fallback is _UNSET:
-                raise
-            else:
-                return fallback
-
-    def getboolean(self, section, option, *, raw=False, vars=None,
-                   fallback=_UNSET):
-        try:
-            return self._get(section, self._convert_to_boolean, option,
-                             raw=raw, vars=vars)
-        except (NoSectionError, NoOptionError):
-            if fallback is _UNSET:
-                raise
-            else:
-                return fallback
-
-    def items(self, section, raw=False, vars=None):
-        """Return a list of (name, value) tuples for each option in a section.
-
-        All % interpolations are expanded in the return values, based on the
-        defaults passed into the constructor, unless the optional argument
-        `raw' is true.  Additional substitutions may be provided using the
-        `vars' argument, which must be a dictionary whose contents overrides
-        any pre-existing defaults.
+    _DEFAULT_INTERPOLATION = BasicInterpolation()
 
-        The section DEFAULT is special.
-        """
-        d = self._defaults.copy()
-        try:
-            d.update(self._sections[section])
-        except KeyError:
-            if section != self._default_section:
-                raise NoSectionError(section)
-        # Update with the entry specific variables
-        if vars:
-            for key, value in vars.items():
-                d[self.optionxform(key)] = value
-        options = list(d.keys())
-        if raw:
-            return [(option, d[option])
-                    for option in options]
-        else:
-            return [(option, self._interpolate(section, option, d[option], d))
-                    for option in options]
-
-    def _interpolate(self, section, option, rawval, vars):
-        # do the string interpolation
-        value = rawval
-        depth = MAX_INTERPOLATION_DEPTH
-        while depth:                    # Loop through this until it's done
-            depth -= 1
-            if value and "%(" in value:
-                value = self._KEYCRE.sub(self._interpolation_replace, value)
-                try:
-                    value = value % vars
-                except KeyError as e:
-                    raise InterpolationMissingOptionError(
-                        option, section, rawval, e.args[0])
-            else:
-                break
-        if value and "%(" in value:
-            raise InterpolationDepthError(option, section, rawval)
-        return value
-
-    _KEYCRE = re.compile(r"%\(([^)]*)\)s|.")
+    def set(self, section, option, value=None):
+        """Set an option.  Extends RawConfigParser.set by validating type and
+        interpolation syntax on the value."""
+        self._validate_value_types(option=option, value=value)
+        super().set(section, option, value)
 
-    def _interpolation_replace(self, match):
-        s = match.group(1)
-        if s is None:
-            return match.group()
-        else:
-            return "%%(%s)s" % self.optionxform(s)
+    def add_section(self, section):
+        """Create a new section in the configuration.  Extends
+        RawConfigParser.add_section by validating if the section name is
+        a string."""
+        self._validate_value_types(section=section)
+        super().add_section(section)
 
 
 class SafeConfigParser(ConfigParser):
-    """ConfigParser implementing sane interpolation."""
-
-    def _interpolate(self, section, option, rawval, vars):
-        # do the string interpolation
-        L = []
-        self._interpolate_some(option, L, rawval, section, vars, 1)
-        return ''.join(L)
-
-    _interpvar_re = re.compile(r"%\(([^)]+)\)s")
-
-    def _interpolate_some(self, option, accum, rest, section, map, depth):
-        if depth > MAX_INTERPOLATION_DEPTH:
-            raise InterpolationDepthError(option, section, rest)
-        while rest:
-            p = rest.find("%")
-            if p < 0:
-                accum.append(rest)
-                return
-            if p > 0:
-                accum.append(rest[:p])
-                rest = rest[p:]
-            # p is no longer used
-            c = rest[1:2]
-            if c == "%":
-                accum.append("%")
-                rest = rest[2:]
-            elif c == "(":
-                m = self._interpvar_re.match(rest)
-                if m is None:
-                    raise InterpolationSyntaxError(option, section,
-                        "bad interpolation variable reference %r" % rest)
-                var = self.optionxform(m.group(1))
-                rest = rest[m.end():]
-                try:
-                    v = map[var]
-                except KeyError:
-                    raise InterpolationMissingOptionError(
-                        option, section, rest, var)
-                if "%" in v:
-                    self._interpolate_some(option, accum, v,
-                                           section, map, depth + 1)
-                else:
-                    accum.append(v)
-            else:
-                raise InterpolationSyntaxError(
-                    option, section,
-                    "'%%' must be followed by '%%' or '(', "
-                    "found: %r" % (rest,))
+    """ConfigParser alias for backwards compatibility purposes."""
 
-    def set(self, section, option, value=None):
-        """Set an option.  Extend ConfigParser.set: check for string values."""
-        self._validate_value_type(value)
-        # check for bad percent signs
-        if value:
-            tmp_value = value.replace('%%', '') # escaped percent signs
-            tmp_value = self._interpvar_re.sub('', tmp_value) # valid syntax
-            if '%' in tmp_value:
-                raise ValueError("invalid interpolation syntax in %r at "
-                                "position %d" % (value, tmp_value.find('%')))
-        ConfigParser.set(self, section, option, value)
+    def __init__(self, *args, **kwargs):
+        super().__init__(*args, **kwargs)
+        warnings.warn(
+            "The SafeConfigParser class has been renamed to ConfigParser "
+            "in Python 3.2. This alias will be removed in future versions."
+            " Use ConfigParser directly instead.",
+            DeprecationWarning, stacklevel=2
+        )
 
 
 class SectionProxy(MutableMapping):
@@ -1106,12 +1185,6 @@
         """Creates a view on a section of the specified `name` in `parser`."""
         self._parser = parser
         self._name = name
-        self.getint = functools.partial(self._parser.getint,
-                                        self._name)
-        self.getfloat = functools.partial(self._parser.getfloat,
-                                          self._name)
-        self.getboolean = functools.partial(self._parser.getboolean,
-                                            self._name)
 
     def __repr__(self):
         return ''.format(self._name)
@@ -1122,25 +1195,44 @@
         return self._parser.get(self._name, key)
 
     def __setitem__(self, key, value):
-        self._parser._validate_value_type(value)
+        self._parser._validate_value_types(option=key, value=value)
         return self._parser.set(self._name, key, value)
 
     def __delitem__(self, key):
-        if not self._parser.has_option(self._name, key):
+        if not (self._parser.has_option(self._name, key) and
+                self._parser.remove_option(self._name, key)):
             raise KeyError(key)
-        return self._parser.remove_option(self._name, key)
 
     def __contains__(self, key):
         return self._parser.has_option(self._name, key)
 
     def __len__(self):
-        # XXX weak performance
-        return len(self._parser.options(self._name))
+        return len(self._options())
 
     def __iter__(self):
-        # XXX weak performance
-        # XXX does not break when underlying container state changed
-        return self._parser.options(self._name).__iter__()
+        return self._options().__iter__()
+
+    def _options(self):
+        if self._name != self._parser.default_section:
+            return self._parser.options(self._name)
+        else:
+            return self._parser.defaults()
+
+    def get(self, option, fallback=None, *, raw=False, vars=None):
+        return self._parser.get(self._name, option, raw=raw, vars=vars,
+                                fallback=fallback)
+
+    def getint(self, option, fallback=None, *, raw=False, vars=None):
+        return self._parser.getint(self._name, option, raw=raw, vars=vars,
+                                   fallback=fallback)
+
+    def getfloat(self, option, fallback=None, *, raw=False, vars=None):
+        return self._parser.getfloat(self._name, option, raw=raw, vars=vars,
+                                     fallback=fallback)
+
+    def getboolean(self, option, fallback=None, *, raw=False, vars=None):
+        return self._parser.getboolean(self._name, option, raw=raw, vars=vars,
+                                       fallback=fallback)
 
     @property
     def parser(self):

Modified: python/branches/py3k-cdecimal/Lib/dbm/dumb.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/dbm/dumb.py	(original)
+++ python/branches/py3k-cdecimal/Lib/dbm/dumb.py	Sun Jan  2 13:18:37 2011
@@ -203,7 +203,7 @@
         # The blocks used by the associated value are lost.
         del self._index[key]
         # XXX It's unclear why we do a _commit() here (the code always
-        # XXX has, so I'm not changing it).  _setitem__ doesn't try to
+        # XXX has, so I'm not changing it).  __setitem__ doesn't try to
         # XXX keep the directory file in synch.  Why should we?  Or
         # XXX why shouldn't __setitem__?
         self._commit()
@@ -232,7 +232,7 @@
 
     __del__ = close
 
-    def _chmod (self, file):
+    def _chmod(self, file):
         if hasattr(self._os, 'chmod'):
             self._os.chmod(file, self._mode)
 

Modified: python/branches/py3k-cdecimal/Lib/decimal.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/decimal.py	(original)
+++ python/branches/py3k-cdecimal/Lib/decimal.py	Sun Jan  2 13:18:37 2011
@@ -132,6 +132,7 @@
 ]
 
 __version__ = '1.70'    # Highest version of the spec this complies with
+                        # See http://speleotrove.com/decimal/
 
 import copy as _copy
 import math as _math
@@ -5526,23 +5527,7 @@
 
 ##### Integer arithmetic functions used by ln, log10, exp and __pow__ #####
 
-# This function from Tim Peters was taken from here:
-# http://mail.python.org/pipermail/python-list/1999-July/007758.html
-# The correction being in the function definition is for speed, and
-# the whole function is not resolved with math.log because of avoiding
-# the use of floats.
-def _nbits(n, correction = {
-        '0': 4, '1': 3, '2': 2, '3': 2,
-        '4': 1, '5': 1, '6': 1, '7': 1,
-        '8': 0, '9': 0, 'a': 0, 'b': 0,
-        'c': 0, 'd': 0, 'e': 0, 'f': 0}):
-    """Number of bits in binary representation of the positive integer n,
-    or 0 if n == 0.
-    """
-    if n < 0:
-        raise ValueError("The argument to _nbits should be nonnegative.")
-    hex_n = "%x" % n
-    return 4*len(hex_n) - correction[hex_n[0]]
+_nbits = int.bit_length
 
 def _sqrt_nearest(n, a):
     """Closest integer to the square root of the positive integer n.  a is
@@ -5991,7 +5976,7 @@
 #
 # A format specifier for Decimal looks like:
 #
-#   [[fill]align][sign][0][minimumwidth][,][.precision][type]
+#   [[fill]align][sign][#][0][minimumwidth][,][.precision][type]
 
 _parse_format_specifier_regex = re.compile(r"""\A
 (?:
@@ -5999,6 +5984,7 @@
    (?P[<>=^])
 )?
 (?P[-+ ])?
+(?P\#)?
 (?P0)?
 (?P(?!0)\d+)?
 (?P,)?
@@ -6214,7 +6200,7 @@
 
     sign = _format_sign(is_negative, spec)
 
-    if fracpart:
+    if fracpart or spec['alt']:
         fracpart = spec['decimal_point'] + fracpart
 
     if exp != 0 or spec['type'] in 'eE':

Modified: python/branches/py3k-cdecimal/Lib/difflib.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/difflib.py	(original)
+++ python/branches/py3k-cdecimal/Lib/difflib.py	Sun Jan  2 13:18:37 2011
@@ -32,6 +32,7 @@
            'Differ','IS_CHARACTER_JUNK', 'IS_LINE_JUNK', 'context_diff',
            'unified_diff', 'HtmlDiff', 'Match']
 
+import warnings
 import heapq
 from collections import namedtuple as _namedtuple
 
@@ -150,7 +151,7 @@
         Return an upper bound on ratio() very quickly.
     """
 
-    def __init__(self, isjunk=None, a='', b=''):
+    def __init__(self, isjunk=None, a='', b='', autojunk=True):
         """Construct a SequenceMatcher.
 
         Optional arg isjunk is None (the default), or a one-argument
@@ -168,6 +169,10 @@
         Optional arg b is the second of two sequences to be compared.  By
         default, an empty string.  The elements of b must be hashable. See
         also .set_seqs() and .set_seq2().
+
+        Optional arg autojunk should be set to False to disable the
+        "automatic junk heuristic" that treats popular elements as junk
+        (see module documentation for more information).
         """
 
         # Members:
@@ -178,7 +183,7 @@
         #      we need to do to 'a' to change it into 'b'?"
         # b2j
         #      for x in b, b2j[x] is a list of the indices (into b)
-        #      at which x appears; junk elements do not appear
+        #      at which x appears; junk and popular elements do not appear
         # fullbcount
         #      for x in b, fullbcount[x] == the number of times x
         #      appears in b; only materialized if really needed (used
@@ -200,17 +205,14 @@
         #      subtle but helpful effects on the algorithm, which I'll
         #      get around to writing up someday <0.9 wink>.
         #      DON'T USE!  Only __chain_b uses this.  Use isbjunk.
-        # isbjunk
-        #      for x in b, isbjunk(x) == isjunk(x) but much faster;
-        #      it's really the __contains__ method of a hidden dict.
-        #      DOES NOT WORK for x in a!
-        # isbpopular
-        #      for x in b, isbpopular(x) is true iff b is reasonably long
-        #      (at least 200 elements) and x accounts for more than 1% of
-        #      its elements.  DOES NOT WORK for x in a!
+        # bjunk
+        #      the items in b for which isjunk is True.
+        # bpopular
+        #      nonjunk items in b treated as junk by the heuristic (if used).
 
         self.isjunk = isjunk
         self.a = self.b = None
+        self.autojunk = autojunk
         self.set_seqs(a, b)
 
     def set_seqs(self, a, b):
@@ -287,7 +289,7 @@
     # from starting any matching block at a junk element ...
     # also creates the fast isbjunk function ...
     # b2j also does not contain entries for "popular" elements, meaning
-    # elements that account for more than 1% of the total elements, and
+    # elements that account for more than 1 + 1% of the total elements, and
     # when the sequence is reasonably large (>= 200 elements); this can
     # be viewed as an adaptive notion of semi-junk, and yields an enormous
     # speedup when, e.g., comparing program files with hundreds of
@@ -308,44 +310,46 @@
         # out the junk later is much cheaper than building b2j "right"
         # from the start.
         b = self.b
-        n = len(b)
         self.b2j = b2j = {}
-        populardict = {}
+
         for i, elt in enumerate(b):
-            if elt in b2j:
-                indices = b2j[elt]
-                if n >= 200 and len(indices) * 100 > n:
-                    populardict[elt] = 1
-                    del indices[:]
-                else:
-                    indices.append(i)
-            else:
-                b2j[elt] = [i]
+            indices = b2j.setdefault(elt, [])
+            indices.append(i)
 
-        # Purge leftover indices for popular elements.
-        for elt in populardict:
-            del b2j[elt]
-
-        # Now b2j.keys() contains elements uniquely, and especially when
-        # the sequence is a string, that's usually a good deal smaller
-        # than len(string).  The difference is the number of isjunk calls
-        # saved.
+        # Purge junk elements
+        self.bjunk = junk = set()
         isjunk = self.isjunk
-        junkdict = {}
         if isjunk:
-            for d in populardict, b2j:
-                for elt in list(d.keys()):
-                    if isjunk(elt):
-                        junkdict[elt] = 1
-                        del d[elt]
-
-        # Now for x in b, isjunk(x) == x in junkdict, but the
-        # latter is much faster.  Note too that while there may be a
-        # lot of junk in the sequence, the number of *unique* junk
-        # elements is probably small.  So the memory burden of keeping
-        # this dict alive is likely trivial compared to the size of b2j.
-        self.isbjunk = junkdict.__contains__
-        self.isbpopular = populardict.__contains__
+            for elt in b2j.keys():
+                if isjunk(elt):
+                    junk.add(elt)
+            for elt in junk: # separate loop avoids separate list of keys
+                del b2j[elt]
+
+        # Purge popular elements that are not junk
+        self.bpopular = popular = set()
+        n = len(b)
+        if self.autojunk and n >= 200:
+            ntest = n // 100 + 1
+            for elt, idxs in b2j.items():
+                if len(idxs) > ntest:
+                    popular.add(elt)
+            for elt in popular: # ditto; as fast for 1% deletion
+                del b2j[elt]
+
+    def isbjunk(self, item):
+        "Deprecated; use 'item in SequenceMatcher().bjunk'."
+        warnings.warn("'SequenceMatcher().isbjunk(item)' is deprecated;\n"
+                      "use 'item in SMinstance.bjunk' instead.",
+                      DeprecationWarning, 2)
+        return item in self.bjunk
+
+    def isbpopular(self, item):
+        "Deprecated; use 'item in SequenceMatcher().bpopular'."
+        warnings.warn("'SequenceMatcher().isbpopular(item)' is deprecated;\n"
+                      "use 'item in SMinstance.bpopular' instead.",
+                      DeprecationWarning, 2)
+        return item in self.bpopular
 
     def find_longest_match(self, alo, ahi, blo, bhi):
         """Find longest matching block in a[alo:ahi] and b[blo:bhi].
@@ -403,7 +407,7 @@
         # Windiff ends up at the same place as diff, but by pairing up
         # the unique 'b's and then matching the first two 'a's.
 
-        a, b, b2j, isbjunk = self.a, self.b, self.b2j, self.isbjunk
+        a, b, b2j, isbjunk = self.a, self.b, self.b2j, self.bjunk.__contains__
         besti, bestj, bestsize = alo, blo, 0
         # find longest junk-free match
         # during an iteration of the loop, j2len[j] = length of longest

Modified: python/branches/py3k-cdecimal/Lib/distutils/__init__.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/distutils/__init__.py	(original)
+++ python/branches/py3k-cdecimal/Lib/distutils/__init__.py	Sun Jan  2 13:18:37 2011
@@ -15,5 +15,5 @@
 # Updated automatically by the Python release process.
 #
 #--start constants--
-__version__ = "3.2a4"
+__version__ = "3.2b2"
 #--end constants--

Modified: python/branches/py3k-cdecimal/Lib/distutils/archive_util.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/distutils/archive_util.py	(original)
+++ python/branches/py3k-cdecimal/Lib/distutils/archive_util.py	Sun Jan  2 13:18:37 2011
@@ -68,7 +68,7 @@
 def make_zipfile(base_name, base_dir, verbose=0, dry_run=0):
     """Create a zip file from all the files under 'base_dir'.
 
-    The output zip file will be named 'base_dir' + ".zip".  Uses either the
+    The output zip file will be named 'base_name' + ".zip".  Uses either the
     "zipfile" Python module (if available) or the InfoZIP "zip" utility
     (if installed and found on the default search path).  If neither tool is
     available, raises DistutilsExecError.  Returns the name of the output zip

Modified: python/branches/py3k-cdecimal/Lib/distutils/command/build_ext.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/distutils/command/build_ext.py	(original)
+++ python/branches/py3k-cdecimal/Lib/distutils/command/build_ext.py	Sun Jan  2 13:18:37 2011
@@ -214,7 +214,7 @@
 
             elif MSVC_VERSION == 8:
                 self.library_dirs.append(os.path.join(sys.exec_prefix,
-                                         'PC', 'VS8.0', 'win32release'))
+                                         'PC', 'VS8.0'))
             elif MSVC_VERSION == 7:
                 self.library_dirs.append(os.path.join(sys.exec_prefix,
                                          'PC', 'VS7.1'))

Modified: python/branches/py3k-cdecimal/Lib/distutils/command/install.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/distutils/command/install.py	(original)
+++ python/branches/py3k-cdecimal/Lib/distutils/command/install.py	Sun Jan  2 13:18:37 2011
@@ -48,7 +48,7 @@
     'unix_prefix': {
         'purelib': '$base/lib/python$py_version_short/site-packages',
         'platlib': '$platbase/lib/python$py_version_short/site-packages',
-        'headers': '$base/include/python$py_version_short/$dist_name',
+        'headers': '$base/include/python$py_version_short$abiflags/$dist_name',
         'scripts': '$base/bin',
         'data'   : '$base',
         },
@@ -82,7 +82,8 @@
     INSTALL_SCHEMES['unix_user'] = {
         'purelib': '$usersite',
         'platlib': '$usersite',
-        'headers': '$userbase/include/python$py_version_short/$dist_name',
+        'headers':
+            '$userbase/include/python$py_version_short$abiflags/$dist_name',
         'scripts': '$userbase/bin',
         'data'   : '$userbase',
         }
@@ -312,6 +313,11 @@
 
         py_version = sys.version.split()[0]
         (prefix, exec_prefix) = get_config_vars('prefix', 'exec_prefix')
+        try:
+            abiflags = sys.abiflags
+        except AttributeError:
+            # sys.abiflags may not be defined on all platforms.
+            abiflags = ''
         self.config_vars = {'dist_name': self.distribution.get_name(),
                             'dist_version': self.distribution.get_version(),
                             'dist_fullname': self.distribution.get_fullname(),
@@ -322,6 +328,7 @@
                             'prefix': prefix,
                             'sys_exec_prefix': exec_prefix,
                             'exec_prefix': exec_prefix,
+                            'abiflags': abiflags,
                            }
 
         if HAS_USER_SITE:

Modified: python/branches/py3k-cdecimal/Lib/distutils/sysconfig.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/distutils/sysconfig.py	(original)
+++ python/branches/py3k-cdecimal/Lib/distutils/sysconfig.py	Sun Jan  2 13:18:37 2011
@@ -11,7 +11,6 @@
 
 __revision__ = "$Id$"
 
-import io
 import os
 import re
 import sys
@@ -49,6 +48,18 @@
     return False
 python_build = _python_build()
 
+# Calculate the build qualifier flags if they are defined.  Adding the flags
+# to the include and lib directories only makes sense for an installation, not
+# an in-source build.
+build_flags = ''
+try:
+    if not python_build:
+        build_flags = sys.abiflags
+except AttributeError:
+    # It's not a configure-based build, so the sys module doesn't have
+    # this attribute, which is fine.
+    pass
+
 def get_python_version():
     """Return a string containing the major and minor Python version,
     leaving off the patchlevel.  Sample return values could be '1.5'
@@ -83,7 +94,8 @@
             else:
                 incdir = os.path.join(get_config_var('srcdir'), 'Include')
                 return os.path.normpath(incdir)
-        return os.path.join(prefix, "include", "python" + get_python_version())
+        python_dir = 'python' + get_python_version() + build_flags
+        return os.path.join(prefix, "include", python_dir)
     elif os.name == "nt":
         return os.path.join(prefix, "include")
     elif os.name == "os2":
@@ -209,7 +221,8 @@
     if python_build:
         return os.path.join(os.path.dirname(sys.executable), "Makefile")
     lib_dir = get_python_lib(plat_specific=1, standard_lib=1)
-    return os.path.join(lib_dir, "config", "Makefile")
+    config_file = 'config-{}{}'.format(get_python_version(), build_flags)
+    return os.path.join(lib_dir, config_file, 'Makefile')
 
 
 def parse_config_h(fp, g=None):

Modified: python/branches/py3k-cdecimal/Lib/doctest.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/doctest.py	(original)
+++ python/branches/py3k-cdecimal/Lib/doctest.py	Sun Jan  2 13:18:37 2011
@@ -318,7 +318,8 @@
     def __init__(self, out):
         self.__out = out
         self.__debugger_used = False
-        pdb.Pdb.__init__(self, stdout=out)
+        # do not play signal games in the pdb
+        pdb.Pdb.__init__(self, stdout=out, nosigint=True)
         # still use input() to get user input
         self.use_rawinput = 1
 
@@ -2528,14 +2529,16 @@
                     exec(f.read(), globs, globs)
             except:
                 print(sys.exc_info()[1])
-                pdb.post_mortem(sys.exc_info()[2])
+                p = pdb.Pdb(nosigint=True)
+                p.reset()
+                p.interaction(None, sys.exc_info()[2])
         else:
             fp = open(srcfilename)
             try:
                 script = fp.read()
             finally:
                 fp.close()
-            pdb.run("exec(%r)" % script, globs, globs)
+            pdb.Pdb(nosigint=True).run("exec(%r)" % script, globs, globs)
 
     finally:
         os.remove(srcfilename)

Modified: python/branches/py3k-cdecimal/Lib/email/_parseaddr.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/email/_parseaddr.py	(original)
+++ python/branches/py3k-cdecimal/Lib/email/_parseaddr.py	Sun Jan  2 13:18:37 2011
@@ -64,8 +64,10 @@
     if len(data) == 4:
         s = data[3]
         i = s.find('+')
+        if i == -1:
+            i = s.find('-')
         if i > 0:
-            data[3:] = [s[:i], s[i+1:]]
+            data[3:] = [s[:i], s[i:]]
         else:
             data.append('') # Dummy tz
     if len(data) < 5:
@@ -199,14 +201,18 @@
         self.commentlist = []
 
     def gotonext(self):
-        """Parse up to the start of the next address."""
+        """Skip white space and extract comments."""
+        wslist = []
         while self.pos < len(self.field):
             if self.field[self.pos] in self.LWS + '\n\r':
+                if self.field[self.pos] not in '\n\r':
+                    wslist.append(self.field[self.pos])
                 self.pos += 1
             elif self.field[self.pos] == '(':
                 self.commentlist.append(self.getcomment())
             else:
                 break
+        return EMPTYSTRING.join(wslist)
 
     def getaddrlist(self):
         """Parse all addresses.
@@ -319,16 +325,24 @@
 
         self.gotonext()
         while self.pos < len(self.field):
+            preserve_ws = True
             if self.field[self.pos] == '.':
+                if aslist and not aslist[-1].strip():
+                    aslist.pop()
                 aslist.append('.')
                 self.pos += 1
+                preserve_ws = False
             elif self.field[self.pos] == '"':
                 aslist.append('"%s"' % quote(self.getquote()))
             elif self.field[self.pos] in self.atomends:
+                if aslist and not aslist[-1].strip():
+                    aslist.pop()
                 break
             else:
                 aslist.append(self.getatom())
-            self.gotonext()
+            ws = self.gotonext()
+            if preserve_ws and ws:
+                aslist.append(ws)
 
         if self.pos >= len(self.field) or self.field[self.pos] != '@':
             return EMPTYSTRING.join(aslist)

Modified: python/branches/py3k-cdecimal/Lib/email/generator.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/email/generator.py	(original)
+++ python/branches/py3k-cdecimal/Lib/email/generator.py	Sun Jan  2 13:18:37 2011
@@ -220,18 +220,13 @@
             g = self.clone(s)
             g.flatten(part, unixfrom=False, linesep=self._NL)
             msgtexts.append(s.getvalue())
-        # Now make sure the boundary we've selected doesn't appear in any of
-        # the message texts.
-        alltext = self._encoded_NL.join(msgtexts)
         # BAW: What about boundaries that are wrapped in double-quotes?
-        boundary = msg.get_boundary(failobj=self._make_boundary(alltext))
-        # If we had to calculate a new boundary because the body text
-        # contained that string, set the new boundary.  We don't do it
-        # unconditionally because, while set_boundary() preserves order, it
-        # doesn't preserve newlines/continuations in headers.  This is no big
-        # deal in practice, but turns out to be inconvenient for the unittest
-        # suite.
-        if msg.get_boundary() != boundary:
+        boundary = msg.get_boundary()
+        if not boundary:
+            # Create a boundary that doesn't appear in any of the
+            # message texts.
+            alltext = self._encoded_NL.join(msgtexts)
+            boundary = self._make_boundary(alltext)
             msg.set_boundary(boundary)
         # If there's a preamble, write it out, with a trailing CRLF
         if msg.preamble is not None:

Modified: python/branches/py3k-cdecimal/Lib/email/header.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/email/header.py	(original)
+++ python/branches/py3k-cdecimal/Lib/email/header.py	Sun Jan  2 13:18:37 2011
@@ -169,7 +169,7 @@
         charset is used both as s's initial charset and as the default for
         subsequent .append() calls.
 
-        The maximum line length can be specified explicit via maxlinelen.  For
+        The maximum line length can be specified explicitly via maxlinelen. For
         splitting the first line to a shorter value (to account for the field
         header which isn't included in s, e.g. `Subject') pass in the name of
         the field in header_name.  The default maxlinelen is 78 as recommended
@@ -241,7 +241,7 @@
         constructor is used.
 
         s may be a byte string or a Unicode string.  If it is a byte string
-        (i.e. isinstance(s, str) is true), then charset is the encoding of
+        (i.e. isinstance(s, str) is false), then charset is the encoding of
         that byte string, and a UnicodeError will be raised if the string
         cannot be decoded with that charset.  If s is a Unicode string, then
         charset is a hint specifying the character set of the characters in

Modified: python/branches/py3k-cdecimal/Lib/email/message.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/email/message.py	(original)
+++ python/branches/py3k-cdecimal/Lib/email/message.py	Sun Jan  2 13:18:37 2011
@@ -57,16 +57,28 @@
 def _formatparam(param, value=None, quote=True):
     """Convenience function to format and return a key=value pair.
 
-    This will quote the value if needed or if quote is true.
+    This will quote the value if needed or if quote is true.  If value is a
+    three tuple (charset, language, value), it will be encoded according
+    to RFC2231 rules.  If it contains non-ascii characters it will likewise
+    be encoded according to RFC2231 rules, using the utf-8 charset and
+    a null language.
     """
     if value is not None and len(value) > 0:
         # A tuple is used for RFC 2231 encoded parameter values where items
         # are (charset, language, value).  charset is a string, not a Charset
-        # instance.
+        # instance.  RFC 2231 encoded values are never quoted, per RFC.
         if isinstance(value, tuple):
             # Encode as per RFC 2231
             param += '*'
             value = utils.encode_rfc2231(value[2], value[0], value[1])
+            return '%s=%s' % (param, value)
+        else:
+            try:
+                value.encode('ascii')
+            except UnicodeEncodeError:
+                param += '*'
+                value = utils.encode_rfc2231(value, 'utf-8', '')
+                return '%s=%s' % (param, value)
         # BAW: Please check this.  I think that if quote is set it should
         # force quoting even if not necessary.
         if quote or tspecials.search(value):
@@ -438,11 +450,19 @@
         name is the header field to add.  keyword arguments can be used to set
         additional parameters for the header field, with underscores converted
         to dashes.  Normally the parameter will be added as key="value" unless
-        value is None, in which case only the key will be added.
+        value is None, in which case only the key will be added.  If a
+        parameter value contains non-ASCII characters it can be specified as a
+        three-tuple of (charset, language, value), in which case it will be
+        encoded according to RFC2231 rules.  Otherwise it will be encoded using
+        the utf-8 charset and a language of ''.
 
-        Example:
+        Examples:
 
         msg.add_header('content-disposition', 'attachment', filename='bud.gif')
+        msg.add_header('content-disposition', 'attachment',
+                       filename=('utf-8', '', Fu??baller.ppt'))
+        msg.add_header('content-disposition', 'attachment',
+                       filename='Fu??baller.ppt'))
         """
         parts = []
         for k, v in _params.items():

Modified: python/branches/py3k-cdecimal/Lib/email/test/test_email.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/email/test/test_email.py	(original)
+++ python/branches/py3k-cdecimal/Lib/email/test/test_email.py	Sun Jan  2 13:18:37 2011
@@ -180,6 +180,17 @@
         self.assertRaises(errors.HeaderParseError,
                           msg.set_boundary, 'BOUNDARY')
 
+    def test_make_boundary(self):
+        msg = MIMEMultipart('form-data')
+        # Note that when the boundary gets created is an implementation
+        # detail and might change.
+        self.assertEqual(msg.items()[0][1], 'multipart/form-data')
+        # Trigger creation of boundary
+        msg.as_string()
+        self.assertEqual(msg.items()[0][1][:33],
+                        'multipart/form-data; boundary="==')
+        # XXX: there ought to be tests of the uniqueness of the boundary, too.
+
     def test_message_rfc822_only(self):
         # Issue 7970: message/rfc822 not in multipart parsed by
         # HeaderParser caused an exception when flattened.
@@ -510,6 +521,45 @@
         self.assertEqual(msg.get_payload(decode=True),
                          bytes(x, 'raw-unicode-escape'))
 
+    # Issue 1078919
+    def test_ascii_add_header(self):
+        msg = Message()
+        msg.add_header('Content-Disposition', 'attachment',
+                       filename='bud.gif')
+        self.assertEqual('attachment; filename="bud.gif"',
+            msg['Content-Disposition'])
+
+    def test_noascii_add_header(self):
+        msg = Message()
+        msg.add_header('Content-Disposition', 'attachment',
+            filename="Fu??baller.ppt")
+        self.assertEqual(
+            'attachment; filename*=utf-8\'\'Fu%C3%9Fballer.ppt',
+            msg['Content-Disposition'])
+
+    def test_nonascii_add_header_via_triple(self):
+        msg = Message()
+        msg.add_header('Content-Disposition', 'attachment',
+            filename=('iso-8859-1', '', 'Fu??baller.ppt'))
+        self.assertEqual(
+            'attachment; filename*=iso-8859-1\'\'Fu%DFballer.ppt',
+            msg['Content-Disposition'])
+
+    def test_ascii_add_header_with_tspecial(self):
+        msg = Message()
+        msg.add_header('Content-Disposition', 'attachment',
+            filename="windows [filename].ppt")
+        self.assertEqual(
+            'attachment; filename="windows [filename].ppt"',
+            msg['Content-Disposition'])
+
+    def test_nonascii_add_header_with_tspecial(self):
+        msg = Message()
+        msg.add_header('Content-Disposition', 'attachment',
+            filename="Fu??baller [filename].ppt")
+        self.assertEqual(
+            "attachment; filename*=utf-8''Fu%C3%9Fballer%20%5Bfilename%5D.ppt",
+            msg['Content-Disposition'])
 
 
 # Test the email.encoders module
@@ -2243,6 +2293,16 @@
         eq(utils.parsedate_tz('5 Feb 2003 13:47:26 -0800'),
            (2003, 2, 5, 13, 47, 26, 0, 1, -1, -28800))
 
+    def test_parsedate_no_space_before_positive_offset(self):
+        self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26+0800'),
+           (2002, 4, 3, 14, 58, 26, 0, 1, -1, 28800))
+
+    def test_parsedate_no_space_before_negative_offset(self):
+        # Issue 1155362: we already handled '+' for this case.
+        self.assertEqual(utils.parsedate_tz('Wed, 3 Apr 2002 14:58:26-0800'),
+           (2002, 4, 3, 14, 58, 26, 0, 1, -1, -28800))
+
+
     def test_parsedate_acceptable_to_time_functions(self):
         eq = self.assertEqual
         timetup = utils.parsedate('5 Feb 2003 13:47:26 -0800')
@@ -2319,6 +2379,24 @@
         eq(utils.parseaddr('"\\\\"example\\\\" example"@example.com'),
           ('', '"\\\\"example\\\\" example"@example.com'))
 
+    def test_parseaddr_preserves_spaces_in_local_part(self):
+        # issue 9286.  A normal RFC5322 local part should not contain any
+        # folding white space, but legacy local parts can (they are a sequence
+        # of atoms, not dotatoms).  On the other hand we strip whitespace from
+        # before the @ and around dots, on the assumption that the whitespace
+        # around the punctuation is a mistake in what would otherwise be
+        # an RFC5322 local part.  Leading whitespace is, usual, stripped as well.
+        self.assertEqual(('', "merwok wok at xample.com"),
+            utils.parseaddr("merwok wok at xample.com"))
+        self.assertEqual(('', "merwok  wok at xample.com"),
+            utils.parseaddr("merwok  wok at xample.com"))
+        self.assertEqual(('', "merwok  wok at xample.com"),
+            utils.parseaddr(" merwok  wok  @xample.com"))
+        self.assertEqual(('', 'merwok"wok"  wok at xample.com'),
+            utils.parseaddr('merwok"wok"  wok at xample.com'))
+        self.assertEqual(('', 'merwok.wok.wok at xample.com'),
+            utils.parseaddr('merwok. wok .  wok at xample.com'))
+
     def test_multiline_from_comment(self):
         x = """\
 Foo
@@ -2457,6 +2535,10 @@
     text/rfc822-headers
 """)
 
+    def test_make_msgid_domain(self):
+        self.assertEqual(
+            email.utils.make_msgid(domain='testdomain-string')[-19:],
+            '@testdomain-string>')
 
 
 # Test the iterator/generators
@@ -3577,7 +3659,7 @@
 Subject: This is a test message
 Date: Fri, 4 May 2001 14:05:44 -0400
 Content-Type: text/plain; charset=us-ascii;
- title*="us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21"
+ title*=us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21
 
 
 Hi,
@@ -3607,7 +3689,7 @@
 Subject: This is a test message
 Date: Fri, 4 May 2001 14:05:44 -0400
 Content-Type: text/plain; charset="us-ascii";
- title*="us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21"
+ title*=us-ascii'en'This%20is%20even%20more%20%2A%2A%2Afun%2A%2A%2A%20isn%27t%20it%21
 
 
 Hi,
@@ -3622,6 +3704,32 @@
         msg = self._msgobj('msg_32.txt')
         eq(msg.get_content_charset(), 'us-ascii')
 
+    def test_rfc2231_parse_rfc_quoting(self):
+        m = textwrap.dedent('''\
+            Content-Disposition: inline;
+            \tfilename*0*=''This%20is%20even%20more%20;
+            \tfilename*1*=%2A%2A%2Afun%2A%2A%2A%20;
+            \tfilename*2="is it not.pdf"
+
+            ''')
+        msg = email.message_from_string(m)
+        self.assertEqual(msg.get_filename(),
+                         'This is even more ***fun*** is it not.pdf')
+        self.assertEqual(m, msg.as_string())
+
+    def test_rfc2231_parse_extra_quoting(self):
+        m = textwrap.dedent('''\
+            Content-Disposition: inline;
+            \tfilename*0*="''This%20is%20even%20more%20";
+            \tfilename*1*="%2A%2A%2Afun%2A%2A%2A%20";
+            \tfilename*2="is it not.pdf"
+
+            ''')
+        msg = email.message_from_string(m)
+        self.assertEqual(msg.get_filename(),
+                         'This is even more ***fun*** is it not.pdf')
+        self.assertEqual(m, msg.as_string())
+
     def test_rfc2231_no_language_or_charset(self):
         m = '''\
 Content-Transfer-Encoding: 8bit

Modified: python/branches/py3k-cdecimal/Lib/email/utils.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/email/utils.py	(original)
+++ python/branches/py3k-cdecimal/Lib/email/utils.py	Sun Jan  2 13:18:37 2011
@@ -148,13 +148,15 @@
 
 
 
-def make_msgid(idstring=None):
+def make_msgid(idstring=None, domain=None):
     """Returns a string suitable for RFC 2822 compliant Message-ID, e.g:
 
     <20020201195627.33539.96671 at nightshade.la.mastaler.com>
 
     Optional idstring if given is a string used to strengthen the
-    uniqueness of the message id.
+    uniqueness of the message id.  Optional domain if given provides the
+    portion of the message id after the '@'.  It defaults to the locally
+    defined hostname.
     """
     timeval = time.time()
     utcdate = time.strftime('%Y%m%d%H%M%S', time.gmtime(timeval))
@@ -164,8 +166,9 @@
         idstring = ''
     else:
         idstring = '.' + idstring
-    idhost = socket.getfqdn()
-    msgid = '<%s.%s.%s%s@%s>' % (utcdate, pid, randint, idstring, idhost)
+    if domain is None:
+        domain = socket.getfqdn()
+    msgid = '<%s.%s.%s%s@%s>' % (utcdate, pid, randint, idstring, domain)
     return msgid
 
 

Modified: python/branches/py3k-cdecimal/Lib/encodings/aliases.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/encodings/aliases.py	(original)
+++ python/branches/py3k-cdecimal/Lib/encodings/aliases.py	Sun Jan  2 13:18:37 2011
@@ -33,9 +33,9 @@
     'us'                 : 'ascii',
     'us_ascii'           : 'ascii',
 
-    ## base64_codec codec
-    #'base64'             : 'base64_codec',
-    #'base_64'            : 'base64_codec',
+    # base64_codec codec
+    'base64'             : 'base64_codec',
+    'base_64'            : 'base64_codec',
 
     # big5 codec
     'big5_tw'            : 'big5',
@@ -45,8 +45,8 @@
     'big5_hkscs'         : 'big5hkscs',
     'hkscs'              : 'big5hkscs',
 
-    ## bz2_codec codec
-    #'bz2'                : 'bz2_codec',
+    # bz2_codec codec
+    'bz2'                : 'bz2_codec',
 
     # cp037 codec
     '037'                : 'cp037',
@@ -248,8 +248,8 @@
     'cp936'              : 'gbk',
     'ms936'              : 'gbk',
 
-    ## hex_codec codec
-    #'hex'                : 'hex_codec',
+    # hex_codec codec
+    'hex'                : 'hex_codec',
 
     # hp_roman8 codec
     'roman8'             : 'hp_roman8',
@@ -450,13 +450,13 @@
     'cp154'              : 'ptcp154',
     'cyrillic_asian'     : 'ptcp154',
 
-    ## quopri_codec codec
-    #'quopri'             : 'quopri_codec',
-    #'quoted_printable'   : 'quopri_codec',
-    #'quotedprintable'    : 'quopri_codec',
+    # quopri_codec codec
+    'quopri'             : 'quopri_codec',
+    'quoted_printable'   : 'quopri_codec',
+    'quotedprintable'    : 'quopri_codec',
 
-    ## rot_13 codec
-    #'rot13'              : 'rot_13',
+    # rot_13 codec
+    'rot13'              : 'rot_13',
 
     # shift_jis codec
     'csshiftjis'         : 'shift_jis',
@@ -518,12 +518,12 @@
     'utf8_ucs2'          : 'utf_8',
     'utf8_ucs4'          : 'utf_8',
 
-    ## uu_codec codec
-    #'uu'                 : 'uu_codec',
+    # uu_codec codec
+    'uu'                 : 'uu_codec',
 
-    ## zlib_codec codec
-    #'zip'                : 'zlib_codec',
-    #'zlib'               : 'zlib_codec',
+    # zlib_codec codec
+    'zip'                : 'zlib_codec',
+    'zlib'               : 'zlib_codec',
 
     # temporary mac CJK aliases, will be replaced by proper codecs in 3.1
     'x_mac_japanese'      : 'shift_jis',

Modified: python/branches/py3k-cdecimal/Lib/functools.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/functools.py	(original)
+++ python/branches/py3k-cdecimal/Lib/functools.py	Sun Jan  2 13:18:37 2011
@@ -12,7 +12,7 @@
            'total_ordering', 'cmp_to_key', 'lru_cache', 'reduce', 'partial']
 
 from _functools import partial, reduce
-from collections import OrderedDict
+from collections import OrderedDict, namedtuple
 try:
     from _thread import allocate_lock as Lock
 except:
@@ -114,49 +114,91 @@
             raise TypeError('hash not implemented')
     return K
 
+_CacheInfo = namedtuple("CacheInfo", "hits misses maxsize currsize")
+
 def lru_cache(maxsize=100):
     """Least-recently-used cache decorator.
 
+    If *maxsize* is set to None, the LRU features are disabled and the cache
+    can grow without bound.
+
     Arguments to the cached function must be hashable.
-    Cache performance statistics stored in f.hits and f.misses.
-    Clear the cache using f.clear().
-    http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
+
+    View the cache statistics named tuple (hits, misses, maxsize, currsize) with
+    f.cache_info().  Clear the cache and statistics with f.cache_clear().
+    Access the underlying function with f.__wrapped__.
+
+    See:  http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
 
     """
-    def decorating_function(user_function, tuple=tuple, sorted=sorted,
-                            len=len, KeyError=KeyError):
-        cache = OrderedDict()           # ordered least recent to most recent
-        cache_popitem = cache.popitem
-        cache_renew = cache.move_to_end
-        kwd_mark = object()             # separate positional and keyword args
+    # Users should only access the lru_cache through its public API:
+    #       cache_info, cache_clear, and f.__wrapped__
+    # The internals of the lru_cache are encapsulated for thread safety and
+    # to allow the implementation to change (including a possible C version).
+
+    def decorating_function(user_function,
+                tuple=tuple, sorted=sorted, len=len, KeyError=KeyError):
+
+        hits = misses = 0
+        kwd_mark = object()             # separates positional and keyword args
         lock = Lock()
 
-        @wraps(user_function)
-        def wrapper(*args, **kwds):
-            key = args
-            if kwds:
-                key += (kwd_mark,) + tuple(sorted(kwds.items()))
-            try:
-                with lock:
+        if maxsize is None:
+            cache = dict()              # simple cache without ordering or size limit
+
+            @wraps(user_function)
+            def wrapper(*args, **kwds):
+                nonlocal hits, misses
+                key = args
+                if kwds:
+                    key += (kwd_mark,) + tuple(sorted(kwds.items()))
+                try:
                     result = cache[key]
-                    cache_renew(key)            # record recent use of this key
-                    wrapper.cache_hits += 1
-            except KeyError:
-                result = user_function(*args, **kwds)
-                with lock:
-                    cache[key] = result         # record recent use of this key
-                    wrapper.cache_misses += 1
-                    if len(cache) > maxsize:
-                        cache_popitem(0)        # purge least recently used cache entry
-            return result
+                    hits += 1
+                except KeyError:
+                    result = user_function(*args, **kwds)
+                    cache[key] = result
+                    misses += 1
+                return result
+        else:
+            cache = OrderedDict()       # ordered least recent to most recent
+            cache_popitem = cache.popitem
+            cache_renew = cache.move_to_end
+
+            @wraps(user_function)
+            def wrapper(*args, **kwds):
+                nonlocal hits, misses
+                key = args
+                if kwds:
+                    key += (kwd_mark,) + tuple(sorted(kwds.items()))
+                try:
+                    with lock:
+                        result = cache[key]
+                        cache_renew(key)        # record recent use of this key
+                        hits += 1
+                except KeyError:
+                    result = user_function(*args, **kwds)
+                    with lock:
+                        cache[key] = result     # record recent use of this key
+                        misses += 1
+                        if len(cache) > maxsize:
+                            cache_popitem(0)    # purge least recently used cache entry
+                return result
+
+        def cache_info():
+            """Report cache statistics"""
+            with lock:
+                return _CacheInfo(hits, misses, maxsize, len(cache))
 
         def cache_clear():
             """Clear the cache and cache statistics"""
+            nonlocal hits, misses
             with lock:
                 cache.clear()
-                wrapper.cache_hits = wrapper.cache_misses = 0
+                hits = misses = 0
 
-        wrapper.cache_hits = wrapper.cache_misses = 0
+        wrapper.cache_info = cache_info
         wrapper.cache_clear = cache_clear
         return wrapper
+
     return decorating_function

Modified: python/branches/py3k-cdecimal/Lib/getpass.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/getpass.py	(original)
+++ python/branches/py3k-cdecimal/Lib/getpass.py	Sun Jan  2 13:18:37 2011
@@ -166,12 +166,7 @@
     try:
         import msvcrt
     except ImportError:
-        try:
-            from EasyDialogs import AskPassword
-        except ImportError:
-            getpass = fallback_getpass
-        else:
-            getpass = AskPassword
+        getpass = fallback_getpass
     else:
         getpass = win_getpass
 else:

Modified: python/branches/py3k-cdecimal/Lib/gettext.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/gettext.py	(original)
+++ python/branches/py3k-cdecimal/Lib/gettext.py	Sun Jan  2 13:18:37 2011
@@ -46,7 +46,7 @@
 #   find this format documented anywhere.
 
 
-import locale, copy, os, re, struct, sys
+import locale, copy, io, os, re, struct, sys
 from errno import ENOENT
 
 
@@ -58,28 +58,13 @@
 _default_localedir = os.path.join(sys.prefix, 'share', 'locale')
 
 
-def test(condition, true, false):
-    """
-    Implements the C expression:
-
-      condition ? true : false
-
-    Required to correctly interpret plural forms.
-    """
-    if condition:
-        return true
-    else:
-        return false
-
-
 def c2py(plural):
     """Gets a C expression as used in PO files for plural forms and returns a
     Python lambda function that implements an equivalent expression.
     """
     # Security check, allow only the "n" identifier
-    from io import StringIO
     import token, tokenize
-    tokens = tokenize.generate_tokens(StringIO(plural).readline)
+    tokens = tokenize.generate_tokens(io.StringIO(plural).readline)
     try:
         danger = [x for x in tokens if x[0] == token.NAME and x[1] != 'n']
     except tokenize.TokenError:
@@ -96,11 +81,11 @@
     plural = expr.sub(' not \\1', plural)
 
     # Regular expression and replacement function used to transform
-    # "a?b:c" to "test(a,b,c)".
+    # "a?b:c" to "b if a else c".
     expr = re.compile(r'(.*?)\?(.*?):(.*)')
     def repl(x):
-        return "test(%s, %s, %s)" % (x.group(1), x.group(2),
-                                     expr.sub(repl, x.group(3)))
+        return "(%s if %s else %s)" % (x.group(2), x.group(1),
+                                       expr.sub(repl, x.group(3)))
 
     # Code to transform the plural expression, taking care of parentheses
     stack = ['']
@@ -123,36 +108,35 @@
 
 
 
-def _expand_lang(locale):
-    from locale import normalize
-    locale = normalize(locale)
+def _expand_lang(loc):
+    loc = locale.normalize(loc)
     COMPONENT_CODESET   = 1 << 0
     COMPONENT_TERRITORY = 1 << 1
     COMPONENT_MODIFIER  = 1 << 2
     # split up the locale into its base components
     mask = 0
-    pos = locale.find('@')
+    pos = loc.find('@')
     if pos >= 0:
-        modifier = locale[pos:]
-        locale = locale[:pos]
+        modifier = loc[pos:]
+        loc = loc[:pos]
         mask |= COMPONENT_MODIFIER
     else:
         modifier = ''
-    pos = locale.find('.')
+    pos = loc.find('.')
     if pos >= 0:
-        codeset = locale[pos:]
-        locale = locale[:pos]
+        codeset = loc[pos:]
+        loc = loc[:pos]
         mask |= COMPONENT_CODESET
     else:
         codeset = ''
-    pos = locale.find('_')
+    pos = loc.find('_')
     if pos >= 0:
-        territory = locale[pos:]
-        locale = locale[:pos]
+        territory = loc[pos:]
+        loc = loc[:pos]
         mask |= COMPONENT_TERRITORY
     else:
         territory = ''
-    language = locale
+    language = loc
     ret = []
     for i in range(mask+1):
         if not (i & ~mask):  # if all components for this combo exist ...

Modified: python/branches/py3k-cdecimal/Lib/html/parser.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/html/parser.py	(original)
+++ python/branches/py3k-cdecimal/Lib/html/parser.py	Sun Jan  2 13:18:37 2011
@@ -24,10 +24,14 @@
 piclose = re.compile('>')
 commentclose = re.compile(r'--\s*>')
 tagfind = re.compile('[a-zA-Z][-.a-zA-Z0-9:_]*')
+# Note, the strict one of this pair isn't really strict, but we can't
+# make it correctly strict without breaking backward compatibility.
 attrfind = re.compile(
     r'\s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(\s*=\s*'
     r'(\'[^\']*\'|"[^"]*"|[-a-zA-Z0-9./,:;+*%?!&$\(\)_#=~@]*))?')
-
+attrfind_tolerant = re.compile(
+    r'\s*([a-zA-Z_][-.:a-zA-Z_0-9]*)(\s*=\s*'
+    r'(\'[^\']*\'|"[^"]*"|[^>\s]*))?')
 locatestarttagend = re.compile(r"""
   <[a-zA-Z][-.a-zA-Z0-9:_]*          # tag name
   (?:\s+                             # whitespace before attribute name
@@ -42,6 +46,21 @@
    )*
   \s*                                # trailing whitespace
 """, re.VERBOSE)
+locatestarttagend_tolerant = re.compile(r"""
+  <[a-zA-Z][-.a-zA-Z0-9:_]*          # tag name
+  (?:\s*                             # optional whitespace before attribute name
+    (?:[a-zA-Z_][-.:a-zA-Z0-9_]*     # attribute name
+      (?:\s*=\s*                     # value indicator
+        (?:'[^']*'                   # LITA-enclosed value
+          |\"[^\"]*\"                # LIT-enclosed value
+          |[^'\">\s]+                # bare value
+         )
+         (?:\s*,)*                   # possibly followed by a comma
+       )?
+     )
+   )*
+  \s*                                # trailing whitespace
+""", re.VERBOSE)
 endendtag = re.compile('>')
 endtagfind = re.compile('')
 
@@ -86,9 +105,15 @@
 
     CDATA_CONTENT_ELEMENTS = ("script", "style")
 
+    def __init__(self, strict=True):
+        """Initialize and reset this instance.
 
-    def __init__(self):
-        """Initialize and reset this instance."""
+        If strict is set to True (the default), errors are raised when invalid
+        HTML is encountered.  If set to False, an attempt is instead made to
+        continue parsing, making "best guesses" about the intended meaning, in
+        a fashion similar to what browsers typically do.
+        """
+        self.strict = strict
         self.reset()
 
     def reset(self):
@@ -160,9 +185,18 @@
                 else:
                     break
                 if k < 0:
-                    if end:
+                    if not end:
+                        break
+                    if self.strict:
                         self.error("EOF in middle of construct")
-                    break
+                    k = rawdata.find('>', i + 1)
+                    if k < 0:
+                        k = rawdata.find('<', i + 1)
+                        if k < 0:
+                            k = i + 1
+                    else:
+                        k += 1
+                    self.handle_data(rawdata[i:k])
                 i = self.updatepos(i, k)
             elif startswith("&#", i):
                 match = charref.match(rawdata, i)
@@ -193,7 +227,12 @@
                 if match:
                     # match.group() will contain at least 2 chars
                     if end and match.group() == rawdata[i:]:
-                        self.error("EOF in middle of entity or char ref")
+                        if self.strict:
+                            self.error("EOF in middle of entity or char ref")
+                        else:
+                            if k <= i:
+                                k = n
+                            i = self.updatepos(i, i + 1)
                     # incomplete
                     break
                 elif (i + 1) < n:
@@ -240,7 +279,10 @@
         self.lasttag = tag = rawdata[i+1:k].lower()
 
         while k < endpos:
-            m = attrfind.match(rawdata, k)
+            if self.strict:
+                m = attrfind.match(rawdata, k)
+            else:
+                m = attrfind_tolerant.search(rawdata, k)
             if not m:
                 break
             attrname, rest, attrvalue = m.group(1, 2, 3)
@@ -262,8 +304,11 @@
                          - self.__starttag_text.rfind("\n")
             else:
                 offset = offset + len(self.__starttag_text)
-            self.error("junk characters in start tag: %r"
-                       % (rawdata[k:endpos][:20],))
+            if self.strict:
+                self.error("junk characters in start tag: %r"
+                           % (rawdata[k:endpos][:20],))
+            self.handle_data(rawdata[i:endpos])
+            return endpos
         if end.endswith('/>'):
             # XHTML-style empty tag: 
             self.handle_startendtag(tag, attrs)
@@ -277,7 +322,10 @@
     # or -1 if incomplete.
     def check_for_whole_start_tag(self, i):
         rawdata = self.rawdata
-        m = locatestarttagend.match(rawdata, i)
+        if self.strict:
+            m = locatestarttagend.match(rawdata, i)
+        else:
+            m = locatestarttagend_tolerant.match(rawdata, i)
         if m:
             j = m.end()
             next = rawdata[j:j+1]
@@ -290,8 +338,13 @@
                     # buffer boundary
                     return -1
                 # else bogus input
-                self.updatepos(i, j + 1)
-                self.error("malformed empty start tag")
+                if self.strict:
+                    self.updatepos(i, j + 1)
+                    self.error("malformed empty start tag")
+                if j > i:
+                    return j
+                else:
+                    return i + 1
             if next == "":
                 # end of input
                 return -1
@@ -300,8 +353,13 @@
                 # end of input in or before attribute value, or we have the
                 # '/' from a '/>' ending
                 return -1
-            self.updatepos(i, j)
-            self.error("malformed start tag")
+            if self.strict:
+                self.updatepos(i, j)
+                self.error("malformed start tag")
+            if j > i:
+                return j
+            else:
+                return i + 1
         raise AssertionError("we should not get here!")
 
     # Internal -- parse endtag, return end or -1 if incomplete
@@ -314,7 +372,15 @@
         j = match.end()
         match = endtagfind.match(rawdata, i) # 
         if not match:
-            self.error("bad end tag: %r" % (rawdata[i:j],))
+            if self.strict:
+                self.error("bad end tag: %r" % (rawdata[i:j],))
+            k = rawdata.find('<', i + 1, j)
+            if k > i:
+                j = k
+            if j <= i:
+                j = i + 1
+            self.handle_data(rawdata[i:j])
+            return j
         tag = match.group(1)
         self.handle_endtag(tag.lower())
         self.clear_cdata_mode()
@@ -358,7 +424,8 @@
         pass
 
     def unknown_decl(self, data):
-        self.error("unknown declaration: %r" % (data,))
+        if self.strict:
+            self.error("unknown declaration: %r" % (data,))
 
     # Internal -- helper to remove special character quoting
     entitydefs = None
@@ -367,13 +434,16 @@
             return s
         def replaceEntities(s):
             s = s.groups()[0]
-            if s[0] == "#":
-                s = s[1:]
-                if s[0] in ['x','X']:
-                    c = int(s[1:], 16)
-                else:
-                    c = int(s)
-                return chr(c)
+            try:
+                if s[0] == "#":
+                    s = s[1:]
+                    if s[0] in ['x','X']:
+                        c = int(s[1:], 16)
+                    else:
+                        c = int(s)
+                    return chr(c)
+            except ValueError:
+                return '&#'+ s +';'
             else:
                 # Cannot use name2codepoint directly, because HTMLParser
                 # supports apos, which is not part of HTML 4

Modified: python/branches/py3k-cdecimal/Lib/http/client.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/http/client.py	(original)
+++ python/branches/py3k-cdecimal/Lib/http/client.py	Sun Jan  2 13:18:37 2011
@@ -71,6 +71,7 @@
 import io
 import os
 import socket
+import collections
 from urllib.parse import urlsplit
 import warnings
 
@@ -203,6 +204,9 @@
 # maximal amount of data to read at one time in _safe_read
 MAXAMOUNT = 1048576
 
+# maximal line length when calling readline().
+_MAXLINE = 65536
+
 class HTTPMessage(email.message.Message):
     # XXX The only usage of this method is in
     # http.server.CGIHTTPRequestHandler.  Maybe move the code there so
@@ -245,20 +249,19 @@
     """
     headers = []
     while True:
-        line = fp.readline()
+        line = fp.readline(_MAXLINE + 1)
+        if len(line) > _MAXLINE:
+            raise LineTooLong("header line")
         headers.append(line)
         if line in (b'\r\n', b'\n', b''):
             break
     hstring = b''.join(headers).decode('iso-8859-1')
     return email.parser.Parser(_class=_class).parsestr(hstring)
 
-class HTTPResponse(io.RawIOBase):
 
-    # strict: If true, raise BadStatusLine if the status line can't be
-    # parsed as a valid HTTP/1.0 or 1.1 status line.  By default it is
-    # false because it prevents clients from talking to HTTP/0.9
-    # servers.  Note that a response with a sufficiently corrupted
-    # status line will look like an HTTP/0.9 response.
+_strict_sentinel = object()
+
+class HTTPResponse(io.RawIOBase):
 
     # See RFC 2616 sec 19.6 and RFC 1945 sec 6 for details.
 
@@ -267,7 +270,7 @@
     # text following RFC 2047.  The basic status line parsing only
     # accepts iso-8859-1.
 
-    def __init__(self, sock, debuglevel=0, strict=0, method=None, url=None):
+    def __init__(self, sock, debuglevel=0, strict=_strict_sentinel, method=None, url=None):
         # If the response includes a content-length header, we need to
         # make sure that the client doesn't read more than the
         # specified number of bytes.  If it does, it will block until
@@ -277,7 +280,10 @@
         # clients unless they know what they are doing.
         self.fp = sock.makefile("rb")
         self.debuglevel = debuglevel
-        self.strict = strict
+        if strict is not _strict_sentinel:
+            warnings.warn("the 'strict' argument isn't supported anymore; "
+                "http.client now always assumes HTTP/1.x compliant servers.",
+                DeprecationWarning, 2)
         self._method = method
 
         # The HTTPResponse object is returned via urllib.  The clients
@@ -299,8 +305,9 @@
         self.will_close = _UNKNOWN      # conn will close at end of response
 
     def _read_status(self):
-        # Initialize with Simple-Response defaults.
-        line = str(self.fp.readline(), "iso-8859-1")
+        line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
+        if len(line) > _MAXLINE:
+            raise LineTooLong("status line")
         if self.debuglevel > 0:
             print("reply:", repr(line))
         if not line:
@@ -308,25 +315,17 @@
             # sending a valid response.
             raise BadStatusLine(line)
         try:
-            [version, status, reason] = line.split(None, 2)
+            version, status, reason = line.split(None, 2)
         except ValueError:
             try:
-                [version, status] = line.split(None, 1)
+                version, status = line.split(None, 1)
                 reason = ""
             except ValueError:
-                # empty version will cause next test to fail and status
-                # will be treated as 0.9 response.
+                # empty version will cause next test to fail.
                 version = ""
         if not version.startswith("HTTP/"):
-            if self.strict:
-                self.close()
-                raise BadStatusLine(line)
-            else:
-                # Assume it's a Simple-Response from an 0.9 server.
-                # We have to convert the first line back to raw bytes
-                # because self.fp.readline() needs to return bytes.
-                self.fp = LineAndFileWrapper(bytes(line, "ascii"), self.fp)
-                return "HTTP/0.9", 200, ""
+            self.close()
+            raise BadStatusLine(line)
 
         # The status code is a three-digit number
         try:
@@ -349,7 +348,10 @@
                 break
             # skip the header from the 100 response
             while True:
-                skip = self.fp.readline().strip()
+                skip = self.fp.readline(_MAXLINE + 1)
+                if len(skip) > _MAXLINE:
+                    raise LineTooLong("header line")
+                skip = skip.strip()
                 if not skip:
                     break
                 if self.debuglevel > 0:
@@ -357,22 +359,14 @@
 
         self.code = self.status = status
         self.reason = reason.strip()
-        if version == "HTTP/1.0":
+        if version in ("HTTP/1.0", "HTTP/0.9"):
+            # Some servers might still return "0.9", treat it as 1.0 anyway
             self.version = 10
         elif version.startswith("HTTP/1."):
             self.version = 11   # use HTTP/1.1 code for HTTP/1.x where x>=1
-        elif version == "HTTP/0.9":
-            self.version = 9
         else:
             raise UnknownProtocol(version)
 
-        if self.version == 9:
-            self.length = None
-            self.chunked = False
-            self.will_close = True
-            self.headers = self.msg = email.message_from_string('')
-            return
-
         self.headers = self.msg = parse_headers(self.fp)
 
         if self.debuglevel > 0:
@@ -525,7 +519,9 @@
         value = []
         while True:
             if chunk_left is None:
-                line = self.fp.readline()
+                line = self.fp.readline(_MAXLINE + 1)
+                if len(line) > _MAXLINE:
+                    raise LineTooLong("chunk size")
                 i = line.find(b";")
                 if i >= 0:
                     line = line[:i] # strip chunk-extensions
@@ -560,7 +556,9 @@
         # read and discard trailer up to the CRLF terminator
         ### note: we shouldn't have any trailers!
         while True:
-            line = self.fp.readline()
+            line = self.fp.readline(_MAXLINE + 1)
+            if len(line) > _MAXLINE:
+                raise LineTooLong("trailer line")
             if not line:
                 # a vanishingly small number of sites EOF without
                 # sending the trailer
@@ -639,10 +637,13 @@
     default_port = HTTP_PORT
     auto_open = 1
     debuglevel = 0
-    strict = 0
 
-    def __init__(self, host, port=None, strict=None,
+    def __init__(self, host, port=None, strict=_strict_sentinel,
                  timeout=socket._GLOBAL_DEFAULT_TIMEOUT, source_address=None):
+        if strict is not _strict_sentinel:
+            warnings.warn("the 'strict' argument isn't supported anymore; "
+                "http.client now always assumes HTTP/1.x compliant servers.",
+                DeprecationWarning, 2)
         self.timeout = timeout
         self.source_address = source_address
         self.sock = None
@@ -654,8 +655,6 @@
         self._tunnel_port = None
 
         self._set_hostport(host, port)
-        if strict is not None:
-            self.strict = strict
 
     def set_tunnel(self, host, port=None, headers=None):
         """ Sets up the host and the port for the HTTP CONNECT Tunnelling.
@@ -700,8 +699,7 @@
             header_bytes = header_str.encode("ascii")
             self.send(header_bytes)
 
-        response = self.response_class(self.sock, strict = self.strict,
-                                       method = self._method)
+        response = self.response_class(self.sock, method = self._method)
         (version, code, message) = response._read_status()
 
         if code != 200:
@@ -709,7 +707,9 @@
             raise socket.error("Tunnel connection failed: %d %s" % (code,
                                                                     message.strip()))
         while True:
-            line = response.fp.readline()
+            line = response.fp.readline(_MAXLINE + 1)
+            if len(line) > _MAXLINE:
+                raise LineTooLong("header line")
             if line == b'\r\n':
                 break
 
@@ -731,7 +731,11 @@
         self.__state = _CS_IDLE
 
     def send(self, data):
-        """Send `data' to the server."""
+        """Send `data' to the server.
+        ``data`` can be a string object, a bytes object, an array object, a
+        file-like object that supports a .read() method, or an iterable object.
+        """
+
         if self.sock is None:
             if self.auto_open:
                 self.connect()
@@ -763,8 +767,16 @@
                 if encode:
                     datablock = datablock.encode("iso-8859-1")
                 self.sock.sendall(datablock)
-        else:
+
+        try:
             self.sock.sendall(data)
+        except TypeError:
+            if isinstance(data, collections.Iterable):
+                for d in data:
+                    self.sock.sendall(d)
+            else:
+                raise TypeError("data should be a bytes-like object\
+                        or an iterable, got %r " % type(it))
 
     def _output(self, s):
         """Add a line of output to the current request buffer.
@@ -1025,11 +1037,9 @@
 
         if self.debuglevel > 0:
             response = self.response_class(self.sock, self.debuglevel,
-                                           strict=self.strict,
                                            method=self._method)
         else:
-            response = self.response_class(self.sock, strict=self.strict,
-                                           method=self._method)
+            response = self.response_class(self.sock, method=self._method)
 
         response.begin()
         assert response.will_close != _UNKNOWN
@@ -1057,7 +1067,7 @@
         # XXX Should key_file and cert_file be deprecated in favour of context?
 
         def __init__(self, host, port=None, key_file=None, cert_file=None,
-                     strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
+                     strict=_strict_sentinel, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
                      source_address=None, *, context=None, check_hostname=None):
             super(HTTPSConnection, self).__init__(host, port, strict, timeout,
                                                   source_address)
@@ -1156,73 +1166,10 @@
         self.args = line,
         self.line = line
 
+class LineTooLong(HTTPException):
+    def __init__(self, line_type):
+        HTTPException.__init__(self, "got more than %d bytes when reading %s"
+                                     % (_MAXLINE, line_type))
+
 # for backwards compatibility
 error = HTTPException
-
-class LineAndFileWrapper:
-    """A limited file-like object for HTTP/0.9 responses."""
-
-    # The status-line parsing code calls readline(), which normally
-    # get the HTTP status line.  For a 0.9 response, however, this is
-    # actually the first line of the body!  Clients need to get a
-    # readable file object that contains that line.
-
-    def __init__(self, line, file):
-        self._line = line
-        self._file = file
-        self._line_consumed = 0
-        self._line_offset = 0
-        self._line_left = len(line)
-
-    def __getattr__(self, attr):
-        return getattr(self._file, attr)
-
-    def _done(self):
-        # called when the last byte is read from the line.  After the
-        # call, all read methods are delegated to the underlying file
-        # object.
-        self._line_consumed = 1
-        self.read = self._file.read
-        self.readline = self._file.readline
-        self.readlines = self._file.readlines
-
-    def read(self, amt=None):
-        if self._line_consumed:
-            return self._file.read(amt)
-        assert self._line_left
-        if amt is None or amt > self._line_left:
-            s = self._line[self._line_offset:]
-            self._done()
-            if amt is None:
-                return s + self._file.read()
-            else:
-                return s + self._file.read(amt - len(s))
-        else:
-            assert amt <= self._line_left
-            i = self._line_offset
-            j = i + amt
-            s = self._line[i:j]
-            self._line_offset = j
-            self._line_left -= amt
-            if self._line_left == 0:
-                self._done()
-            return s
-
-    def readline(self):
-        if self._line_consumed:
-            return self._file.readline()
-        assert self._line_left
-        s = self._line[self._line_offset:]
-        self._done()
-        return s
-
-    def readlines(self, size=None):
-        if self._line_consumed:
-            return self._file.readlines(size)
-        assert self._line_left
-        L = [self._line[self._line_offset:]]
-        self._done()
-        if size is None:
-            return L + self._file.readlines()
-        else:
-            return L + self._file.readlines(size)

Modified: python/branches/py3k-cdecimal/Lib/http/cookies.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/http/cookies.py	(original)
+++ python/branches/py3k-cdecimal/Lib/http/cookies.py	Sun Jan  2 13:18:37 2011
@@ -173,6 +173,11 @@
     '\033' : '\\033',  '\034' : '\\034',  '\035' : '\\035',
     '\036' : '\\036',  '\037' : '\\037',
 
+    # Because of the way browsers really handle cookies (as opposed
+    # to what the RFC says) we also encode , and ;
+
+    ',' : '\\054', ';' : '\\073',
+
     '"' : '\\"',       '\\' : '\\\\',
 
     '\177' : '\\177',  '\200' : '\\200',  '\201' : '\\201',
@@ -230,7 +235,7 @@
     if all(c in LegalChars for c in str):
         return str
     else:
-        return '"' + _nulljoin(map(_Translator.get, str, str)) + '"'
+        return '"' + _nulljoin(_Translator.get(s, s) for s in str) + '"'
 
 
 _OctalPatt = re.compile(r"\\[0-3][0-7][0-7]")

Modified: python/branches/py3k-cdecimal/Lib/http/server.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/http/server.py	(original)
+++ python/branches/py3k-cdecimal/Lib/http/server.py	Sun Jan  2 13:18:37 2011
@@ -314,8 +314,12 @@
         self.command, self.path, self.request_version = command, path, version
 
         # Examine the headers and look for a Connection directive.
-        self.headers = http.client.parse_headers(self.rfile,
-                                                 _class=self.MessageClass)
+        try:
+            self.headers = http.client.parse_headers(self.rfile,
+                                                     _class=self.MessageClass)
+        except http.client.LineTooLong:
+            self.send_error(400, "Line too long")
+            return False
 
         conntype = self.headers.get('Connection', "")
         if conntype.lower() == 'close':
@@ -358,7 +362,13 @@
 
         """
         try:
-            self.raw_requestline = self.rfile.readline()
+            self.raw_requestline = self.rfile.readline(65537)
+            if len(self.raw_requestline) > 65536:
+                self.requestline = ''
+                self.request_version = ''
+                self.command = ''
+                self.send_error(414)
+                return
             if not self.raw_requestline:
                 self.close_connection = 1
                 return
@@ -868,7 +878,7 @@
     try:
         nobody = pwd.getpwnam('nobody')[2]
     except KeyError:
-        nobody = 1 + max(map(lambda x: x[2], pwd.getpwall()))
+        nobody = 1 + max(x[2] for x in pwd.getpwall())
     return nobody
 
 

Modified: python/branches/py3k-cdecimal/Lib/idlelib/Bindings.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/idlelib/Bindings.py	(original)
+++ python/branches/py3k-cdecimal/Lib/idlelib/Bindings.py	Sun Jan  2 13:18:37 2011
@@ -98,14 +98,6 @@
     # menu
     del menudefs[-1][1][0:2]
 
-    menudefs.insert(0,
-            ('application', [
-                ('About IDLE', '<>'),
-                None,
-                ('_Preferences....', '<>'),
-            ]))
-
-
 default_keydefs = idleConf.GetCurrentKeySet()
 
 del sys

Modified: python/branches/py3k-cdecimal/Lib/idlelib/EditorWindow.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/idlelib/EditorWindow.py	(original)
+++ python/branches/py3k-cdecimal/Lib/idlelib/EditorWindow.py	Sun Jan  2 13:18:37 2011
@@ -138,6 +138,14 @@
         if macosxSupport.runningAsOSXApp():
             # Command-W on editorwindows doesn't work without this.
             text.bind('<>', self.close_event)
+            # Some OS X systems have only one mouse button,
+            # so use control-click for pulldown menus there.
+            #  (Note, AquaTk defines <2> as the right button if
+            #   present and the Tk Text widget already binds <2>.)
+            text.bind("",self.right_menu_event)
+        else:
+            # Elsewhere, use right-click for pulldown menus.
+            text.bind("<3>",self.right_menu_event)
         text.bind("<>", self.cut)
         text.bind("<>", self.copy)
         text.bind("<>", self.paste)
@@ -156,7 +164,6 @@
         text.bind("<>", self.find_selection_event)
         text.bind("<>", self.replace_event)
         text.bind("<>", self.goto_line_event)
-        text.bind("<3>", self.right_menu_event)
         text.bind("<>",self.smart_backspace_event)
         text.bind("<>",self.newline_and_indent_event)
         text.bind("<>",self.smart_indent_event)
@@ -380,7 +387,7 @@
             underline, label = prepstr(label)
             menudict[name] = menu = Menu(mbar, name=name)
             mbar.add_cascade(label=label, menu=menu, underline=underline)
-        if macosxSupport.runningAsOSXApp():
+        if macosxSupport.isCarbonAquaTk(self.root):
             # Insert the application menu
             menudict['application'] = menu = Menu(mbar, name='apple')
             mbar.add_cascade(label='IDLE', menu=menu)
@@ -443,7 +450,11 @@
 
     def python_docs(self, event=None):
         if sys.platform[:3] == 'win':
-            os.startfile(self.help_url)
+            try:
+                os.startfile(self.help_url)
+            except WindowsError as why:
+                tkMessageBox.showerror(title='Document Start Failure',
+                    message=str(why), parent=self.text)
         else:
             webbrowser.open(self.help_url)
         return "break"
@@ -746,9 +757,13 @@
         "Create a callback with the helpfile value frozen at definition time"
         def display_extra_help(helpfile=helpfile):
             if not helpfile.startswith(('www', 'http')):
-                url = os.path.normpath(helpfile)
+                helpfile = os.path.normpath(helpfile)
             if sys.platform[:3] == 'win':
-                os.startfile(helpfile)
+                try:
+                    os.startfile(helpfile)
+                except WindowsError as why:
+                    tkMessageBox.showerror(title='Document Start Failure',
+                        message=str(why), parent=self.text)
             else:
                 webbrowser.open(helpfile)
         return display_extra_help

Modified: python/branches/py3k-cdecimal/Lib/idlelib/FileList.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/idlelib/FileList.py	(original)
+++ python/branches/py3k-cdecimal/Lib/idlelib/FileList.py	Sun Jan  2 13:18:37 2011
@@ -48,7 +48,7 @@
     def new(self, filename=None):
         return self.EditorWindow(self, filename)
 
-    def close_all_callback(self, event):
+    def close_all_callback(self, *args, **kwds):
         for edit in list(self.inversedict):
             reply = edit.close()
             if reply == "cancel":

Modified: python/branches/py3k-cdecimal/Lib/idlelib/IOBinding.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/idlelib/IOBinding.py	(original)
+++ python/branches/py3k-cdecimal/Lib/idlelib/IOBinding.py	Sun Jan  2 13:18:37 2011
@@ -476,8 +476,8 @@
     savedialog = None
 
     filetypes = [
-        ("Python and text files", "*.py *.pyw *.txt", "TEXT"),
-        ("All text files", "*", "TEXT"),
+        ("Python files", "*.py *.pyw", "TEXT"),
+        ("Text files", "*.txt", "TEXT"),
         ("All files", "*"),
         ]
 

Modified: python/branches/py3k-cdecimal/Lib/idlelib/idlever.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/idlelib/idlever.py	(original)
+++ python/branches/py3k-cdecimal/Lib/idlelib/idlever.py	Sun Jan  2 13:18:37 2011
@@ -1 +1 @@
-IDLE_VERSION = "3.2a4"
+IDLE_VERSION = "3.2b2"

Modified: python/branches/py3k-cdecimal/Lib/idlelib/macosxSupport.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/idlelib/macosxSupport.py	(original)
+++ python/branches/py3k-cdecimal/Lib/idlelib/macosxSupport.py	Sun Jan  2 13:18:37 2011
@@ -4,6 +4,7 @@
 """
 import sys
 import tkinter
+from os import path
 
 
 _appbundle = None
@@ -19,6 +20,20 @@
         _appbundle = (sys.platform == 'darwin' and '.app' in sys.executable)
     return _appbundle
 
+_carbonaquatk = None
+
+def isCarbonAquaTk(root):
+    """
+    Returns True if IDLE is using a Carbon Aqua Tk (instead of the
+    newer Cocoa Aqua Tk).
+    """
+    global _carbonaquatk
+    if _carbonaquatk is None:
+        _carbonaquatk = (runningAsOSXApp() and
+                         'aqua' in root.tk.call('tk', 'windowingsystem') and
+                         'AppKit' not in root.tk.call('winfo', 'server', '.'))
+    return _carbonaquatk
+
 def addOpenEventSupport(root, flist):
     """
     This ensures that the application will respont to open AppleEvents, which
@@ -79,9 +94,6 @@
         WindowList.add_windows_to_menu(menu)
     WindowList.register_callback(postwindowsmenu)
 
-    menudict['application'] = menu = Menu(menubar, name='apple')
-    menubar.add_cascade(label='IDLE', menu=menu)
-
     def about_dialog(event=None):
         from idlelib import aboutDialog
         aboutDialog.AboutDialog(root, 'About IDLE')
@@ -97,41 +109,45 @@
         root.instance_dict = flist.inversedict
         configDialog.ConfigDialog(root, 'Settings')
 
+    def help_dialog(event=None):
+        from idlelib import textView
+        fn = path.join(path.abspath(path.dirname(__file__)), 'help.txt')
+        textView.view_file(root, 'Help', fn)
 
     root.bind('<>', about_dialog)
     root.bind('<>', config_dialog)
+    root.createcommand('::tk::mac::ShowPreferences', config_dialog)
     if flist:
         root.bind('<>', flist.close_all_callback)
 
-
-    ###check if Tk version >= 8.4.14; if so, use hard-coded showprefs binding
-    tkversion = root.tk.eval('info patchlevel')
-    # Note: we cannot check if the string tkversion >= '8.4.14', because
-    # the string '8.4.7' is greater than the string '8.4.14'.
-    if tuple(map(int, tkversion.split('.'))) >= (8, 4, 14):
-        Bindings.menudefs[0] =  ('application', [
+        # The binding above doesn't reliably work on all versions of Tk
+        # on MacOSX. Adding command definition below does seem to do the
+        # right thing for now.
+        root.createcommand('exit', flist.close_all_callback)
+
+    if isCarbonAquaTk(root):
+        # for Carbon AquaTk, replace the default Tk apple menu
+        menudict['application'] = menu = Menu(menubar, name='apple')
+        menubar.add_cascade(label='IDLE', menu=menu)
+        Bindings.menudefs.insert(0,
+            ('application', [
                 ('About IDLE', '<>'),
-                None,
-            ])
-        root.createcommand('::tk::mac::ShowPreferences', config_dialog)
+                    None,
+                ]))
+        tkversion = root.tk.eval('info patchlevel')
+        if tuple(map(int, tkversion.split('.'))) < (8, 4, 14):
+            # for earlier AquaTk versions, supply a Preferences menu item
+            Bindings.menudefs[0][1].append(
+                    ('_Preferences....', '<>'),
+                )
     else:
-        for mname, entrylist in Bindings.menudefs:
-            menu = menudict.get(mname)
-            if not menu:
-                continue
-            else:
-                for entry in entrylist:
-                    if not entry:
-                        menu.add_separator()
-                    else:
-                        label, eventname = entry
-                        underline, label = prepstr(label)
-                        accelerator = get_accelerator(Bindings.default_keydefs,
-                        eventname)
-                        def command(text=root, eventname=eventname):
-                            text.event_generate(eventname)
-                        menu.add_command(label=label, underline=underline,
-                        command=command, accelerator=accelerator)
+        # assume Cocoa AquaTk
+        # replace default About dialog with About IDLE one
+        root.createcommand('tkAboutDialog', about_dialog)
+        # replace default "Help" item in Help menu
+        root.createcommand('::tk::mac::ShowHelp', help_dialog)
+        # remove redundant "IDLE Help" from menu
+        del Bindings.menudefs[-1][1][0]
 
 def setupApp(root, flist):
     """

Modified: python/branches/py3k-cdecimal/Lib/inspect.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/inspect.py	(original)
+++ python/branches/py3k-cdecimal/Lib/inspect.py	Sun Jan  2 13:18:37 2011
@@ -1130,7 +1130,10 @@
     raise AttributeError(attr)
 
 
-GEN_CREATED, GEN_RUNNING, GEN_SUSPENDED, GEN_CLOSED = range(4)
+GEN_CREATED = 'GEN_CREATED'
+GEN_RUNNING = 'GEN_RUNNING'
+GEN_SUSPENDED = 'GEN_SUSPENDED'
+GEN_CLOSED = 'GEN_CLOSED'
 
 def getgeneratorstate(generator):
     """Get current state of a generator-iterator.

Modified: python/branches/py3k-cdecimal/Lib/lib2to3/fixes/fix_urllib.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/lib2to3/fixes/fix_urllib.py	(original)
+++ python/branches/py3k-cdecimal/Lib/lib2to3/fixes/fix_urllib.py	Sun Jan  2 13:18:37 2011
@@ -12,7 +12,7 @@
 
 MAPPING = {"urllib":  [
                 ("urllib.request",
-                    ["URLOpener", "FancyURLOpener", "urlretrieve",
+                    ["URLopener", "FancyURLopener", "urlretrieve",
                      "_urlopener", "urlopen", "urlcleanup",
                      "pathname2url", "url2pathname"]),
                 ("urllib.parse",

Modified: python/branches/py3k-cdecimal/Lib/lib2to3/main.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/lib2to3/main.py	(original)
+++ python/branches/py3k-cdecimal/Lib/lib2to3/main.py	Sun Jan  2 13:18:37 2011
@@ -100,7 +100,7 @@
     parser.add_option("-j", "--processes", action="store", default=1,
                       type="int", help="Run 2to3 concurrently")
     parser.add_option("-x", "--nofix", action="append", default=[],
-                      help="Prevent a fixer from being run.")
+                      help="Prevent a transformation from being run")
     parser.add_option("-l", "--list-fixes", action="store_true",
                       help="List available transformations")
     parser.add_option("-p", "--print-function", action="store_true",
@@ -112,7 +112,7 @@
     parser.add_option("-w", "--write", action="store_true",
                       help="Write back modified files")
     parser.add_option("-n", "--nobackups", action="store_true", default=False,
-                      help="Don't write backups for modified files.")
+                      help="Don't write backups for modified files")
 
     # Parse command line arguments
     refactor_stdin = False

Modified: python/branches/py3k-cdecimal/Lib/lib2to3/refactor.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/lib2to3/refactor.py	(original)
+++ python/branches/py3k-cdecimal/Lib/lib2to3/refactor.py	Sun Jan  2 13:18:37 2011
@@ -302,13 +302,14 @@
 
         Files and subdirectories starting with '.' are skipped.
         """
+        py_ext = os.extsep + "py"
         for dirpath, dirnames, filenames in os.walk(dir_name):
             self.log_debug("Descending into %s", dirpath)
             dirnames.sort()
             filenames.sort()
             for name in filenames:
-                if not name.startswith(".") and \
-                        os.path.splitext(name)[1].endswith("py"):
+                if (not name.startswith(".") and
+                    os.path.splitext(name)[1] == py_ext):
                     fullname = os.path.join(dirpath, name)
                     self.refactor_file(fullname, write, doctests_only)
             # Modify dirnames in-place to remove subdirs with leading dots

Modified: python/branches/py3k-cdecimal/Lib/lib2to3/tests/test_refactor.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/lib2to3/tests/test_refactor.py	(original)
+++ python/branches/py3k-cdecimal/Lib/lib2to3/tests/test_refactor.py	Sun Jan  2 13:18:37 2011
@@ -223,6 +223,7 @@
                 "hi.py",
                 ".dumb",
                 ".after.py",
+                "notpy.npy",
                 "sappy"]
         expected = ["hi.py"]
         check(tree, expected)

Modified: python/branches/py3k-cdecimal/Lib/lib2to3/tests/test_util.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/lib2to3/tests/test_util.py	(original)
+++ python/branches/py3k-cdecimal/Lib/lib2to3/tests/test_util.py	Sun Jan  2 13:18:37 2011
@@ -568,8 +568,8 @@
 
     def test_from_import(self):
         node = parse('bar()')
-        fixer_util.touch_import("cgi", "escape", node)
-        self.assertEqual(str(node), 'from cgi import escape\nbar()\n\n')
+        fixer_util.touch_import("html", "escape", node)
+        self.assertEqual(str(node), 'from html import escape\nbar()\n\n')
 
     def test_name_import(self):
         node = parse('bar()')

Modified: python/branches/py3k-cdecimal/Lib/logging/__init__.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/logging/__init__.py	(original)
+++ python/branches/py3k-cdecimal/Lib/logging/__init__.py	Sun Jan  2 13:18:37 2011
@@ -33,7 +33,7 @@
            'captureWarnings', 'critical', 'debug', 'disable', 'error',
            'exception', 'fatal', 'getLevelName', 'getLogger', 'getLoggerClass',
            'info', 'log', 'makeLogRecord', 'setLoggerClass', 'warn', 'warning',
-           'getLogRecordClass', 'setLogRecordClass']
+           'getLogRecordFactory', 'setLogRecordFactory', 'lastResort']
 
 try:
     import codecs
@@ -238,7 +238,7 @@
     information to be logged.
     """
     def __init__(self, name, level, pathname, lineno,
-                 msg, args, exc_info, func=None, sinfo=None):
+                 msg, args, exc_info, func=None, sinfo=None, **kwargs):
         """
         Initialize a logging record with interesting information.
         """
@@ -322,21 +322,24 @@
 #
 #   Determine which class to use when instantiating log records.
 #
-_logRecordClass = LogRecord
+_logRecordFactory = LogRecord
 
-def setLogRecordClass(cls):
+def setLogRecordFactory(factory):
     """
-    Set the class to be used when instantiating a log record.
+    Set the factory to be used when instantiating a log record.
+
+    :param factory: A callable which will be called to instantiate
+    a log record.
     """
-    global _logRecordClass
-    _logRecordClass = cls
+    global _logRecordFactory
+    _logRecordFactory = factory
 
-def getLogRecordClass():
+def getLogRecordFactory():
     """
-    Return the class to be used when instantiating a log record.
+    Return the factory to be used when instantiating a log record.
     """
 
-    return _logRecordClass
+    return _logRecordFactory
 
 def makeLogRecord(dict):
     """
@@ -345,7 +348,7 @@
     a socket connection (which is sent as a dictionary) into a LogRecord
     instance.
     """
-    rv = _logRecordClass(None, None, "", 0, "", (), None, None)
+    rv = _logRecordFactory(None, None, "", 0, "", (), None, None)
     rv.__dict__.update(dict)
     return rv
 
@@ -994,6 +997,26 @@
             self.stream = self._open()
         StreamHandler.emit(self, record)
 
+class _StderrHandler(StreamHandler):
+    """
+    This class is like a StreamHandler using sys.stderr, but always uses
+    whatever sys.stderr is currently set to rather than the value of
+    sys.stderr at handler construction time.
+    """
+    def __init__(self, level=NOTSET):
+        """
+        Initialize the handler.
+        """
+        Handler.__init__(self, level)
+
+    @property
+    def stream(self):
+        return sys.stderr
+
+
+_defaultLastResort = _StderrHandler(WARNING)
+lastResort = _defaultLastResort
+
 #---------------------------------------------------------------------------
 #   Manager classes and functions
 #---------------------------------------------------------------------------
@@ -1053,10 +1076,10 @@
         """
         self.root = rootnode
         self.disable = 0
-        self.emittedNoHandlerWarning = 0
+        self.emittedNoHandlerWarning = False
         self.loggerDict = {}
         self.loggerClass = None
-        self.logRecordClass = None
+        self.logRecordFactory = None
 
     def getLogger(self, name):
         """
@@ -1100,12 +1123,12 @@
                                 + klass.__name__)
         self.loggerClass = klass
 
-    def setLogRecordClass(self, cls):
+    def setLogRecordFactory(self, factory):
         """
-        Set the class to be used when instantiating a log record with this
+        Set the factory to be used when instantiating a log record with this
         Manager.
         """
-        self.logRecordClass = cls
+        self.logRecordFactory = factory
 
     def _fixupParents(self, alogger):
         """
@@ -1305,7 +1328,7 @@
         A factory method which can be overridden in subclasses to create
         specialized LogRecords.
         """
-        rv = _logRecordClass(name, level, fn, lno, msg, args, exc_info, func,
+        rv = _logRecordFactory(name, level, fn, lno, msg, args, exc_info, func,
                              sinfo)
         if extra is not None:
             for key in extra:
@@ -1412,10 +1435,13 @@
                 c = None    #break out
             else:
                 c = c.parent
-        if (found == 0) and raiseExceptions and not self.manager.emittedNoHandlerWarning:
-            sys.stderr.write("No handlers could be found for logger"
-                             " \"%s\"\n" % self.name)
-            self.manager.emittedNoHandlerWarning = 1
+        if (found == 0):
+            if lastResort:
+                lastResort.handle(record)
+            elif raiseExceptions and not self.manager.emittedNoHandlerWarning:
+                sys.stderr.write("No handlers could be found for logger"
+                                 " \"%s\"\n" % self.name)
+                self.manager.emittedNoHandlerWarning = True
 
     def getEffectiveLevel(self):
         """
@@ -1673,7 +1699,9 @@
 
 def critical(msg, *args, **kwargs):
     """
-    Log a message with severity 'CRITICAL' on the root logger.
+    Log a message with severity 'CRITICAL' on the root logger. If the logger
+    has no handlers, call basicConfig() to add a console handler with a
+    pre-defined format.
     """
     if len(root.handlers) == 0:
         basicConfig()
@@ -1683,7 +1711,9 @@
 
 def error(msg, *args, **kwargs):
     """
-    Log a message with severity 'ERROR' on the root logger.
+    Log a message with severity 'ERROR' on the root logger. If the logger has
+    no handlers, call basicConfig() to add a console handler with a pre-defined
+    format.
     """
     if len(root.handlers) == 0:
         basicConfig()
@@ -1691,15 +1721,18 @@
 
 def exception(msg, *args, **kwargs):
     """
-    Log a message with severity 'ERROR' on the root logger,
-    with exception information.
+    Log a message with severity 'ERROR' on the root logger, with exception
+    information. If the logger has no handlers, basicConfig() is called to add
+    a console handler with a pre-defined format.
     """
     kwargs['exc_info'] = True
     error(msg, *args, **kwargs)
 
 def warning(msg, *args, **kwargs):
     """
-    Log a message with severity 'WARNING' on the root logger.
+    Log a message with severity 'WARNING' on the root logger. If the logger has
+    no handlers, call basicConfig() to add a console handler with a pre-defined
+    format.
     """
     if len(root.handlers) == 0:
         basicConfig()
@@ -1709,7 +1742,9 @@
 
 def info(msg, *args, **kwargs):
     """
-    Log a message with severity 'INFO' on the root logger.
+    Log a message with severity 'INFO' on the root logger. If the logger has
+    no handlers, call basicConfig() to add a console handler with a pre-defined
+    format.
     """
     if len(root.handlers) == 0:
         basicConfig()
@@ -1717,7 +1752,9 @@
 
 def debug(msg, *args, **kwargs):
     """
-    Log a message with severity 'DEBUG' on the root logger.
+    Log a message with severity 'DEBUG' on the root logger. If the logger has
+    no handlers, call basicConfig() to add a console handler with a pre-defined
+    format.
     """
     if len(root.handlers) == 0:
         basicConfig()
@@ -1725,7 +1762,9 @@
 
 def log(level, msg, *args, **kwargs):
     """
-    Log 'msg % args' with the integer severity 'level' on the root logger.
+    Log 'msg % args' with the integer severity 'level' on the root logger. If
+    the logger has no handlers, call basicConfig() to add a console handler
+    with a pre-defined format.
     """
     if len(root.handlers) == 0:
         basicConfig()

Modified: python/branches/py3k-cdecimal/Lib/mimetypes.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/mimetypes.py	(original)
+++ python/branches/py3k-cdecimal/Lib/mimetypes.py	Sun Jan  2 13:18:37 2011
@@ -374,6 +374,7 @@
     global common_types
 
     suffix_map = {
+        '.svgz': '.svg.gz',
         '.tgz': '.tar.gz',
         '.taz': '.tar.gz',
         '.tz': '.tar.gz',
@@ -387,7 +388,7 @@
         }
 
     # Before adding new types, make sure they are either registered with IANA,
-    # at http://www.isi.edu/in-notes/iana/assignments/media-types
+    # at http://www.iana.org/assignments/media-types
     # or extensions, i.e. using the x- prefix
 
     # If you add to these, please keep them sorted!
@@ -488,6 +489,7 @@
         '.src'    : 'application/x-wais-source',
         '.sv4cpio': 'application/x-sv4cpio',
         '.sv4crc' : 'application/x-sv4crc',
+        '.svg'    : 'image/svg+xml',
         '.swf'    : 'application/x-shockwave-flash',
         '.t'      : 'application/x-troff',
         '.tar'    : 'application/x-tar',

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/__init__.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/__init__.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/__init__.py	Sun Jan  2 13:18:37 2011
@@ -38,6 +38,7 @@
 # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 __version__ = '0.70a1'

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/connection.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/connection.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/connection.py	Sun Jan  2 13:18:37 2011
@@ -3,7 +3,33 @@
 #
 # multiprocessing/connection.py
 #
-# Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 __all__ = [ 'Client', 'Listener', 'Pipe' ]

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/dummy/__init__.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/dummy/__init__.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/dummy/__init__.py	Sun Jan  2 13:18:37 2011
@@ -3,7 +3,33 @@
 #
 # multiprocessing/dummy/__init__.py
 #
-# Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 __all__ = [

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/dummy/connection.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/dummy/connection.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/dummy/connection.py	Sun Jan  2 13:18:37 2011
@@ -3,7 +3,33 @@
 #
 # multiprocessing/dummy/connection.py
 #
-# Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 __all__ = [ 'Client', 'Listener', 'Pipe' ]

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/forking.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/forking.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/forking.py	Sun Jan  2 13:18:37 2011
@@ -3,7 +3,33 @@
 #
 # multiprocessing/forking.py
 #
-# Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 import os

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/heap.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/heap.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/heap.py	Sun Jan  2 13:18:37 2011
@@ -3,7 +3,33 @@
 #
 # multiprocessing/heap.py
 #
-# Copyright (c) 2007-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 import bisect

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/managers.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/managers.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/managers.py	Sun Jan  2 13:18:37 2011
@@ -4,7 +4,33 @@
 #
 # multiprocessing/managers.py
 #
-# Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 __all__ = [ 'BaseManager', 'SyncManager', 'BaseProxy', 'Token' ]

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/pool.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/pool.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/pool.py	Sun Jan  2 13:18:37 2011
@@ -3,7 +3,33 @@
 #
 # multiprocessing/pool.py
 #
-# Copyright (c) 2007-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 __all__ = ['Pool']

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/process.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/process.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/process.py	Sun Jan  2 13:18:37 2011
@@ -3,7 +3,33 @@
 #
 # multiprocessing/process.py
 #
-# Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 __all__ = ['Process', 'current_process', 'active_children']

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/queues.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/queues.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/queues.py	Sun Jan  2 13:18:37 2011
@@ -3,7 +3,33 @@
 #
 # multiprocessing/queues.py
 #
-# Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 __all__ = ['Queue', 'SimpleQueue', 'JoinableQueue']

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/reduction.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/reduction.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/reduction.py	Sun Jan  2 13:18:37 2011
@@ -4,7 +4,33 @@
 #
 # multiprocessing/reduction.py
 #
-# Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 __all__ = []

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/sharedctypes.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/sharedctypes.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/sharedctypes.py	Sun Jan  2 13:18:37 2011
@@ -3,7 +3,33 @@
 #
 # multiprocessing/sharedctypes.py
 #
-# Copyright (c) 2007-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 import sys

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/synchronize.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/synchronize.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/synchronize.py	Sun Jan  2 13:18:37 2011
@@ -3,7 +3,33 @@
 #
 # multiprocessing/synchronize.py
 #
-# Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 __all__ = [

Modified: python/branches/py3k-cdecimal/Lib/multiprocessing/util.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/multiprocessing/util.py	(original)
+++ python/branches/py3k-cdecimal/Lib/multiprocessing/util.py	Sun Jan  2 13:18:37 2011
@@ -3,7 +3,33 @@
 #
 # multiprocessing/util.py
 #
-# Copyright (c) 2006-2008, R Oudkerk --- see COPYING.txt
+# Copyright (c) 2006-2008, R Oudkerk
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of author nor the names of any contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
 #
 
 import itertools

Modified: python/branches/py3k-cdecimal/Lib/netrc.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/netrc.py	(original)
+++ python/branches/py3k-cdecimal/Lib/netrc.py	Sun Jan  2 13:18:37 2011
@@ -34,11 +34,15 @@
     def _parse(self, file, fp):
         lexer = shlex.shlex(fp)
         lexer.wordchars += r"""!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"""
+        lexer.commenters = lexer.commenters.replace('#', '')
         while 1:
             # Look for a machine, default, or macdef top-level keyword
             toplevel = tt = lexer.get_token()
             if not tt:
                 break
+            elif tt[0] == '#':
+                fp.readline();
+                continue;
             elif tt == 'machine':
                 entryname = lexer.get_token()
             elif tt == 'default':

Modified: python/branches/py3k-cdecimal/Lib/numbers.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/numbers.py	(original)
+++ python/branches/py3k-cdecimal/Lib/numbers.py	Sun Jan  2 13:18:37 2011
@@ -60,7 +60,7 @@
 
     @abstractproperty
     def imag(self):
-        """Retrieve the real component of this number.
+        """Retrieve the imaginary component of this number.
 
         This should subclass Real.
         """
@@ -303,7 +303,7 @@
         raise NotImplementedError
 
     def __index__(self):
-        """index(self)"""
+        """someobject[self]"""
         return int(self)
 
     @abstractmethod

Modified: python/branches/py3k-cdecimal/Lib/os.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/os.py	(original)
+++ python/branches/py3k-cdecimal/Lib/os.py	Sun Jan  2 13:18:37 2011
@@ -114,18 +114,26 @@
 SEEK_CUR = 1
 SEEK_END = 2
 
+
+def _get_masked_mode(mode):
+    mask = umask(0)
+    umask(mask)
+    return mode & ~mask
+
 #'
 
 # Super directory utilities.
 # (Inspired by Eric Raymond; the doc strings are mostly his)
 
-def makedirs(name, mode=0o777):
-    """makedirs(path [, mode=0o777])
+def makedirs(name, mode=0o777, exist_ok=False):
+    """makedirs(path [, mode=0o777][, exist_ok=False])
 
     Super-mkdir; create a leaf directory and all intermediate ones.
     Works like mkdir, except that any intermediate path segment (not
-    just the rightmost) will be created if it does not exist.  This is
-    recursive.
+    just the rightmost) will be created if it does not exist. If the
+    target directory with the same mode as we specified already exists,
+    raises an OSError if exist_ok is False, otherwise no exception is
+    raised.  This is recursive.
 
     """
     head, tail = path.split(name)
@@ -133,14 +141,20 @@
         head, tail = path.split(head)
     if head and tail and not path.exists(head):
         try:
-            makedirs(head, mode)
+            makedirs(head, mode, exist_ok)
         except OSError as e:
             # be happy if someone already created the path
             if e.errno != errno.EEXIST:
                 raise
         if tail == curdir:           # xxx/newdir/. exists if xxx/newdir exists
             return
-    mkdir(name, mode)
+    try:
+        mkdir(name, mode)
+    except OSError as e:
+        import stat as st
+        if not (e.errno == errno.EEXIST and exist_ok and path.isdir(name) and
+                st.S_IMODE(lstat(name).st_mode) == _get_masked_mode(mode)):
+            raise
 
 def removedirs(name):
     """removedirs(path)

Modified: python/branches/py3k-cdecimal/Lib/pdb.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/pdb.py	(original)
+++ python/branches/py3k-cdecimal/Lib/pdb.py	Sun Jan  2 13:18:37 2011
@@ -66,16 +66,18 @@
 # NOTE: the actual command documentation is collected from docstrings of the
 # commands and is appended to __doc__ after the class has been defined.
 
+import os
+import re
 import sys
-import linecache
 import cmd
 import bdb
 import dis
-import os
-import re
+import code
 import pprint
-import traceback
+import signal
 import inspect
+import traceback
+import linecache
 
 
 class Restart(Exception):
@@ -94,14 +96,14 @@
     # consumer of this info expects the first line to be 1
     lineno = 1
     answer = None
-    while 1:
+    while True:
         line = fp.readline()
         if line == '':
             break
         if cre.match(line):
             answer = funcname, filename, lineno
             break
-        lineno = lineno + 1
+        lineno += 1
     fp.close()
     return answer
 
@@ -123,6 +125,12 @@
     return 0
 
 
+class _rstr(str):
+    """String that doesn't quote its repr."""
+    def __repr__(self):
+        return self
+
+
 # Interaction prompt line will separate file and call info from code
 # text using value of line_prefix string.  A newline and arrow may
 # be to your liking.  You can set it once pdb is imported using the
@@ -132,21 +140,25 @@
 
 class Pdb(bdb.Bdb, cmd.Cmd):
 
-    def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None):
+    def __init__(self, completekey='tab', stdin=None, stdout=None, skip=None,
+                 nosigint=False):
         bdb.Bdb.__init__(self, skip=skip)
         cmd.Cmd.__init__(self, completekey, stdin, stdout)
         if stdout:
             self.use_rawinput = 0
         self.prompt = '(Pdb) '
         self.aliases = {}
+        self.displaying = {}
         self.mainpyfile = ''
-        self._wait_for_mainpyfile = 0
+        self._wait_for_mainpyfile = False
         self.tb_lineno = {}
         # Try to load readline if it exists
         try:
             import readline
         except ImportError:
             pass
+        self.allow_kbdint = False
+        self.nosigint = nosigint
 
         # Read $HOME/.pdbrc and ./.pdbrc
         self.rcLines = []
@@ -173,6 +185,15 @@
         self.commands_bnum = None # The breakpoint number for which we are
                                   # defining a list
 
+    def sigint_handler(self, signum, frame):
+        if self.allow_kbdint:
+            raise KeyboardInterrupt
+        self.message("\nProgram interrupted. (Use 'cont' to resume).")
+        self.set_step()
+        self.set_trace(frame)
+        # restore previous signal handler
+        signal.signal(signal.SIGINT, self._previous_sigint_handler)
+
     def reset(self):
         bdb.Bdb.reset(self)
         self.forget()
@@ -235,9 +256,9 @@
         """This function is called when we stop or break at this line."""
         if self._wait_for_mainpyfile:
             if (self.mainpyfile != self.canonic(frame.f_code.co_filename)
-                or frame.f_lineno<= 0):
+                or frame.f_lineno <= 0):
                 return
-            self._wait_for_mainpyfile = 0
+            self._wait_for_mainpyfile = False
         if self.bp_commands(frame):
             self.interaction(frame, None)
 
@@ -260,7 +281,7 @@
             if not self.commands_silent[currentbp]:
                 self.print_stack_entry(self.stack[self.curindex])
             if self.commands_doprompt[currentbp]:
-                self.cmdloop()
+                self._cmdloop()
             self.forget()
             return
         return 1
@@ -285,6 +306,31 @@
         self.interaction(frame, exc_traceback)
 
     # General interaction function
+    def _cmdloop(self):
+        while True:
+            try:
+                # keyboard interrupts allow for an easy way to cancel
+                # the current command, so allow them during interactive input
+                self.allow_kbdint = True
+                self.cmdloop()
+                self.allow_kbdint = False
+                break
+            except KeyboardInterrupt:
+                self.message('--KeyboardInterrupt--')
+
+    # Called before loop, handles display expressions
+    def preloop(self):
+        displaying = self.displaying.get(self.curframe)
+        if displaying:
+            for expr, oldvalue in displaying.items():
+                newvalue = self._getval_except(expr)
+                # check for identity first; this prevents custom __eq__ to
+                # be called at every loop, and also prevents instances whose
+                # fields are changed to be displayed
+                if newvalue is not oldvalue and newvalue != oldvalue:
+                    displaying[expr] = newvalue
+                    self.message('display %s: %r  [old: %r]' %
+                                 (expr, newvalue, oldvalue))
 
     def interaction(self, frame, traceback):
         if self.setup(frame, traceback):
@@ -293,7 +339,7 @@
             self.forget()
             return
         self.print_stack_entry(self.stack[self.curindex])
-        self.cmdloop()
+        self._cmdloop()
         self.forget()
 
     def displayhook(self, obj):
@@ -337,7 +383,7 @@
             for tmpArg in args[1:]:
                 line = line.replace("%" + str(ii),
                                       tmpArg)
-                ii = ii + 1
+                ii += 1
             line = line.replace("%*", ' '.join(args[1:]))
             args = line.split()
         # split into ';;' separated commands
@@ -774,7 +820,7 @@
             except ValueError as err:
                 self.error(err)
             else:
-                self.clear_break(bp.file, bp.line)
+                self.clear_bpbynumber(i)
                 self.message('Deleted %s' % bp)
     do_cl = do_clear # 'c' is already an abbreviation for 'continue'
 
@@ -908,6 +954,9 @@
         """c(ont(inue))
         Continue execution, only stop when a breakpoint is encountered.
         """
+        if not self.nosigint:
+            self._previous_sigint_handler = \
+                signal.signal(signal.SIGINT, self.sigint_handler)
         self.set_continue()
         return 1
     do_c = do_cont = do_continue
@@ -962,7 +1011,7 @@
         """q(uit)\nexit
         Quit from the debugger. The program being executed is aborted.
         """
-        self._user_requested_quit = 1
+        self._user_requested_quit = True
         self.set_quit()
         return 1
 
@@ -974,7 +1023,7 @@
         Handles the receipt of EOF as a command.
         """
         self.message('')
-        self._user_requested_quit = 1
+        self._user_requested_quit = True
         self.set_quit()
         return 1
 
@@ -1013,6 +1062,17 @@
             self.error(traceback.format_exception_only(*exc_info)[-1].strip())
             raise
 
+    def _getval_except(self, arg, frame=None):
+        try:
+            if frame is None:
+                return eval(arg, self.curframe.f_globals, self.curframe_locals)
+            else:
+                return eval(arg, frame.f_globals, frame.f_locals)
+        except:
+            exc_info = sys.exc_info()[:2]
+            err = traceback.format_exception_only(*exc_info)[-1].strip()
+            return _rstr('** raised %s **' % err)
+
     def do_p(self, arg):
         """p(rint) expression
         Print the value of the expression.
@@ -1167,6 +1227,48 @@
         # None of the above...
         self.message(type(value))
 
+    def do_display(self, arg):
+        """display [expression]
+
+        Display the value of the expression if it changed, each time execution
+        stops in the current frame.
+
+        Without expression, list all display expressions for the current frame.
+        """
+        if not arg:
+            self.message('Currently displaying:')
+            for item in self.displaying.get(self.curframe, {}).items():
+                self.message('%s: %r' % item)
+        else:
+            val = self._getval_except(arg)
+            self.displaying.setdefault(self.curframe, {})[arg] = val
+            self.message('display %s: %r' % (arg, val))
+
+    def do_undisplay(self, arg):
+        """undisplay [expression]
+
+        Do not display the expression any more in the current frame.
+
+        Without expression, clear all display expressions for the current frame.
+        """
+        if arg:
+            try:
+                del self.displaying.get(self.curframe, {})[arg]
+            except KeyError:
+                self.error('not displaying %s' % arg)
+        else:
+            self.displaying.pop(self.curframe, None)
+
+    def do_interact(self, arg):
+        """interact
+
+        Start an interative interpreter whose global namespace
+        contains all the (global and local) names found in the current scope.
+        """
+        ns = self.curframe.f_globals.copy()
+        ns.update(self.curframe_locals)
+        code.interact("*interactive*", local=ns)
+
     def do_alias(self, arg):
         """alias [name [command [parameter parameter ...] ]]
         Create an alias called 'name' that executes 'command'.  The
@@ -1326,9 +1428,9 @@
         # events depends on python version). So we take special measures to
         # avoid stopping before we reach the main script (see user_line and
         # user_call for details).
-        self._wait_for_mainpyfile = 1
+        self._wait_for_mainpyfile = True
         self.mainpyfile = self.canonic(filename)
-        self._user_requested_quit = 0
+        self._user_requested_quit = False
         with open(filename, "rb") as fp:
             statement = "exec(compile(%r, %r, 'exec'))" % \
                         (fp.read(), self.mainpyfile)
@@ -1342,8 +1444,8 @@
         'help', 'where', 'down', 'up', 'break', 'tbreak', 'clear', 'disable',
         'enable', 'ignore', 'condition', 'commands', 'step', 'next', 'until',
         'jump', 'return', 'retval', 'run', 'continue', 'list', 'longlist',
-        'args', 'print', 'pp', 'whatis', 'source', 'alias', 'unalias',
-        'debug', 'quit',
+        'args', 'print', 'pp', 'whatis', 'source', 'display', 'undisplay',
+        'interact', 'alias', 'unalias', 'debug', 'quit',
     ]
 
     for _command in _help_order:

Modified: python/branches/py3k-cdecimal/Lib/py_compile.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/py_compile.py	(original)
+++ python/branches/py3k-cdecimal/Lib/py_compile.py	Sun Jan  2 13:18:37 2011
@@ -72,7 +72,7 @@
                    (x >> 16) & 0xff,
                    (x >> 24) & 0xff]))
 
-def compile(file, cfile=None, dfile=None, doraise=False):
+def compile(file, cfile=None, dfile=None, doraise=False, optimize=-1):
     """Byte-compile one Python source file to Python bytecode.
 
     :param file: The source file name.
@@ -86,6 +86,10 @@
         will be printed, and the function will return to the caller. If an
         exception occurs and this flag is set to True, a PyCompileError
         exception will be raised.
+    :param optimize: The optimization level for the compiler.  Valid values
+        are -1, 0, 1 and 2.  A value of -1 means to use the optimization
+        level of the current interpreter, as given by -O command line options.
+
     :return: Path to the resulting byte compiled file.
 
     Note that it isn't necessary to byte-compile Python modules for
@@ -111,7 +115,8 @@
             timestamp = int(os.stat(file).st_mtime)
         codestring = f.read()
     try:
-        codeobject = builtins.compile(codestring, dfile or file,'exec')
+        codeobject = builtins.compile(codestring, dfile or file, 'exec',
+                                      optimize=optimize)
     except Exception as err:
         py_exc = PyCompileError(err.__class__, err, dfile or file)
         if doraise:
@@ -120,7 +125,10 @@
             sys.stderr.write(py_exc.msg + '\n')
             return
     if cfile is None:
-        cfile = imp.cache_from_source(file)
+        if optimize >= 0:
+            cfile = imp.cache_from_source(file, debug_override=not optimize)
+        else:
+            cfile = imp.cache_from_source(file)
     try:
         os.makedirs(os.path.dirname(cfile))
     except OSError as error:

Modified: python/branches/py3k-cdecimal/Lib/pydoc.py
==============================================================================
--- python/branches/py3k-cdecimal/Lib/pydoc.py	(original)
+++ python/branches/py3k-cdecimal/Lib/pydoc.py	Sun Jan  2 13:18:37 2011
@@ -15,11 +15,17 @@
 Run "pydoc -k " to search for a keyword in the synopsis lines
 of all available modules.
 
-Run "pydoc -p " to start an HTTP server on a given port on the
-local machine to generate documentation web pages.
+Run "pydoc -p " to start an HTTP server on the given port on the
+local machine.  Port number 0 can be used to get an arbitrary unused port.
+
+Run "pydoc -b" to start an HTTP server on an arbitrary unused port and
+open a Web browser to interactively browse documentation.  The -p option
+can be used with the -b option to explicitly specify the server port.
 
 For platforms without a command line, "pydoc -g" starts the HTTP server
-and also pops up a little window for controlling it.
+and also pops up a little window for controlling it.  This option is
+deprecated, since the server can now be controlled directly from HTTP
+clients.
 
 Run "pydoc -w " to write out the HTML documentation for a module
 to a file named ".html".
@@ -51,10 +57,22 @@
 #     the current directory is changed with os.chdir(), an incorrect
 #     path will be displayed.
 
-import sys, imp, os, re, inspect, builtins, pkgutil
-from reprlib import Repr
-from traceback import extract_tb as _extract_tb
+import os
+import sys
+import builtins
+import imp
+import io
+import inspect
+import pkgutil
+import platform
+import re
+import time
+import warnings
 from collections import deque
+from reprlib import Repr
+from traceback import extract_tb
+
+
 # --------------------------------------------------------- common routines
 
 def pathdirs():
@@ -285,7 +303,7 @@
         elif exc is SyntaxError:
             # A SyntaxError occurred before we could execute the module.
             raise ErrorDuringImport(value.filename, info)
-        elif exc is ImportError and _extract_tb(tb)[-1][2]=='safeimport':
+        elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport':
             # The import error occurred directly in this function,
             # which means there is no such module in the path.
             return None
@@ -513,6 +531,10 @@
             text = name
         return '%s' % (url, text)
 
+    def filelink(self, url, path):
+        """Make a link to source file."""
+        return '%s' % (url, path)
+
     def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
         """Mark up some plain text, given a context of symbols to look for.
         Each context dictionary maps object names to anchor names."""
@@ -591,7 +613,7 @@
             if sys.platform == 'win32':
                 import nturl2path
                 url = nturl2path.pathname2url(path)
-            filelink = '%s' % (url, path)
+            filelink = self.filelink(url, path)
         except TypeError:
             filelink = '(built-in)'
         info = []
@@ -978,7 +1000,7 @@
 
     def bold(self, text):
         """Format a string in bold by overstriking."""
-        return ''.join(map(lambda ch: ch + '\b' + ch, text))
+        return ''.join(ch + '\b' + ch for ch in text)
 
     def indent(self, text, prefix='    '):
         """Indent text by prepending a given prefix to each line."""
@@ -1002,7 +1024,7 @@
                 c, bases = entry
                 result = result + prefix + classname(c, modname)
                 if bases and bases != (parent,):
-                    parents = map(lambda c, m=modname: classname(c, m), bases)
+                    parents = (classname(c, modname) for c in bases)
                     result = result + '(%s)' % ', '.join(parents)
                 result = result + '\n'
             elif type(entry) is type([]):
@@ -1110,7 +1132,7 @@
         result = result + self.section('FILE', file)
         return result
 
-    def docclass(self, object, name=None, mod=None):
+    def docclass(self, object, name=None, mod=None, *ignored):
         """Produce text documentation for a given class object."""
         realname = object.__name__
         name = name or realname
@@ -1310,6 +1332,11 @@
             line += '\n' + self.indent(str(doc))
         return line
 
+class _PlainTextDoc(TextDoc):
+    """Subclass of TextDoc which overrides string styling"""
+    def bold(self, text):
+        return text
+
 # --------------------------------------------------------- user interfaces
 
 def pager(text):
@@ -1464,6 +1491,7 @@
 # --------------------------------------- interactive interpreter interface
 
 text = TextDoc()
+plaintext = _PlainTextDoc()
 html = HTMLDoc()
 
 def resolve(thing, forceload=0):
@@ -1476,8 +1504,11 @@
     else:
         return thing, getattr(thing, '__name__', None)
 
-def render_doc(thing, title='Python Library Documentation: %s', forceload=0):
+def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
+        renderer=None):
     """Render text documentation, given an object or a path to an object."""
+    if renderer is None:
+        renderer = text
     object, name = resolve(thing, forceload)
     desc = describe(object)
     module = inspect.getmodule(object)
@@ -1496,12 +1527,16 @@
         # document its available methods instead of its value.
         object = type(object)
         desc += ' object'
-    return title % desc + '\n\n' + text.document(object, name)
+    return title % desc + '\n\n' + renderer.document(object, name)
 
-def doc(thing, title='Python Library Documentation: %s', forceload=0):
+def doc(thing, title='Python Library Documentation: %s', forceload=0,
+        output=None):
     """Display text documentation, given an object or a path to an object."""
     try:
-        pager(render_doc(thing, title, forceload))
+        if output is None:
+            pager(render_doc(thing, title, forceload))
+        else:
+            output.write(render_doc(thing, title, forceload, plaintext))
     except (ImportError, ErrorDuringImport) as value:
         print(value)
 
@@ -1755,9 +1790,9 @@
             elif request in self.symbols: self.showsymbol(request)
             elif request in self.keywords: self.showtopic(request)
             elif request in self.topics: self.showtopic(request)
-            elif request: doc(request, 'Help on %s:')
+            elif request: doc(request, 'Help on %s:', output=self._output)
         elif isinstance(request, Helper): self()
-        else: doc(request, 'Help on %s:')
+        else: doc(request, 'Help on %s:', output=self._output)
         self.output.write('\n')
 
     def intro(self):
@@ -1838,12 +1873,40 @@
         if more_xrefs:
             xrefs = (xrefs or '') + ' ' + more_xrefs
         if xrefs:
-            import io, formatter
+            import formatter
             buffer = io.StringIO()
             formatter.DumbWriter(buffer).send_flowing_data(
                 'Related help topics: ' + ', '.join(xrefs.split()) + '\n')
             self.output.write('\n%s\n' % buffer.getvalue())
 
+    def _gettopic(self, topic, more_xrefs=''):
+        """Return unbuffered tuple of (topic, xrefs).
+
+        If an error occurs, topic is the error message, and xrefs is ''.
+        This function duplicates the showtopic method but returns its
+        result directly so it can be formatted for display in an html page.
+        """
+        try:
+            import pydoc_data.topics
+        except ImportError:
+            return('''
+Sorry, topic and keyword documentation is not available because the
+module "pydoc_data.topics" could not be found.
+''' , '')
+        target = self.topics.get(topic, self.keywords.get(topic))
+        if not target:
+            return 'no documentation found for %r' % topic, ''
+        if isinstance(target, str):
+            return self._gettopic(target, more_xrefs)
+        label, xrefs = target
+        try:
+            doc = pydoc_data.topics.topics[label]
+        except KeyError:
+            return 'no documentation found for %r' % topic, ''
+        if more_xrefs:
+            xrefs = (xrefs or '') + ' ' + more_xrefs
+        return doc, xrefs
+
     def showsymbol(self, symbol):
         target = self.symbols[symbol]
         topic, _, xrefs = target.partition(' ')
@@ -1925,6 +1988,15 @@
         for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
             if self.quit:
                 break
+
+            # XXX Skipping this file is a workaround for a bug
+            # that causes python to crash with a segfault.
+            # http://bugs.python.org/issue9319
+            #
+            # TODO Remove this once the bug is fixed.
+            if modname in {'test.badsyntax_pep3120', 'badsyntax_pep3120'}:
+                continue
+
             if key is None:
                 callback(None, modname, '')
             else:
@@ -1940,7 +2012,6 @@
                         if onerror:
                             onerror(modname)
                         continue
-                    import io
                     desc = source_synopsis(io.StringIO(source)) or ''
                     if hasattr(loader, 'get_filename'):
                         path = loader.get_filename(modname)
@@ -1970,16 +2041,18 @@
         print(modname, desc and '- ' + desc)
     def onerror(modname):
         pass
-    try: import warnings
-    except ImportError: pass
-    else: warnings.filterwarnings('ignore') # ignore problems during import
-    ModuleScanner().run(callback, key, onerror=onerror)
+    with warnings.catch_warnings():
+        warnings.filterwarnings('ignore') # ignore problems during import
+        ModuleScanner().run(callback, key, onerror=onerror)
 
-# --------------------------------------------------- web browser interface
+# --------------------------------------------------- Web browser interface
 
 def serve(port, callback=None, completer=None):
     import http.server, email.message, select
 
+    msg = 'the pydoc.serve() function is deprecated'
+    warnings.warn(msg, DeprecationWarning, stacklevel=2)
+
     class DocHandler(http.server.BaseHTTPRequestHandler):
         def send_document(self, title, contents):
             try:
@@ -2058,7 +2131,12 @@
 # ----------------------------------------------------- graphical interface
 
 def gui():
-    """Graphical interface (starts web server and pops up a control window)."""
+    """Graphical interface (starts Web server and pops up a control window)."""
+
+    msg = ('the pydoc.gui() function and "pydoc -g" option are deprecated\n',
+           'use "pydoc.browse() function and "pydoc -b" option instead.')
+    warnings.warn(msg, DeprecationWarning, stacklevel=2)
+
     class GUI:
         def __init__(self, window, port=7464):
             self.window = window
@@ -2138,15 +2216,8 @@
 
         def open(self, event=None, url=None):
             url = url or self.server.url
-            try:
-                import webbrowser
-                webbrowser.open(url)
-            except ImportError: # pre-webbrowser.py compatibility
-                if sys.platform == 'win32':
-                    os.system('start "%s"' % url)
-                else:
-                    rc = os.system('netscape -remote "openURL(%s)" &' % url)
-                    if rc: os.system('netscape "%s" &' % url)
+            import webbrowser
+            webbrowser.open(url)
 
         def quit(self, event=None):
             if self.server:
@@ -2238,6 +2309,433 @@
     except KeyboardInterrupt:
         pass
 
+
+# --------------------------------------- enhanced Web browser interface
+
+def _start_server(urlhandler, port):
+    """Start an HTTP server thread on a specific port.
+
+    Start an HTML/text server thread, so HTML or text documents can be
+    browsed dynamically and interactively with a Web browser.  Example use:
+
+        >>> import time
+        >>> import pydoc
+
+        Define a URL handler.  To determine what the client is asking
+        for, check the URL and content_type.
+
+        Then get or generate some text or HTML code and return it.
+
+        >>> def my_url_handler(url, content_type):
+        ...     text = 'the URL sent was: (%s, %s)' % (url, content_type)
+        ...     return text
+
+        Start server thread on port 0.
+        If you use port 0, the server will pick a random port number.
+        You can then use serverthread.port to get the port number.
+
+        >>> port = 0
+        >>> serverthread = pydoc._start_server(my_url_handler, port)
+
+        Check that the server is really started.  If it is, open browser
+        and get first page.  Use serverthread.url as the starting page.
+
+        >>> if serverthread.serving:
+        ...    import webbrowser
+
+        The next two lines are commented out so a browser doesn't open if
+        doctest is run on this module.
+
+        #...    webbrowser.open(serverthread.url)
+        #True
+
+        Let the server do its thing. We just need to monitor its status.
+        Use time.sleep so the loop doesn't hog the CPU.
+
+        >>> starttime = time.time()
+        >>> timeout = 1                    #seconds
+
+        This is a short timeout for testing purposes.
+
+        >>> while serverthread.serving:
+        ...     time.sleep(.01)
+        ...     if serverthread.serving and time.time() - starttime > timeout:
+        ...          serverthread.stop()
+        ...          break
+
+        Print any errors that may have occurred.
+
+        >>> print(serverthread.error)
+        None
+   """
+    import http.server
+    import email.message
+    import select
+    import threading
+
+    class DocHandler(http.server.BaseHTTPRequestHandler):
+
+        def do_GET(self):
+            """Process a request from an HTML browser.
+
+            The URL received is in self.path.
+            Get an HTML page from self.urlhandler and send it.
+            """
+            if self.path.endswith('.css'):
+                content_type = 'text/css'
+            else:
+                content_type = 'text/html'
+            self.send_response(200)
+            self.send_header('Content-Type', '%s;charset=UTF-8' % content_type)
+            self.end_headers()
+            self.wfile.write(self.urlhandler(
+                self.path, content_type).encode('utf-8'))
+
+        def log_message(self, *args):
+            # Don't log messages.
+            pass
+
+    class DocServer(http.server.HTTPServer):
+
+        def __init__(self, port, callback):
+            self.host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
+            self.address = ('', port)
+            self.callback = callback
+            self.base.__init__(self, self.address, self.handler)
+            self.quit = False
+
+        def serve_until_quit(self):
+            while not self.quit:
+                rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
+                if rd:
+                    self.handle_request()
+
+        def server_activate(self):
+            self.base.server_activate(self)
+            if self.callback:
+                self.callback(self)
+
+    class ServerThread(threading.Thread):
+
+        def __init__(self, urlhandler, port):
+            self.urlhandler = urlhandler
+            self.port = int(port)
+            threading.Thread.__init__(self)
+            self.serving = False
+            self.error = None
+
+        def run(self):
+            """Start the server."""
+            try:
+                DocServer.base = http.server.HTTPServer
+                DocServer.handler = DocHandler
+                DocHandler.MessageClass = email.message.Message
+                DocHandler.urlhandler = staticmethod(self.urlhandler)
+                docsvr = DocServer(self.port, self.ready)
+                self.docserver = docsvr
+                docsvr.serve_until_quit()
+            except Exception as e:
+                self.error = e
+
+        def ready(self, server):
+            self.serving = True
+            self.host = server.host
+            self.port = server.server_port
+            self.url = 'http://%s:%d/' % (self.host, self.port)
+
+        def stop(self):
+            """Stop the server and this thread nicely"""
+            self.docserver.quit = True
+            self.serving = False
+            self.url = None
+
+    thread = ServerThread(urlhandler, port)
+    thread.start()
+    # Wait until thread.serving is True to make sure we are
+    # really up before returning.
+    while not thread.error and not thread.serving:
+        time.sleep(.01)
+    return thread
+
+
+def _url_handler(url, content_type="text/html"):
+    """The pydoc url handler for use with the pydoc server.
+
+    If the content_type is 'text/css', the _pydoc.css style
+    sheet is read and returned if it exits.
+
+    If the content_type is 'text/html', then the result of
+    get_html_page(url) is returned.
+    """
+    class _HTMLDoc(HTMLDoc):
+
+        def page(self, title, contents):
+            """Format an HTML page."""
+            css_path = "pydoc_data/_pydoc.css"
+            css_link = (
+                '' %
+                css_path)
+            return '''\
+
+Python: %s
+
+%s%s
+''' % (title, css_link, contents)
+
+        def filelink(self, url, path):
+            return '%s' % (url, path)
+
+
+    html = _HTMLDoc()
+
+    def html_navbar():
+        version = "%s [%s, %s]" % (platform.python_version(),
+                                   platform.python_build()[0],
+                                   platform.python_compiler())
+        return """
+            
+ Python %s
%s

+
+
+ +
+
+ + +     +
+
+ + +
+
+
+
 
+ """ % (version, platform.platform(terse=True)) + + def html_index(): + """Module Index page.""" + + def bltinlink(name): + return '%s' % (name, name) + + heading = html.heading( + 'Index of Modules', + '#ffffff', '#7799ee') + names = [name for name in sys.builtin_module_names + if name != '__main__'] + contents = html.multicolumn(names, bltinlink) + contents = [heading, '

' + html.bigsection( + 'Built-in Modules', '#ffffff', '#ee77aa', contents)] + + seen = {} + for dir in sys.path: + contents.append(html.index(dir, seen)) + + contents.append( + '

pydoc by Ka-Ping Yee' + '<ping at lfw.org>') + return 'Index of Modules', ''.join(contents) + + def html_search(key): + """Search results page.""" + # scan for modules + search_result = [] + + def callback(path, modname, desc): + if modname[-9:] == '.__init__': + modname = modname[:-9] + ' (package)' + search_result.append((modname, desc and '- ' + desc)) + + with warnings.catch_warnings(): + warnings.filterwarnings('ignore') # ignore problems during import + ModuleScanner().run(callback, key) + + # format page + def bltinlink(name): + return '%s' % (name, name) + + results = [] + heading = html.heading( + 'Search Results', + '#ffffff', '#7799ee') + for name, desc in search_result: + results.append(bltinlink(name) + desc) + contents = heading + html.bigsection( + 'key = %s' % key, '#ffffff', '#ee77aa', '
'.join(results)) + return 'Search Results', contents + + def html_getfile(path): + """Get and display a source file listing safely.""" + path = path.replace('%20', ' ') + with open(path, 'r') as fp: + lines = html.escape(fp.read()) + body = '

%s
' % lines + heading = html.heading( + 'File Listing', + '#ffffff', '#7799ee') + contents = heading + html.bigsection( + 'File: %s' % path, '#ffffff', '#ee77aa', body) + return 'getfile %s' % path, contents + + def html_topics(): + """Index of topic texts available.""" + + def bltinlink(name): + return '%s' % (name, name) + + heading = html.heading( + 'INDEX', + '#ffffff', '#7799ee') + names = sorted(Helper.topics.keys()) + + contents = html.multicolumn(names, bltinlink) + contents = heading + html.bigsection( + 'Topics', '#ffffff', '#ee77aa', contents) + return 'Topics', contents + + def html_keywords(): + """Index of keywords.""" + heading = html.heading( + 'INDEX', + '#ffffff', '#7799ee') + names = sorted(Helper.keywords.keys()) + + def bltinlink(name): + return '%s' % (name, name) + + contents = html.multicolumn(names, bltinlink) + contents = heading + html.bigsection( + 'Keywords', '#ffffff', '#ee77aa', contents) + return 'Keywords', contents + + def html_topicpage(topic): + """Topic or keyword help page.""" + buf = io.StringIO() + htmlhelp = Helper(buf, buf) + contents, xrefs = htmlhelp._gettopic(topic) + if topic in htmlhelp.keywords: + title = 'KEYWORD' + else: + title = 'TOPIC' + heading = html.heading( + '%s' % title, + '#ffffff', '#7799ee') + contents = '
%s
' % contents + contents = html.bigsection(topic , '#ffffff','#ee77aa', contents) + xrefs = sorted(xrefs.split()) + + def bltinlink(name): + return '%s' % (name, name) + + xrefs = html.multicolumn(xrefs, bltinlink) + xrefs = html.section('Related help topics: ', + '#ffffff', '#ee77aa', xrefs) + return ('%s %s' % (title, topic), + ''.join((heading, contents, xrefs))) + + def html_error(url): + heading = html.heading( + 'Error', + '#ffffff', '#ee0000') + return heading + url + + def get_html_page(url): + """Generate an HTML page for url.""" + if url.endswith('.html'): + url = url[:-5] + if url.startswith('/'): + url = url[1:] + if url.startswith("get?key="): + url = url[8:] + title = url + contents = '' + if url in ("", ".", "index"): + title, contents = html_index() + elif url == "topics": + title, contents = html_topics() + elif url == "keywords": + title, contents = html_keywords() + elif url.startswith("search?key="): + title, contents = html_search(url[11:]) + elif url.startswith("getfile?key="): + url = url[12:] + try: + title, contents = html_getfile(url) + except IOError: + contents = html_error('could not read file %r' % url) + title = 'Read Error' + else: + obj = None + try: + obj = locate(url, forceload=1) + except ErrorDuringImport as value: + contents = html.escape(str(value)) + if obj: + title = describe(obj) + contents = html.document(obj, url) + elif url in Helper.keywords or url in Helper.topics: + title, contents = html_topicpage(url) + else: + contents = html_error( + 'no Python documentation found for %r' % url) + title = 'Error' + return html.page(title, html_navbar() + contents) + + if url.startswith('/'): + url = url[1:] + if content_type == 'text/css': + path_here = os.path.dirname(os.path.realpath(__file__)) + try: + with open(os.path.join(path_here, url)) as fp: + return ''.join(fp.readlines()) + except IOError: + return 'Error: can not open css file %r' % url + elif content_type == 'text/html': + return get_html_page(url) + return 'Error: unknown content type %r' % content_type + + +def browse(port=0, *, open_browser=True): + """Start the enhanced pydoc Web server and open a Web browser. + + Use port '0' to start the server on an arbitrary port. + Set open_browser to False to suppress opening a browser. + """ + import webbrowser + serverthread = _start_server(_url_handler, port) + if serverthread.error: + print(serverthread.error) + return + if serverthread.serving: + server_help_msg = 'Server commands: [b]rowser, [q]uit' + if open_browser: + webbrowser.open(serverthread.url) + try: + print('Server ready at', serverthread.url) + print(server_help_msg) + while serverthread.serving: + cmd = input('server> ') + cmd = cmd.lower() + if cmd == 'q': + break + elif cmd == 'b': + webbrowser.open(serverthread.url) + else: + print(server_help_msg) + except (KeyboardInterrupt, EOFError): + print() + finally: + if serverthread.serving: + serverthread.stop() + print('Server stopped') + + # -------------------------------------------------- command-line interface def ispath(x): @@ -2257,29 +2755,32 @@ sys.path.insert(0, '.') try: - opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w') - writing = 0 - + opts, args = getopt.getopt(sys.argv[1:], 'bgk:p:w') + writing = False + start_server = False + open_browser = False + port = None for opt, val in opts: if opt == '-g': gui() return + if opt == '-b': + start_server = True + open_browser = True if opt == '-k': apropos(val) return if opt == '-p': - try: - port = int(val) - except ValueError: - raise BadUsage - def ready(server): - print('pydoc server ready at %s' % server.url) - def stopped(): - print('pydoc server stopped') - serve(port, ready, stopped) - return + start_server = True + port = val if opt == '-w': - writing = 1 + writing = True + + if start_server == True: + if port == None: + port = 0 + browse(port, open_browser=open_browser) + return if not args: raise BadUsage for arg in args: @@ -2300,30 +2801,37 @@ print(value) except (getopt.error, BadUsage): - cmd = os.path.basename(sys.argv[0]) + cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0] print("""pydoc - the Python documentation tool -%s ... +{cmd} ... Show text documentation on something. may be the name of a Python keyword, topic, function, module, or package, or a dotted reference to a class or function within a module or module in a - package. If contains a '%s', it is used as the path to a + package. If contains a '{sep}', it is used as the path to a Python source file to document. If name is 'keywords', 'topics', or 'modules', a listing of these things is displayed. -%s -k +{cmd} -k Search for a keyword in the synopsis lines of all available modules. -%s -p - Start an HTTP server on the given port on the local machine. +{cmd} -p + Start an HTTP server on the given port on the local machine. Port + number 0 can be used to get an arbitrary unused port. + +{cmd} -b + Start an HTTP server on an arbitrary unused port and open a Web browser + to interactively browse documentation. The -p option can be used with + the -b option to explicitly specify the server port. -%s -g - Pop up a graphical interface for finding and serving documentation. +{cmd} -g + Deprecated. -%s -w ... +{cmd} -w ... Write out the HTML documentation for a module to a file in the current - directory. If contains a '%s', it is treated as a filename; if + directory. If contains a '{sep}', it is treated as a filename; if it names a directory, documentation is written for all the contents. -""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)) +""".format(cmd=cmd, sep=os.sep)) -if __name__ == '__main__': cli() +if __name__ == '__main__': + cli() Modified: python/branches/py3k-cdecimal/Lib/pydoc_data/topics.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/pydoc_data/topics.py (original) +++ python/branches/py3k-cdecimal/Lib/pydoc_data/topics.py Sun Jan 2 13:18:37 2011 @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Sat Nov 13 06:34:47 2010 +# Autogenerated by Sphinx on Sun Dec 19 11:18:44 2010 topics = {'assert': '\nThe ``assert`` statement\n************************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, ``assert expression``, is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, ``assert expression1, expression2``, is equivalent\nto\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that ``__debug__`` and ``AssertionError``\nrefer to the built-in variables with those names. In the current\nimplementation, the built-in variable ``__debug__`` is ``True`` under\nnormal circumstances, ``False`` when optimization is requested\n(command line option -O). The current code generator emits no code\nfor an assert statement when optimization is requested at compile\ntime. Note that it is unnecessary to include the source code for the\nexpression that failed in the error message; it will be displayed as\npart of the stack trace.\n\nAssignments to ``__debug__`` are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets. (This rule is relaxed as of\n Python 1.5; in earlier versions, the object had to be a tuple.\n Since strings are sequences, an assignment like ``a, b = "xy"`` is\n now legal as long as the string has the right length.)\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a ``NameError`` exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name in front of the name, with leading underscores removed, and\na single underscore inserted in front of the class name. For example,\nthe identifier ``__spam`` occurring in a class named ``Ham`` will be\ntransformed to ``_Ham__spam``. This transformation is independent of\nthe syntactical context in which the identifier is used. If the\ntransformed name is extremely long (longer than 255 characters),\nimplementation defined truncation may happen. If the class name\nconsists only of underscores, no transformation is done.\n', @@ -16,14 +16,14 @@ 'break': '\nThe ``break`` statement\n***********************\n\n break_stmt ::= "break"\n\n``break`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition\nwithin that loop.\n\nIt terminates the nearest enclosing loop, skipping the optional\n``else`` clause if the loop has one.\n\nIf a ``for`` loop is terminated by ``break``, the loop control target\nkeeps its current value.\n\nWhen ``break`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nleaving the loop.\n', 'callable-types': '\nEmulating callable objects\n**************************\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n', 'calls': '\nCalls\n*****\n\nA call calls a callable object (e.g., a function) with a possibly\nempty series of arguments:\n\n call ::= primary "(" [argument_list [","] | comprehension] ")"\n argument_list ::= positional_arguments ["," keyword_arguments]\n ["," "*" expression] ["," keyword_arguments]\n ["," "**" expression]\n | keyword_arguments ["," "*" expression]\n ["," keyword_arguments] ["," "**" expression]\n | "*" expression ["," keyword_arguments] ["," "**" expression]\n | "**" expression\n positional_arguments ::= expression ("," expression)*\n keyword_arguments ::= keyword_item ("," keyword_item)*\n keyword_item ::= identifier "=" expression\n\nA trailing comma may be present after the positional and keyword\narguments but does not affect the semantics.\n\nThe primary must evaluate to a callable object (user-defined\nfunctions, built-in functions, methods of built-in objects, class\nobjects, methods of class instances, and all objects having a\n``__call__()`` method are callable). All argument expressions are\nevaluated before the call is attempted. Please refer to section\n*Function definitions* for the syntax of formal parameter lists.\n\nIf keyword arguments are present, they are first converted to\npositional arguments, as follows. First, a list of unfilled slots is\ncreated for the formal parameters. If there are N positional\narguments, they are placed in the first N slots. Next, for each\nkeyword argument, the identifier is used to determine the\ncorresponding slot (if the identifier is the same as the first formal\nparameter name, the first slot is used, and so on). If the slot is\nalready filled, a ``TypeError`` exception is raised. Otherwise, the\nvalue of the argument is placed in the slot, filling it (even if the\nexpression is ``None``, it fills the slot). When all arguments have\nbeen processed, the slots that are still unfilled are filled with the\ncorresponding default value from the function definition. (Default\nvalues are calculated, once, when the function is defined; thus, a\nmutable object such as a list or dictionary used as default value will\nbe shared by all calls that don\'t specify an argument value for the\ncorresponding slot; this should usually be avoided.) If there are any\nunfilled slots for which no default value is specified, a\n``TypeError`` exception is raised. Otherwise, the list of filled\nslots is used as the argument list for the call.\n\n**CPython implementation detail:** An implementation may provide\nbuilt-in functions whose positional parameters do not have names, even\nif they are \'named\' for the purpose of documentation, and which\ntherefore cannot be supplied by keyword. In CPython, this is the case\nfor functions implemented in C that use ``PyArg_ParseTuple()`` to\nparse their arguments.\n\nIf there are more positional arguments than there are formal parameter\nslots, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``*identifier`` is present; in this case, that formal\nparameter receives a tuple containing the excess positional arguments\n(or an empty tuple if there were no excess positional arguments).\n\nIf any keyword argument does not correspond to a formal parameter\nname, a ``TypeError`` exception is raised, unless a formal parameter\nusing the syntax ``**identifier`` is present; in this case, that\nformal parameter receives a dictionary containing the excess keyword\narguments (using the keywords as keys and the argument values as\ncorresponding values), or a (new) empty dictionary if there were no\nexcess keyword arguments.\n\nIf the syntax ``*expression`` appears in the function call,\n``expression`` must evaluate to a sequence. Elements from this\nsequence are treated as if they were additional positional arguments;\nif there are positional arguments *x1*,..., *xN*, and ``expression``\nevaluates to a sequence *y1*, ..., *yM*, this is equivalent to a call\nwith M+N positional arguments *x1*, ..., *xN*, *y1*, ..., *yM*.\n\nA consequence of this is that although the ``*expression`` syntax may\nappear *after* some keyword arguments, it is processed *before* the\nkeyword arguments (and the ``**expression`` argument, if any -- see\nbelow). So:\n\n >>> def f(a, b):\n ... print(a, b)\n ...\n >>> f(b=1, *(2,))\n 2 1\n >>> f(a=1, *(2,))\n Traceback (most recent call last):\n File "", line 1, in ?\n TypeError: f() got multiple values for keyword argument \'a\'\n >>> f(1, *(2,))\n 1 2\n\nIt is unusual for both keyword arguments and the ``*expression``\nsyntax to be used in the same call, so in practice this confusion does\nnot arise.\n\nIf the syntax ``**expression`` appears in the function call,\n``expression`` must evaluate to a mapping, the contents of which are\ntreated as additional keyword arguments. In the case of a keyword\nappearing in both ``expression`` and as an explicit keyword argument,\na ``TypeError`` exception is raised.\n\nFormal parameters using the syntax ``*identifier`` or ``**identifier``\ncannot be used as positional argument slots or as keyword argument\nnames.\n\nA call always returns some value, possibly ``None``, unless it raises\nan exception. How this value is computed depends on the type of the\ncallable object.\n\nIf it is---\n\na user-defined function:\n The code block for the function is executed, passing it the\n argument list. The first thing the code block will do is bind the\n formal parameters to the arguments; this is described in section\n *Function definitions*. When the code block executes a ``return``\n statement, this specifies the return value of the function call.\n\na built-in function or method:\n The result is up to the interpreter; see *Built-in Functions* for\n the descriptions of built-in functions and methods.\n\na class object:\n A new instance of that class is returned.\n\na class instance method:\n The corresponding user-defined function is called, with an argument\n list that is one longer than the argument list of the call: the\n instance becomes the first argument.\n\na class instance:\n The class must define a ``__call__()`` method; the effect is then\n the same as if that method was called.\n', - 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing.\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3116** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'class': '\nClass definitions\n*****************\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3116** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'comparisons': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and ``2 == float(2)`` but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', - 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting\nof: ``exc_type``, the exception class; ``exc_value``, the exception\ninstance; ``exc_traceback``, a traceback object (see section *The\nstandard type hierarchy*) identifying the point in the program where\nthe exception occurred. ``sys.exc_info()`` values are restored to\ntheir previous values (before the call) when returning from a function\nthat handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing.\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3116** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', + 'compound': '\nCompound statements\n*******************\n\nCompound statements contain (groups of) other statements; they affect\nor control the execution of those other statements in some way. In\ngeneral, compound statements span multiple lines, although in simple\nincarnations a whole compound statement may be contained in one line.\n\nThe ``if``, ``while`` and ``for`` statements implement traditional\ncontrol flow constructs. ``try`` specifies exception handlers and/or\ncleanup code for a group of statements, while the ``with`` statement\nallows the execution of initialization and finalization code around a\nblock of code. Function and class definitions are also syntactically\ncompound statements.\n\nCompound statements consist of one or more \'clauses.\' A clause\nconsists of a header and a \'suite.\' The clause headers of a\nparticular compound statement are all at the same indentation level.\nEach clause header begins with a uniquely identifying keyword and ends\nwith a colon. A suite is a group of statements controlled by a\nclause. A suite can be one or more semicolon-separated simple\nstatements on the same line as the header, following the header\'s\ncolon, or it can be one or more indented statements on subsequent\nlines. Only the latter form of suite can contain nested compound\nstatements; the following is illegal, mostly because it wouldn\'t be\nclear to which ``if`` clause a following ``else`` clause would belong:\n\n if test1: if test2: print(x)\n\nAlso note that the semicolon binds tighter than the colon in this\ncontext, so that in the following example, either all or none of the\n``print()`` calls are executed:\n\n if x < y < z: print(x); print(y); print(z)\n\nSummarizing:\n\n compound_stmt ::= if_stmt\n | while_stmt\n | for_stmt\n | try_stmt\n | with_stmt\n | funcdef\n | classdef\n suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT\n statement ::= stmt_list NEWLINE | compound_stmt\n stmt_list ::= simple_stmt (";" simple_stmt)* [";"]\n\nNote that statements always end in a ``NEWLINE`` possibly followed by\na ``DEDENT``. Also note that optional continuation clauses always\nbegin with a keyword that cannot start a statement, thus there are no\nambiguities (the \'dangling ``else``\' problem is solved in Python by\nrequiring nested ``if`` statements to be indented).\n\nThe formatting of the grammar rules in the following sections places\neach clause on a separate line for clarity.\n\n\nThe ``if`` statement\n====================\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n\n\nThe ``while`` statement\n=======================\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n\n\nThe ``for`` statement\n=====================\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n\n\nThe ``try`` statement\n=====================\n\nThe ``try`` statement specifies exception handlers and/or cleanup code\nfor a group of statements:\n\n try_stmt ::= try1_stmt | try2_stmt\n try1_stmt ::= "try" ":" suite\n ("except" [expression ["as" target]] ":" suite)+\n ["else" ":" suite]\n ["finally" ":" suite]\n try2_stmt ::= "try" ":" suite\n "finally" ":" suite\n\nThe ``except`` clause(s) specify one or more exception handlers. When\nno exception occurs in the ``try`` clause, no exception handler is\nexecuted. When an exception occurs in the ``try`` suite, a search for\nan exception handler is started. This search inspects the except\nclauses in turn until one is found that matches the exception. An\nexpression-less except clause, if present, must be last; it matches\nany exception. For an except clause with an expression, that\nexpression is evaluated, and the clause matches the exception if the\nresulting object is "compatible" with the exception. An object is\ncompatible with an exception if it is the class or a base class of the\nexception object or a tuple containing an item compatible with the\nexception.\n\nIf no except clause matches the exception, the search for an exception\nhandler continues in the surrounding code and on the invocation stack.\n[1]\n\nIf the evaluation of an expression in the header of an except clause\nraises an exception, the original search for a handler is canceled and\na search starts for the new exception in the surrounding code and on\nthe call stack (it is treated as if the entire ``try`` statement\nraised the exception).\n\nWhen a matching except clause is found, the exception is assigned to\nthe target specified after the ``as`` keyword in that except clause,\nif present, and the except clause\'s suite is executed. All except\nclauses must have an executable block. When the end of this block is\nreached, execution continues normally after the entire try statement.\n(This means that if two nested handlers exist for the same exception,\nand the exception occurs in the try clause of the inner handler, the\nouter handler will not handle the exception.)\n\nWhen an exception has been assigned using ``as target``, it is cleared\nat the end of the except clause. This is as if\n\n except E as N:\n foo\n\nwas translated to\n\n except E as N:\n try:\n foo\n finally:\n del N\n\nThis means the exception must be assigned to a different name to be\nable to refer to it after the except clause. Exceptions are cleared\nbecause with the traceback attached to them, they form a reference\ncycle with the stack frame, keeping all locals in that frame alive\nuntil the next garbage collection occurs.\n\nBefore an except clause\'s suite is executed, details about the\nexception are stored in the ``sys`` module and can be access via\n``sys.exc_info()``. ``sys.exc_info()`` returns a 3-tuple consisting\nof: ``exc_type``, the exception class; ``exc_value``, the exception\ninstance; ``exc_traceback``, a traceback object (see section *The\nstandard type hierarchy*) identifying the point in the program where\nthe exception occurred. ``sys.exc_info()`` values are restored to\ntheir previous values (before the call) when returning from a function\nthat handled an exception.\n\nThe optional ``else`` clause is executed if and when control flows off\nthe end of the ``try`` clause. [2] Exceptions in the ``else`` clause\nare not handled by the preceding ``except`` clauses.\n\nIf ``finally`` is present, it specifies a \'cleanup\' handler. The\n``try`` clause is executed, including any ``except`` and ``else``\nclauses. If an exception occurs in any of the clauses and is not\nhandled, the exception is temporarily saved. The ``finally`` clause is\nexecuted. If there is a saved exception, it is re-raised at the end\nof the ``finally`` clause. If the ``finally`` clause raises another\nexception or executes a ``return`` or ``break`` statement, the saved\nexception is lost. The exception information is not available to the\nprogram during execution of the ``finally`` clause.\n\nWhen a ``return``, ``break`` or ``continue`` statement is executed in\nthe ``try`` suite of a ``try``...``finally`` statement, the\n``finally`` clause is also executed \'on the way out.\' A ``continue``\nstatement is illegal in the ``finally`` clause. (The reason is a\nproblem with the current implementation --- this restriction may be\nlifted in the future).\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information on using the ``raise`` statement to\ngenerate exceptions may be found in section *The raise statement*.\n\n\nThe ``with`` statement\n======================\n\nThe ``with`` statement is used to wrap the execution of a block with\nmethods defined by a context manager (see section *With Statement\nContext Managers*). This allows common\n``try``...``except``...``finally`` usage patterns to be encapsulated\nfor convenient reuse.\n\n with_stmt ::= "with" with_item ("," with_item)* ":" suite\n with_item ::= expression ["as" target]\n\nThe execution of the ``with`` statement with one "item" proceeds as\nfollows:\n\n1. The context expression (the expression given in the ``with_item``)\n is evaluated to obtain a context manager.\n\n2. The context manager\'s ``__exit__()`` is loaded for later use.\n\n3. The context manager\'s ``__enter__()`` method is invoked.\n\n4. If a target was included in the ``with`` statement, the return\n value from ``__enter__()`` is assigned to it.\n\n Note: The ``with`` statement guarantees that if the ``__enter__()``\n method returns without an error, then ``__exit__()`` will always\n be called. Thus, if an error occurs during the assignment to the\n target list, it will be treated the same as an error occurring\n within the suite would be. See step 6 below.\n\n5. The suite is executed.\n\n6. The context manager\'s ``__exit__()`` method is invoked. If an\n exception caused the suite to be exited, its type, value, and\n traceback are passed as arguments to ``__exit__()``. Otherwise,\n three ``None`` arguments are supplied.\n\n If the suite was exited due to an exception, and the return value\n from the ``__exit__()`` method was false, the exception is\n reraised. If the return value was true, the exception is\n suppressed, and execution continues with the statement following\n the ``with`` statement.\n\n If the suite was exited for any reason other than an exception, the\n return value from ``__exit__()`` is ignored, and execution proceeds\n at the normal location for the kind of exit that was taken.\n\nWith more than one item, the context managers are processed as if\nmultiple ``with`` statements were nested:\n\n with A() as a, B() as b:\n suite\n\nis equivalent to\n\n with A() as a:\n with B() as b:\n suite\n\nChanged in version 3.1: Support for multiple context expressions.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nFunction definitions\n====================\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n\n\nClass definitions\n=================\n\nA class definition defines a class object (see section *The standard\ntype hierarchy*):\n\n classdef ::= [decorators] "class" classname [inheritance] ":" suite\n inheritance ::= "(" [argument_list [","] | comprehension] ")"\n classname ::= identifier\n\nA class definition is an executable statement. The inheritance list\nusually gives a list of base classes (see *Customizing class creation*\nfor more advanced uses), so each item in the list should evaluate to a\nclass object which allows subclassing. Classes without an inheritance\nlist inherit, by default, from the base class ``object``; hence,\n\n class Foo:\n pass\n\nis equivalent to\n\n class Foo(object):\n pass\n\nThe class\'s suite is then executed in a new execution frame (see\n*Naming and binding*), using a newly created local namespace and the\noriginal global namespace. (Usually, the suite contains mostly\nfunction definitions.) When the class\'s suite finishes execution, its\nexecution frame is discarded but its local namespace is saved. [4] A\nclass object is then created using the inheritance list for the base\nclasses and the saved local namespace for the attribute dictionary.\nThe class name is bound to this class object in the original local\nnamespace.\n\nClass creation can be customized heavily using *metaclasses*.\n\nClasses can also be decorated: just like when decorating functions,\n\n @f1(arg)\n @f2\n class Foo: pass\n\nis equivalent to\n\n class Foo: pass\n Foo = f1(arg)(f2(Foo))\n\nThe evaluation rules for the decorator expressions are the same as for\nfunction decorators. The result must be a class object, which is then\nbound to the class name.\n\n**Programmer\'s note:** Variables defined in the class definition are\nclass attributes; they are shared by instances. Instance attributes\ncan be set in a method with ``self.name = value``. Both class and\ninstance attributes are accessible through the notation\n"``self.name``", and an instance attribute hides a class attribute\nwith the same name when accessed in this way. Class attributes can be\nused as defaults for instance attributes, but using mutable values\nthere can lead to unexpected results. *Descriptors* can be used to\ncreate instance variables with different implementation details.\n\nSee also:\n\n **PEP 3116** - Metaclasses in Python 3 **PEP 3129** - Class\n Decorators\n\n-[ Footnotes ]-\n\n[1] The exception is propagated to the invocation stack only if there\n is no ``finally`` clause that negates the exception.\n\n[2] Currently, control "flows off the end" except in the case of an\n exception or the execution of a ``return``, ``continue``, or\n ``break`` statement.\n\n[3] A string literal appearing as the first statement in the function\n body is transformed into the function\'s ``__doc__`` attribute and\n therefore the function\'s *docstring*.\n\n[4] A string literal appearing as the first statement in the class\n body is transformed into the namespace\'s ``__doc__`` item and\n therefore the class\'s *docstring*.\n', 'context-managers': '\nWith Statement Context Managers\n*******************************\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n', 'continue': '\nThe ``continue`` statement\n**************************\n\n continue_stmt ::= "continue"\n\n``continue`` may only occur syntactically nested in a ``for`` or\n``while`` loop, but not nested in a function or class definition or\n``finally`` clause within that loop. It continues with the next cycle\nof the nearest enclosing loop.\n\nWhen ``continue`` passes control out of a ``try`` statement with a\n``finally`` clause, that ``finally`` clause is executed before really\nstarting the next loop cycle.\n', 'conversions': '\nArithmetic conversions\n**********************\n\nWhen a description of an arithmetic operator below uses the phrase\n"the numeric arguments are converted to a common type," this means\nthat the operator implementation for built-in types works that way:\n\n* If either argument is a complex number, the other is converted to\n complex;\n\n* otherwise, if either argument is a floating point number, the other\n is converted to floating point;\n\n* otherwise, both must be integers and no conversion is necessary.\n\nSome additional rules apply for certain operators (e.g., a string left\nargument to the \'%\' operator). Extensions must define their own\nconversion behavior.\n', 'customization': '\nBasic customization\n*******************\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n', - 'debugger': '\n``pdb`` --- The Python Debugger\n*******************************\n\nThe module ``pdb`` defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible -- it is actually defined as the class\n``Pdb``. This is currently undocumented but easily understood by\nreading the source. The extension interface uses the modules ``bdb``\nand ``cmd``.\n\nThe debugger\'s prompt is ``(Pdb)``. Typical usage to run a program\nunder control of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\n``pdb.py`` can also be invoked as a script to debug other scripts.\nFor example:\n\n python3 -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 3.2: ``pdb.py`` now accepts a ``-c`` option that\nexecutes commands as if given in a ``.pdbrc`` file, see *Debugger\nCommands*.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the ``continue`` command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement, globals=None, locals=None)\n\n Execute the *statement* (given as a string or a code object) under\n debugger control. The debugger prompt appears before any code is\n executed; you can set breakpoints and type ``continue``, or you can\n step through the statement using ``step`` or ``next`` (all these\n commands are explained below). The optional *globals* and *locals*\n arguments specify the environment in which the code is executed; by\n default the dictionary of the module ``__main__`` is used. (See\n the explanation of the built-in ``exec()`` or ``eval()``\n functions.)\n\npdb.runeval(expression, globals=None, locals=None)\n\n Evaluate the *expression* (given as a string or a code object)\n under debugger control. When ``runeval()`` returns, it returns the\n value of the expression. Otherwise this function is similar to\n ``run()``.\n\npdb.runcall(function, *args, **kwds)\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When ``runcall()`` returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem(traceback=None)\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n ``sys.last_traceback``.\n\nThe ``run_*`` functions and ``set_trace()`` are aliases for\ninstantiating the ``Pdb`` class and calling the method of the same\nname. If you want to access further features, you have to do this\nyourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None)\n\n ``Pdb`` is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying ``cmd.Cmd`` class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n run(statement, globals=None, locals=None)\n runeval(expression, globals=None, locals=None)\n runcall(function, *args, **kwds)\n set_trace()\n\n See the documentation for the functions explained above.\n\n\nDebugger Commands\n=================\n\nThe commands recognized by the debugger are listed below. Most\ncommands can be abbreviated to one or two letters as indicated; e.g.\n``h(elp)`` means that either ``h`` or ``help`` can be used to enter\nthe help command (but not ``he`` or ``hel``, nor ``H`` or ``Help`` or\n``HELP``). Arguments to commands must be separated by whitespace\n(spaces or tabs). Optional arguments are enclosed in square brackets\n(``[]``) in the command syntax; the square brackets must not be typed.\nAlternatives in the command syntax are separated by a vertical bar\n(``|``).\n\nEntering a blank line repeats the last command entered. Exception: if\nthe last command was a ``list`` command, the next 11 lines are listed.\n\nCommands that the debugger doesn\'t recognize are assumed to be Python\nstatements and are executed in the context of the program being\ndebugged. Python statements can also be prefixed with an exclamation\npoint (``!``). This is a powerful way to inspect the program being\ndebugged; it is even possible to change a variable or call a function.\nWhen an exception occurs in such a statement, the exception name is\nprinted but the debugger\'s state is not changed.\n\nThe debugger supports *aliases*. Aliases can have parameters which\nallows one a certain level of adaptability to the context under\nexamination.\n\nMultiple commands may be entered on a single line, separated by\n``;;``. (A single ``;`` is not used as it is the separator for\nmultiple commands in a line that is passed to the Python parser.) No\nintelligence is applied to separating the commands; the input is split\nat the first ``;;`` pair, even if it is in the middle of a quoted\nstring.\n\nIf a file ``.pdbrc`` exists in the user\'s home directory or in the\ncurrent directory, it is read in and executed as if it had been typed\nat the debugger prompt. This is particularly useful for aliases. If\nboth files exist, the one in the home directory is read first and\naliases defined there can be overridden by the local file.\n\nChanged in version 3.2: ``.pdbrc`` can now contain commands that\ncontinue debugging, such as ``continue`` or ``next``. Previously,\nthese commands had no effect.\n\nh(elp) [command]\n\n Without argument, print the list of available commands. With a\n *command* as argument, print help about that command. ``help pdb``\n displays the full documentation (the docstring of the ``pdb``\n module). Since the *command* argument must be an identifier,\n ``help exec`` must be entered to get help on the ``!`` command.\n\nw(here)\n\n Print a stack trace, with the most recent frame at the bottom. An\n arrow indicates the current frame, which determines the context of\n most commands.\n\nd(own) [count]\n\n Move the current frame *count* (default one) levels down in the\n stack trace (to a newer frame).\n\nu(p) [count]\n\n Move the current frame *count* (default one) levels up in the stack\n trace (to an older frame).\n\nb(reak) [([filename:]lineno | function) [, condition]]\n\n With a *lineno* argument, set a break there in the current file.\n With a *function* argument, set a break at the first executable\n statement within that function. The line number may be prefixed\n with a filename and a colon, to specify a breakpoint in another\n file (probably one that hasn\'t been loaded yet). The file is\n searched on ``sys.path``. Note that each breakpoint is assigned a\n number to which all the other breakpoint commands refer.\n\n If a second argument is present, it is an expression which must\n evaluate to true before the breakpoint is honored.\n\n Without argument, list all breaks, including for each breakpoint,\n the number of times that breakpoint has been hit, the current\n ignore count, and the associated condition if any.\n\ntbreak [([filename:]lineno | function) [, condition]]\n\n Temporary breakpoint, which is removed automatically when it is\n first hit. The arguments are the same as for ``break``.\n\ncl(ear) [bpnumber [bpnumber ...]]\n\n With a space separated list of breakpoint numbers, clear those\n breakpoints. Without argument, clear all breaks (but first ask\n confirmation).\n\ndisable [bpnumber [bpnumber ...]]\n\n Disable the breakpoints given as a space separated list of\n breakpoint numbers. Disabling a breakpoint means it cannot cause\n the program to stop execution, but unlike clearing a breakpoint, it\n remains in the list of breakpoints and can be (re-)enabled.\n\nenable [bpnumber [bpnumber ...]]\n\n Enable the breakpoints specified.\n\nignore bpnumber [count]\n\n Set the ignore count for the given breakpoint number. If count is\n omitted, the ignore count is set to 0. A breakpoint becomes active\n when the ignore count is zero. When non-zero, the count is\n decremented each time the breakpoint is reached and the breakpoint\n is not disabled and any associated condition evaluates to true.\n\ncondition bpnumber [condition]\n\n Set a new *condition* for the breakpoint, an expression which must\n evaluate to true before the breakpoint is honored. If *condition*\n is absent, any existing condition is removed; i.e., the breakpoint\n is made unconditional.\n\ncommands [bpnumber]\n\n Specify a list of commands for breakpoint number *bpnumber*. The\n commands themselves appear on the following lines. Type a line\n containing just ``end`` to terminate the commands. An example:\n\n (Pdb) commands 1\n (com) print some_variable\n (com) end\n (Pdb)\n\n To remove all commands from a breakpoint, type commands and follow\n it immediately with ``end``; that is, give no commands.\n\n With no *bpnumber* argument, commands refers to the last breakpoint\n set.\n\n You can use breakpoint commands to start your program up again.\n Simply use the continue command, or step, or any other command that\n resumes execution.\n\n Specifying any command resuming execution (currently continue,\n step, next, return, jump, quit and their abbreviations) terminates\n the command list (as if that command was immediately followed by\n end). This is because any time you resume execution (even with a\n simple next or step), you may encounter another breakpoint--which\n could have its own command list, leading to ambiguities about which\n list to execute.\n\n If you use the \'silent\' command in the command list, the usual\n message about stopping at a breakpoint is not printed. This may be\n desirable for breakpoints that are to print a specific message and\n then continue. If none of the other commands print anything, you\n see no sign that the breakpoint was reached.\n\ns(tep)\n\n Execute the current line, stop at the first possible occasion\n (either in a function that is called or on the next line in the\n current function).\n\nn(ext)\n\n Continue execution until the next line in the current function is\n reached or it returns. (The difference between ``next`` and\n ``step`` is that ``step`` stops inside a called function, while\n ``next`` executes called functions at (nearly) full speed, only\n stopping at the next line in the current function.)\n\nunt(il) [lineno]\n\n Without argument, continue execution until the line with a number\n greater than the current one is reached.\n\n With a line number, continue execution until a line with a number\n greater or equal to that is reached. In both cases, also stop when\n the current frame returns.\n\n Changed in version 3.2: Allow giving an explicit line number.\n\nr(eturn)\n\n Continue execution until the current function returns.\n\nc(ont(inue))\n\n Continue execution, only stop when a breakpoint is encountered.\n\nj(ump) lineno\n\n Set the next line that will be executed. Only available in the\n bottom-most frame. This lets you jump back and execute code again,\n or jump forward to skip code that you don\'t want to run.\n\n It should be noted that not all jumps are allowed -- for instance\n it is not possible to jump into the middle of a ``for`` loop or out\n of a ``finally`` clause.\n\nl(ist) [first[, last]]\n\n List source code for the current file. Without arguments, list 11\n lines around the current line or continue the previous listing.\n With ``.`` as argument, list 11 lines around the current line.\n With one argument, list 11 lines around at that line. With two\n arguments, list the given range; if the second argument is less\n than the first, it is interpreted as a count.\n\n The current line in the current frame is indicated by ``->``. If\n an exception is being debugged, the line where the exception was\n originally raised or propagated is indicated by ``>>``, if it\n differs from the current line.\n\n New in version 3.2: The ``>>`` marker.\n\nll | longlist\n\n List all source code for the current function or frame.\n Interesting lines are marked as for ``list``.\n\n New in version 3.2.\n\na(rgs)\n\n Print the argument list of the current function.\n\np(rint) expression\n\n Evaluate the *expression* in the current context and print its\n value.\n\npp expression\n\n Like the ``print`` command, except the value of the expression is\n pretty-printed using the ``pprint`` module.\n\nwhatis expression\n\n Print the type of the *expression*.\n\nsource expression\n\n Try to get source code for the given object and display it.\n\n New in version 3.2.\n\nalias [name [command]]\n\n Create an alias called *name* that executes *command*. The command\n must *not* be enclosed in quotes. Replaceable parameters can be\n indicated by ``%1``, ``%2``, and so on, while ``%*`` is replaced by\n all the parameters. If no command is given, the current alias for\n *name* is shown. If no arguments are given, all aliases are listed.\n\n Aliases may be nested and can contain anything that can be legally\n typed at the pdb prompt. Note that internal pdb commands *can* be\n overridden by aliases. Such a command is then hidden until the\n alias is removed. Aliasing is recursively applied to the first\n word of the command line; all other words in the line are left\n alone.\n\n As an example, here are two useful aliases (especially when placed\n in the ``.pdbrc`` file):\n\n # Print instance variables (usage "pi classInst")\n alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])\n # Print instance variables in self\n alias ps pi self\n\nunalias name\n\n Delete the specified alias.\n\n! statement\n\n Execute the (one-line) *statement* in the context of the current\n stack frame. The exclamation point can be omitted unless the first\n word of the statement resembles a debugger command. To set a\n global variable, you can prefix the assignment command with a\n ``global`` statement on the same line, e.g.:\n\n (Pdb) global list_options; list_options = [\'-l\']\n (Pdb)\n\nrun [args ...]\nrestart [args ...]\n\n Restart the debugged Python program. If an argument is supplied,\n it is split with ``shlex`` and the result is used as the new\n ``sys.argv``. History, breakpoints, actions and debugger options\n are preserved. ``restart`` is an alias for ``run``.\n\nq(uit)\n\n Quit from the debugger. The program being executed is aborted.\n\n-[ Footnotes ]-\n\n[1] Whether a frame is considered to originate in a certain module is\n determined by the ``__name__`` in the frame globals.\n', + 'debugger': '\n``pdb`` --- The Python Debugger\n*******************************\n\nThe module ``pdb`` defines an interactive source code debugger for\nPython programs. It supports setting (conditional) breakpoints and\nsingle stepping at the source line level, inspection of stack frames,\nsource code listing, and evaluation of arbitrary Python code in the\ncontext of any stack frame. It also supports post-mortem debugging\nand can be called under program control.\n\nThe debugger is extensible -- it is actually defined as the class\n``Pdb``. This is currently undocumented but easily understood by\nreading the source. The extension interface uses the modules ``bdb``\nand ``cmd``.\n\nThe debugger\'s prompt is ``(Pdb)``. Typical usage to run a program\nunder control of the debugger is:\n\n >>> import pdb\n >>> import mymodule\n >>> pdb.run(\'mymodule.test()\')\n > (0)?()\n (Pdb) continue\n > (1)?()\n (Pdb) continue\n NameError: \'spam\'\n > (1)?()\n (Pdb)\n\n``pdb.py`` can also be invoked as a script to debug other scripts.\nFor example:\n\n python3 -m pdb myscript.py\n\nWhen invoked as a script, pdb will automatically enter post-mortem\ndebugging if the program being debugged exits abnormally. After post-\nmortem debugging (or after normal exit of the program), pdb will\nrestart the program. Automatic restarting preserves pdb\'s state (such\nas breakpoints) and in most cases is more useful than quitting the\ndebugger upon program\'s exit.\n\nNew in version 3.2: ``pdb.py`` now accepts a ``-c`` option that\nexecutes commands as if given in a ``.pdbrc`` file, see *Debugger\nCommands*.\n\nThe typical usage to break into the debugger from a running program is\nto insert\n\n import pdb; pdb.set_trace()\n\nat the location you want to break into the debugger. You can then\nstep through the code following this statement, and continue running\nwithout the debugger using the ``continue`` command.\n\nThe typical usage to inspect a crashed program is:\n\n >>> import pdb\n >>> import mymodule\n >>> mymodule.test()\n Traceback (most recent call last):\n File "", line 1, in ?\n File "./mymodule.py", line 4, in test\n test2()\n File "./mymodule.py", line 3, in test2\n print(spam)\n NameError: spam\n >>> pdb.pm()\n > ./mymodule.py(3)test2()\n -> print(spam)\n (Pdb)\n\nThe module defines the following functions; each enters the debugger\nin a slightly different way:\n\npdb.run(statement, globals=None, locals=None)\n\n Execute the *statement* (given as a string or a code object) under\n debugger control. The debugger prompt appears before any code is\n executed; you can set breakpoints and type ``continue``, or you can\n step through the statement using ``step`` or ``next`` (all these\n commands are explained below). The optional *globals* and *locals*\n arguments specify the environment in which the code is executed; by\n default the dictionary of the module ``__main__`` is used. (See\n the explanation of the built-in ``exec()`` or ``eval()``\n functions.)\n\npdb.runeval(expression, globals=None, locals=None)\n\n Evaluate the *expression* (given as a string or a code object)\n under debugger control. When ``runeval()`` returns, it returns the\n value of the expression. Otherwise this function is similar to\n ``run()``.\n\npdb.runcall(function, *args, **kwds)\n\n Call the *function* (a function or method object, not a string)\n with the given arguments. When ``runcall()`` returns, it returns\n whatever the function call returned. The debugger prompt appears\n as soon as the function is entered.\n\npdb.set_trace()\n\n Enter the debugger at the calling stack frame. This is useful to\n hard-code a breakpoint at a given point in a program, even if the\n code is not otherwise being debugged (e.g. when an assertion\n fails).\n\npdb.post_mortem(traceback=None)\n\n Enter post-mortem debugging of the given *traceback* object. If no\n *traceback* is given, it uses the one of the exception that is\n currently being handled (an exception must be being handled if the\n default is to be used).\n\npdb.pm()\n\n Enter post-mortem debugging of the traceback found in\n ``sys.last_traceback``.\n\nThe ``run_*`` functions and ``set_trace()`` are aliases for\ninstantiating the ``Pdb`` class and calling the method of the same\nname. If you want to access further features, you have to do this\nyourself:\n\nclass class pdb.Pdb(completekey=\'tab\', stdin=None, stdout=None, skip=None, nosigint=False)\n\n ``Pdb`` is the debugger class.\n\n The *completekey*, *stdin* and *stdout* arguments are passed to the\n underlying ``cmd.Cmd`` class; see the description there.\n\n The *skip* argument, if given, must be an iterable of glob-style\n module name patterns. The debugger will not step into frames that\n originate in a module that matches one of these patterns. [1]\n\n By default, Pdb sets a handler for the SIGINT signal (which is sent\n when the user presses Ctrl-C on the console) when you give a\n ``continue`` command. This allows you to break into the debugger\n again by pressing Ctrl-C. If you want Pdb not to touch the SIGINT\n handler, set *nosigint* tot true.\n\n Example call to enable tracing with *skip*:\n\n import pdb; pdb.Pdb(skip=[\'django.*\']).set_trace()\n\n New in version 3.1: The *skip* argument.\n\n New in version 3.2: The *nosigint* argument. Previously, a SIGINT\n handler was never set by Pdb.\n\n run(statement, globals=None, locals=None)\n runeval(expression, globals=None, locals=None)\n runcall(function, *args, **kwds)\n set_trace()\n\n See the documentation for the functions explained above.\n\n\nDebugger Commands\n=================\n\nThe commands recognized by the debugger are listed below. Most\ncommands can be abbreviated to one or two letters as indicated; e.g.\n``h(elp)`` means that either ``h`` or ``help`` can be used to enter\nthe help command (but not ``he`` or ``hel``, nor ``H`` or ``Help`` or\n``HELP``). Arguments to commands must be separated by whitespace\n(spaces or tabs). Optional arguments are enclosed in square brackets\n(``[]``) in the command syntax; the square brackets must not be typed.\nAlternatives in the command syntax are separated by a vertical bar\n(``|``).\n\nEntering a blank line repeats the last command entered. Exception: if\nthe last command was a ``list`` command, the next 11 lines are listed.\n\nCommands that the debugger doesn\'t recognize are assumed to be Python\nstatements and are executed in the context of the program being\ndebugged. Python statements can also be prefixed with an exclamation\npoint (``!``). This is a powerful way to inspect the program being\ndebugged; it is even possible to change a variable or call a function.\nWhen an exception occurs in such a statement, the exception name is\nprinted but the debugger\'s state is not changed.\n\nThe debugger supports *aliases*. Aliases can have parameters which\nallows one a certain level of adaptability to the context under\nexamination.\n\nMultiple commands may be entered on a single line, separated by\n``;;``. (A single ``;`` is not used as it is the separator for\nmultiple commands in a line that is passed to the Python parser.) No\nintelligence is applied to separating the commands; the input is split\nat the first ``;;`` pair, even if it is in the middle of a quoted\nstring.\n\nIf a file ``.pdbrc`` exists in the user\'s home directory or in the\ncurrent directory, it is read in and executed as if it had been typed\nat the debugger prompt. This is particularly useful for aliases. If\nboth files exist, the one in the home directory is read first and\naliases defined there can be overridden by the local file.\n\nChanged in version 3.2: ``.pdbrc`` can now contain commands that\ncontinue debugging, such as ``continue`` or ``next``. Previously,\nthese commands had no effect.\n\nh(elp) [command]\n\n Without argument, print the list of available commands. With a\n *command* as argument, print help about that command. ``help pdb``\n displays the full documentation (the docstring of the ``pdb``\n module). Since the *command* argument must be an identifier,\n ``help exec`` must be entered to get help on the ``!`` command.\n\nw(here)\n\n Print a stack trace, with the most recent frame at the bottom. An\n arrow indicates the current frame, which determines the context of\n most commands.\n\nd(own) [count]\n\n Move the current frame *count* (default one) levels down in the\n stack trace (to a newer frame).\n\nu(p) [count]\n\n Move the current frame *count* (default one) levels up in the stack\n trace (to an older frame).\n\nb(reak) [([filename:]lineno | function) [, condition]]\n\n With a *lineno* argument, set a break there in the current file.\n With a *function* argument, set a break at the first executable\n statement within that function. The line number may be prefixed\n with a filename and a colon, to specify a breakpoint in another\n file (probably one that hasn\'t been loaded yet). The file is\n searched on ``sys.path``. Note that each breakpoint is assigned a\n number to which all the other breakpoint commands refer.\n\n If a second argument is present, it is an expression which must\n evaluate to true before the breakpoint is honored.\n\n Without argument, list all breaks, including for each breakpoint,\n the number of times that breakpoint has been hit, the current\n ignore count, and the associated condition if any.\n\ntbreak [([filename:]lineno | function) [, condition]]\n\n Temporary breakpoint, which is removed automatically when it is\n first hit. The arguments are the same as for ``break``.\n\ncl(ear) [filename:lineno | bpnumber [bpnumber ...]]\n\n With a *filename:lineno* argument, clear all the breakpoints at\n this line. With a space separated list of breakpoint numbers, clear\n those breakpoints. Without argument, clear all breaks (but first\n ask confirmation).\n\ndisable [bpnumber [bpnumber ...]]\n\n Disable the breakpoints given as a space separated list of\n breakpoint numbers. Disabling a breakpoint means it cannot cause\n the program to stop execution, but unlike clearing a breakpoint, it\n remains in the list of breakpoints and can be (re-)enabled.\n\nenable [bpnumber [bpnumber ...]]\n\n Enable the breakpoints specified.\n\nignore bpnumber [count]\n\n Set the ignore count for the given breakpoint number. If count is\n omitted, the ignore count is set to 0. A breakpoint becomes active\n when the ignore count is zero. When non-zero, the count is\n decremented each time the breakpoint is reached and the breakpoint\n is not disabled and any associated condition evaluates to true.\n\ncondition bpnumber [condition]\n\n Set a new *condition* for the breakpoint, an expression which must\n evaluate to true before the breakpoint is honored. If *condition*\n is absent, any existing condition is removed; i.e., the breakpoint\n is made unconditional.\n\ncommands [bpnumber]\n\n Specify a list of commands for breakpoint number *bpnumber*. The\n commands themselves appear on the following lines. Type a line\n containing just ``end`` to terminate the commands. An example:\n\n (Pdb) commands 1\n (com) print some_variable\n (com) end\n (Pdb)\n\n To remove all commands from a breakpoint, type commands and follow\n it immediately with ``end``; that is, give no commands.\n\n With no *bpnumber* argument, commands refers to the last breakpoint\n set.\n\n You can use breakpoint commands to start your program up again.\n Simply use the continue command, or step, or any other command that\n resumes execution.\n\n Specifying any command resuming execution (currently continue,\n step, next, return, jump, quit and their abbreviations) terminates\n the command list (as if that command was immediately followed by\n end). This is because any time you resume execution (even with a\n simple next or step), you may encounter another breakpoint--which\n could have its own command list, leading to ambiguities about which\n list to execute.\n\n If you use the \'silent\' command in the command list, the usual\n message about stopping at a breakpoint is not printed. This may be\n desirable for breakpoints that are to print a specific message and\n then continue. If none of the other commands print anything, you\n see no sign that the breakpoint was reached.\n\ns(tep)\n\n Execute the current line, stop at the first possible occasion\n (either in a function that is called or on the next line in the\n current function).\n\nn(ext)\n\n Continue execution until the next line in the current function is\n reached or it returns. (The difference between ``next`` and\n ``step`` is that ``step`` stops inside a called function, while\n ``next`` executes called functions at (nearly) full speed, only\n stopping at the next line in the current function.)\n\nunt(il) [lineno]\n\n Without argument, continue execution until the line with a number\n greater than the current one is reached.\n\n With a line number, continue execution until a line with a number\n greater or equal to that is reached. In both cases, also stop when\n the current frame returns.\n\n Changed in version 3.2: Allow giving an explicit line number.\n\nr(eturn)\n\n Continue execution until the current function returns.\n\nc(ont(inue))\n\n Continue execution, only stop when a breakpoint is encountered.\n\nj(ump) lineno\n\n Set the next line that will be executed. Only available in the\n bottom-most frame. This lets you jump back and execute code again,\n or jump forward to skip code that you don\'t want to run.\n\n It should be noted that not all jumps are allowed -- for instance\n it is not possible to jump into the middle of a ``for`` loop or out\n of a ``finally`` clause.\n\nl(ist) [first[, last]]\n\n List source code for the current file. Without arguments, list 11\n lines around the current line or continue the previous listing.\n With ``.`` as argument, list 11 lines around the current line.\n With one argument, list 11 lines around at that line. With two\n arguments, list the given range; if the second argument is less\n than the first, it is interpreted as a count.\n\n The current line in the current frame is indicated by ``->``. If\n an exception is being debugged, the line where the exception was\n originally raised or propagated is indicated by ``>>``, if it\n differs from the current line.\n\n New in version 3.2: The ``>>`` marker.\n\nll | longlist\n\n List all source code for the current function or frame.\n Interesting lines are marked as for ``list``.\n\n New in version 3.2.\n\na(rgs)\n\n Print the argument list of the current function.\n\np(rint) expression\n\n Evaluate the *expression* in the current context and print its\n value.\n\npp expression\n\n Like the ``print`` command, except the value of the expression is\n pretty-printed using the ``pprint`` module.\n\nwhatis expression\n\n Print the type of the *expression*.\n\nsource expression\n\n Try to get source code for the given object and display it.\n\n New in version 3.2.\n\ndisplay [expression]\n\n Display the value of the expression if it changed, each time\n execution stops in the current frame.\n\n Without expression, list all display expressions for the current\n frame.\n\n New in version 3.2.\n\nundisplay [expression]\n\n Do not display the expression any more in the current frame.\n Without expression, clear all display expressions for the current\n frame.\n\n New in version 3.2.\n\ninteract\n\n Start an interative interpreter (using the ``code`` module) whose\n global namespace contains all the (global and local) names found in\n the current scope.\n\n New in version 3.2.\n\nalias [name [command]]\n\n Create an alias called *name* that executes *command*. The command\n must *not* be enclosed in quotes. Replaceable parameters can be\n indicated by ``%1``, ``%2``, and so on, while ``%*`` is replaced by\n all the parameters. If no command is given, the current alias for\n *name* is shown. If no arguments are given, all aliases are listed.\n\n Aliases may be nested and can contain anything that can be legally\n typed at the pdb prompt. Note that internal pdb commands *can* be\n overridden by aliases. Such a command is then hidden until the\n alias is removed. Aliasing is recursively applied to the first\n word of the command line; all other words in the line are left\n alone.\n\n As an example, here are two useful aliases (especially when placed\n in the ``.pdbrc`` file):\n\n # Print instance variables (usage "pi classInst")\n alias pi for k in %1.__dict__.keys(): print("%1.",k,"=",%1.__dict__[k])\n # Print instance variables in self\n alias ps pi self\n\nunalias name\n\n Delete the specified alias.\n\n! statement\n\n Execute the (one-line) *statement* in the context of the current\n stack frame. The exclamation point can be omitted unless the first\n word of the statement resembles a debugger command. To set a\n global variable, you can prefix the assignment command with a\n ``global`` statement on the same line, e.g.:\n\n (Pdb) global list_options; list_options = [\'-l\']\n (Pdb)\n\nrun [args ...]\nrestart [args ...]\n\n Restart the debugged Python program. If an argument is supplied,\n it is split with ``shlex`` and the result is used as the new\n ``sys.argv``. History, breakpoints, actions and debugger options\n are preserved. ``restart`` is an alias for ``run``.\n\nq(uit)\n\n Quit from the debugger. The program being executed is aborted.\n\n-[ Footnotes ]-\n\n[1] Whether a frame is considered to originate in a certain module is\n determined by the ``__name__`` in the frame globals.\n', 'del': '\nThe ``del`` statement\n*********************\n\n del_stmt ::= "del" target_list\n\nDeletion is recursively defined very similar to the way assignment is\ndefined. Rather that spelling it out in full details, here are some\nhints.\n\nDeletion of a target list recursively deletes each target, from left\nto right.\n\nDeletion of a name removes the binding of that name from the local or\nglobal namespace, depending on whether the name occurs in a ``global``\nstatement in the same code block. If the name is unbound, a\n``NameError`` exception will be raised.\n\nDeletion of attribute references, subscriptions and slicings is passed\nto the primary object involved; deletion of a slicing is in general\nequivalent to assignment of an empty slice of the right type (but even\nthis is determined by the sliced object).\n\nChanged in version 3.2.\n', 'dict': '\nDictionary displays\n*******************\n\nA dictionary display is a possibly empty series of key/datum pairs\nenclosed in curly braces:\n\n dict_display ::= "{" [key_datum_list | dict_comprehension] "}"\n key_datum_list ::= key_datum ("," key_datum)* [","]\n key_datum ::= expression ":" expression\n dict_comprehension ::= expression ":" expression comp_for\n\nA dictionary display yields a new dictionary object.\n\nIf a comma-separated sequence of key/datum pairs is given, they are\nevaluated from left to right to define the entries of the dictionary:\neach key object is used as a key into the dictionary to store the\ncorresponding datum. This means that you can specify the same key\nmultiple times in the key/datum list, and the final dictionary\'s value\nfor that key will be the last one given.\n\nA dict comprehension, in contrast to list and set comprehensions,\nneeds two expressions separated with a colon followed by the usual\n"for" and "if" clauses. When the comprehension is run, the resulting\nkey and value elements are inserted in the new dictionary in the order\nthey are produced.\n\nRestrictions on the types of the key values are listed earlier in\nsection *The standard type hierarchy*. (To summarize, the key type\nshould be *hashable*, which excludes all mutable objects.) Clashes\nbetween duplicate keys are not detected; the last datum (textually\nrightmost in the display) stored for a given key value prevails.\n', 'dynamic-features': '\nInteraction with dynamic features\n*********************************\n\nThere are several cases where Python statements are illegal when used\nin conjunction with nested scopes that contain free variables.\n\nIf a variable is referenced in an enclosing scope, it is illegal to\ndelete the name. An error will be reported at compile time.\n\nIf the wild card form of import --- ``import *`` --- is used in a\nfunction and the function contains or is a nested block with free\nvariables, the compiler will raise a ``SyntaxError``.\n\nThe ``eval()`` and ``exec()`` functions do not have access to the full\nenvironment for resolving names. Names may be resolved in the local\nand global namespaces of the caller. Free variables are not resolved\nin the nearest enclosing namespace, but in the global namespace. [1]\nThe ``exec()`` and ``eval()`` functions have optional arguments to\noverride the global and local namespace. If only one namespace is\nspecified, it is used for both.\n', @@ -33,14 +33,14 @@ 'exprlists': '\nExpression lists\n****************\n\n expression_list ::= expression ( "," expression )* [","]\n\nAn expression list containing at least one comma yields a tuple. The\nlength of the tuple is the number of expressions in the list. The\nexpressions are evaluated from left to right.\n\nThe trailing comma is required only to create a single tuple (a.k.a. a\n*singleton*); it is optional in all other cases. A single expression\nwithout a trailing comma doesn\'t create a tuple, but rather yields the\nvalue of that expression. (To create an empty tuple, use an empty pair\nof parentheses: ``()``.)\n', 'floating': '\nFloating point literals\n***********************\n\nFloating point literals are described by the following lexical\ndefinitions:\n\n floatnumber ::= pointfloat | exponentfloat\n pointfloat ::= [intpart] fraction | intpart "."\n exponentfloat ::= (intpart | pointfloat) exponent\n intpart ::= digit+\n fraction ::= "." digit+\n exponent ::= ("e" | "E") ["+" | "-"] digit+\n\nNote that the integer and exponent parts are always interpreted using\nradix 10. For example, ``077e010`` is legal, and denotes the same\nnumber as ``77e10``. The allowed range of floating point literals is\nimplementation-dependent. Some examples of floating point literals:\n\n 3.14 10. .001 1e100 3.14e-10 0e0\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator ``-`` and the\nliteral ``1``.\n', 'for': '\nThe ``for`` statement\n*********************\n\nThe ``for`` statement is used to iterate over the elements of a\nsequence (such as a string, tuple or list) or other iterable object:\n\n for_stmt ::= "for" target_list "in" expression_list ":" suite\n ["else" ":" suite]\n\nThe expression list is evaluated once; it should yield an iterable\nobject. An iterator is created for the result of the\n``expression_list``. The suite is then executed once for each item\nprovided by the iterator, in the order of ascending indices. Each\nitem in turn is assigned to the target list using the standard rules\nfor assignments (see *Assignment statements*), and then the suite is\nexecuted. When the items are exhausted (which is immediately when the\nsequence is empty or an iterator raises a ``StopIteration``\nexception), the suite in the ``else`` clause, if present, is executed,\nand the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ncontinues with the next item, or with the ``else`` clause if there was\nno next item.\n\nThe suite may assign to the variable(s) in the target list; this does\nnot affect the next item assigned to it.\n\nNames in the target list are not deleted when the loop is finished,\nbut if the sequence is empty, it will not have been assigned to at all\nby the loop. Hint: the built-in function ``range()`` returns an\niterator of integers suitable to emulate the effect of Pascal\'s ``for\ni := a to b do``; e.g., ``list(range(3))`` returns the list ``[0, 1,\n2]``.\n\nNote: There is a subtlety when the sequence is being modified by the loop\n (this can only occur for mutable sequences, i.e. lists). An\n internal counter is used to keep track of which item is used next,\n and this is incremented on each iteration. When this counter has\n reached the length of the sequence the loop terminates. This means\n that if the suite deletes the current (or a previous) item from the\n sequence, the next item will be skipped (since it gets the index of\n the current item which has already been treated). Likewise, if the\n suite inserts an item in the sequence before the current item, the\n current item will be treated again the next time through the loop.\n This can lead to nasty bugs that can be avoided by making a\n temporary copy using a slice of the whole sequence, e.g.,\n\n for x in a[:]:\n if x < 0: a.remove(x)\n', - 'formatstrings': '\nFormat String Syntax\n********************\n\nThe ``str.format()`` method and the ``Formatter`` class share the same\nsyntax for format strings (although in the case of ``Formatter``,\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n``{}``. Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n``{{`` and ``}}``.\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point ``\'!\'``, and a *format_spec*, which\nis preceded by a colon ``\':\'``. These specify a non-default format\nfor the replacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either\neither a number or a keyword. If it\'s a number, it refers to a\npositional argument, and if it\'s a keyword, it refers to a named\nkeyword argument. If the numerical arg_names in a format string are\n0, 1, 2, ... in sequence, they can all be omitted (not just some) and\nthe numbers 0, 1, 2, ... will be automatically inserted in that order.\nThe *arg_name* can be followed by any number of index or attribute\nexpressions. An expression of the form ``\'.name\'`` selects the named\nattribute using ``getattr()``, while an expression of the form\n``\'[index]\'`` does an index lookup using ``__getitem__()``.\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so ``\'{} {}\'`` is equivalent to ``\'{0} {1}\'``.\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the\n``__format__()`` method of the value itself. However, in some cases\nit is desirable to force a type to be formatted as a string,\noverriding its own definition of formatting. By converting the value\nto a string before calling ``__format__()``, the normal formatting\nlogic is bypassed.\n\nThree conversion flags are currently supported: ``\'!s\'`` which calls\n``str()`` on the value, ``\'!r\'`` which calls ``repr()`` and ``\'!a\'``\nwhich calls ``ascii()``.\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in ``format()`` function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string (``""``) produces\nthe same result as if you had called ``str()`` on the value. A non-\nempty format string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nThe *fill* character can be any character other than \'{\' or \'}\'. The\npresence of a fill character is signaled by the character following\nit, which must be one of the alignment options. If the second\ncharacter of *format_spec* is not a valid alignment option, then it is\nassumed that both the fill character and the alignment option are\nabsent.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'<\'`` | Forces the field to be left-aligned within the available |\n | | space (this is the default). |\n +-----------+------------------------------------------------------------+\n | ``\'>\'`` | Forces the field to be right-aligned within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n | ``\'=\'`` | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | ``\'^\'`` | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'+\'`` | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | ``\'-\'`` | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe ``\'#\'`` option is only valid for integers, and only for binary,\noctal, or hexadecimal output. If present, it specifies that the\noutput will be prefixed by ``\'0b\'``, ``\'0o\'``, or ``\'0x\'``,\nrespectively.\n\nThe ``\',\'`` option signals the use of a comma for a thousands\nseparator. For a locale aware separator, use the ``\'n\'`` integer\npresentation type instead.\n\nChanged in version 3.1: Added the ``\',\'`` option (see also **PEP\n378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nIf the *width* field is preceded by a zero (``\'0\'``) character, this\nenables zero-padding. This is equivalent to an *alignment* type of\n``\'=\'`` and a *fill* character of ``\'0\'``.\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with ``\'f\'`` and ``\'F\'``, or before and after the decimal\npoint for a floating point value formatted with ``\'g\'`` or ``\'G\'``.\nFor non-number types the field indicates the maximum field size - in\nother words, how many characters will be used from the field content.\nThe *precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'s\'`` | String format. This is the default type for strings and |\n | | may be omitted. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'s\'``. |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'b\'`` | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | ``\'c\'`` | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | ``\'d\'`` | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | ``\'o\'`` | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | ``\'x\'`` | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'X\'`` | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'d\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'d\'``. |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except\n``\'n\'`` and None). When doing so, ``float()`` is used to convert the\ninteger to a floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'e\'`` | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n +-----------+------------------------------------------------------------+\n | ``\'E\'`` | Exponent notation. Same as ``\'e\'`` except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | ``\'f\'`` | Fixed point. Displays the number as a fixed-point number. |\n +-----------+------------------------------------------------------------+\n | ``\'F\'`` | Fixed point. Same as ``\'f\'``, but converts ``nan`` to |\n | | ``NAN`` and ``inf`` to ``INF``. |\n +-----------+------------------------------------------------------------+\n | ``\'g\'`` | General format. For a given precision ``p >= 1``, this |\n | | rounds the number to ``p`` significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1`` would have exponent ``exp``. Then if ``-4 <= exp |\n | | < p``, the number is formatted with presentation type |\n | | ``\'f\'`` and precision ``p-1-exp``. Otherwise, the number |\n | | is formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1``. In both cases insignificant trailing zeros are |\n | | removed from the significand, and the decimal point is |\n | | also removed if there are no remaining digits following |\n | | it. Positive and negative infinity, positive and negative |\n | | zero, and nans, are formatted as ``inf``, ``-inf``, ``0``, |\n | | ``-0`` and ``nan`` respectively, regardless of the |\n | | precision. A precision of ``0`` is treated as equivalent |\n | | to a precision of ``1``. |\n +-----------+------------------------------------------------------------+\n | ``\'G\'`` | General format. Same as ``\'g\'`` except switches to ``\'E\'`` |\n | | if the number gets too large. The representations of |\n | | infinity and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'g\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | ``\'%\'`` | Percentage. Multiplies the number by 100 and displays in |\n | | fixed (``\'f\'``) format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to ``\'g\'``, except with at least one digit past |\n | | the decimal point and a default precision of 12. This is |\n | | intended to match ``str()``, except you can add the other |\n | | format modifiers. |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old ``%``-formatting.\n\nIn most of the cases the syntax is similar to the old\n``%``-formatting, with the addition of the ``{}`` and with ``:`` used\ninstead of ``%``. For example, ``\'%03.2f\'`` can be translated to\n``\'{:03.2f}\'``.\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing ``%s`` and ``%r``:\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing ``%x`` and ``%o`` and converting the value to different\nbases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}.\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{align}{fill}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12):\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', + 'formatstrings': '\nFormat String Syntax\n********************\n\nThe ``str.format()`` method and the ``Formatter`` class share the same\nsyntax for format strings (although in the case of ``Formatter``,\nsubclasses can define their own format string syntax).\n\nFormat strings contain "replacement fields" surrounded by curly braces\n``{}``. Anything that is not contained in braces is considered literal\ntext, which is copied unchanged to the output. If you need to include\na brace character in the literal text, it can be escaped by doubling:\n``{{`` and ``}}``.\n\nThe grammar for a replacement field is as follows:\n\n replacement_field ::= "{" [field_name] ["!" conversion] [":" format_spec] "}"\n field_name ::= arg_name ("." attribute_name | "[" element_index "]")*\n arg_name ::= [identifier | integer]\n attribute_name ::= identifier\n element_index ::= integer | index_string\n index_string ::= +\n conversion ::= "r" | "s" | "a"\n format_spec ::= \n\nIn less formal terms, the replacement field can start with a\n*field_name* that specifies the object whose value is to be formatted\nand inserted into the output instead of the replacement field. The\n*field_name* is optionally followed by a *conversion* field, which is\npreceded by an exclamation point ``\'!\'``, and a *format_spec*, which\nis preceded by a colon ``\':\'``. These specify a non-default format\nfor the replacement value.\n\nSee also the *Format Specification Mini-Language* section.\n\nThe *field_name* itself begins with an *arg_name* that is either\neither a number or a keyword. If it\'s a number, it refers to a\npositional argument, and if it\'s a keyword, it refers to a named\nkeyword argument. If the numerical arg_names in a format string are\n0, 1, 2, ... in sequence, they can all be omitted (not just some) and\nthe numbers 0, 1, 2, ... will be automatically inserted in that order.\nThe *arg_name* can be followed by any number of index or attribute\nexpressions. An expression of the form ``\'.name\'`` selects the named\nattribute using ``getattr()``, while an expression of the form\n``\'[index]\'`` does an index lookup using ``__getitem__()``.\n\nChanged in version 3.1: The positional argument specifiers can be\nomitted, so ``\'{} {}\'`` is equivalent to ``\'{0} {1}\'``.\n\nSome simple format string examples:\n\n "First, thou shalt count to {0}" # References first positional argument\n "Bring me a {}" # Implicitly references the first positional argument\n "From {} to {}" # Same as "From {0} to {1}"\n "My quest is {name}" # References keyword argument \'name\'\n "Weight in tons {0.weight}" # \'weight\' attribute of first positional arg\n "Units destroyed: {players[0]}" # First element of keyword argument \'players\'.\n\nThe *conversion* field causes a type coercion before formatting.\nNormally, the job of formatting a value is done by the\n``__format__()`` method of the value itself. However, in some cases\nit is desirable to force a type to be formatted as a string,\noverriding its own definition of formatting. By converting the value\nto a string before calling ``__format__()``, the normal formatting\nlogic is bypassed.\n\nThree conversion flags are currently supported: ``\'!s\'`` which calls\n``str()`` on the value, ``\'!r\'`` which calls ``repr()`` and ``\'!a\'``\nwhich calls ``ascii()``.\n\nSome examples:\n\n "Harold\'s a clever {0!s}" # Calls str() on the argument first\n "Bring out the holy {name!r}" # Calls repr() on the argument first\n "More {!a}" # Calls ascii() on the argument first\n\nThe *format_spec* field contains a specification of how the value\nshould be presented, including such details as field width, alignment,\npadding, decimal precision and so on. Each value type can define its\nown "formatting mini-language" or interpretation of the *format_spec*.\n\nMost built-in types support a common formatting mini-language, which\nis described in the next section.\n\nA *format_spec* field can also include nested replacement fields\nwithin it. These nested replacement fields can contain only a field\nname; conversion flags and format specifications are not allowed. The\nreplacement fields within the format_spec are substituted before the\n*format_spec* string is interpreted. This allows the formatting of a\nvalue to be dynamically specified.\n\nSee the *Format examples* section for some examples.\n\n\nFormat Specification Mini-Language\n==================================\n\n"Format specifications" are used within replacement fields contained\nwithin a format string to define how individual values are presented\n(see *Format String Syntax*). They can also be passed directly to the\nbuilt-in ``format()`` function. Each formattable type may define how\nthe format specification is to be interpreted.\n\nMost built-in types implement the following options for format\nspecifications, although some of the formatting options are only\nsupported by the numeric types.\n\nA general convention is that an empty format string (``""``) produces\nthe same result as if you had called ``str()`` on the value. A non-\nempty format string typically modifies the result.\n\nThe general form of a *standard format specifier* is:\n\n format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]\n fill ::= \n align ::= "<" | ">" | "=" | "^"\n sign ::= "+" | "-" | " "\n width ::= integer\n precision ::= integer\n type ::= "b" | "c" | "d" | "e" | "E" | "f" | "F" | "g" | "G" | "n" | "o" | "s" | "x" | "X" | "%"\n\nThe *fill* character can be any character other than \'{\' or \'}\'. The\npresence of a fill character is signaled by the character following\nit, which must be one of the alignment options. If the second\ncharacter of *format_spec* is not a valid alignment option, then it is\nassumed that both the fill character and the alignment option are\nabsent.\n\nThe meaning of the various alignment options is as follows:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'<\'`` | Forces the field to be left-aligned within the available |\n | | space (this is the default). |\n +-----------+------------------------------------------------------------+\n | ``\'>\'`` | Forces the field to be right-aligned within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n | ``\'=\'`` | Forces the padding to be placed after the sign (if any) |\n | | but before the digits. This is used for printing fields |\n | | in the form \'+000000120\'. This alignment option is only |\n | | valid for numeric types. |\n +-----------+------------------------------------------------------------+\n | ``\'^\'`` | Forces the field to be centered within the available |\n | | space. |\n +-----------+------------------------------------------------------------+\n\nNote that unless a minimum field width is defined, the field width\nwill always be the same size as the data to fill it, so that the\nalignment option has no meaning in this case.\n\nThe *sign* option is only valid for number types, and can be one of\nthe following:\n\n +-----------+------------------------------------------------------------+\n | Option | Meaning |\n +===========+============================================================+\n | ``\'+\'`` | indicates that a sign should be used for both positive as |\n | | well as negative numbers. |\n +-----------+------------------------------------------------------------+\n | ``\'-\'`` | indicates that a sign should be used only for negative |\n | | numbers (this is the default behavior). |\n +-----------+------------------------------------------------------------+\n | space | indicates that a leading space should be used on positive |\n | | numbers, and a minus sign on negative numbers. |\n +-----------+------------------------------------------------------------+\n\nThe ``\'#\'`` option causes the "alternate form" to be used for the\nconversion. The alternate form is defined differently for different\ntypes. This option is only valid for integer, float, complex and\nDecimal types. For integers, when binary, octal, or hexadecimal output\nis used, this option adds the prefix respective ``\'0b\'``, ``\'0o\'``, or\n``\'0x\'`` to the output value. For floats, complex and Decimal the\nalternate form causes the result of the conversion to always contain a\ndecimal-point character, even if no digits follow it. Normally, a\ndecimal-point character appears in the result of these conversions\nonly if a digit follows it. In addition, for ``\'g\'`` and ``\'G\'``\nconversions, trailing zeros are not removed from the result.\n\nThe ``\',\'`` option signals the use of a comma for a thousands\nseparator. For a locale aware separator, use the ``\'n\'`` integer\npresentation type instead.\n\nChanged in version 3.1: Added the ``\',\'`` option (see also **PEP\n378**).\n\n*width* is a decimal integer defining the minimum field width. If not\nspecified, then the field width will be determined by the content.\n\nIf the *width* field is preceded by a zero (``\'0\'``) character, this\nenables zero-padding. This is equivalent to an *alignment* type of\n``\'=\'`` and a *fill* character of ``\'0\'``.\n\nThe *precision* is a decimal number indicating how many digits should\nbe displayed after the decimal point for a floating point value\nformatted with ``\'f\'`` and ``\'F\'``, or before and after the decimal\npoint for a floating point value formatted with ``\'g\'`` or ``\'G\'``.\nFor non-number types the field indicates the maximum field size - in\nother words, how many characters will be used from the field content.\nThe *precision* is not allowed for integer values.\n\nFinally, the *type* determines how the data should be presented.\n\nThe available string presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'s\'`` | String format. This is the default type for strings and |\n | | may be omitted. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'s\'``. |\n +-----------+------------------------------------------------------------+\n\nThe available integer presentation types are:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'b\'`` | Binary format. Outputs the number in base 2. |\n +-----------+------------------------------------------------------------+\n | ``\'c\'`` | Character. Converts the integer to the corresponding |\n | | unicode character before printing. |\n +-----------+------------------------------------------------------------+\n | ``\'d\'`` | Decimal Integer. Outputs the number in base 10. |\n +-----------+------------------------------------------------------------+\n | ``\'o\'`` | Octal format. Outputs the number in base 8. |\n +-----------+------------------------------------------------------------+\n | ``\'x\'`` | Hex format. Outputs the number in base 16, using lower- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'X\'`` | Hex format. Outputs the number in base 16, using upper- |\n | | case letters for the digits above 9. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'d\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | None | The same as ``\'d\'``. |\n +-----------+------------------------------------------------------------+\n\nIn addition to the above presentation types, integers can be formatted\nwith the floating point presentation types listed below (except\n``\'n\'`` and None). When doing so, ``float()`` is used to convert the\ninteger to a floating point number before formatting.\n\nThe available presentation types for floating point and decimal values\nare:\n\n +-----------+------------------------------------------------------------+\n | Type | Meaning |\n +===========+============================================================+\n | ``\'e\'`` | Exponent notation. Prints the number in scientific |\n | | notation using the letter \'e\' to indicate the exponent. |\n +-----------+------------------------------------------------------------+\n | ``\'E\'`` | Exponent notation. Same as ``\'e\'`` except it uses an upper |\n | | case \'E\' as the separator character. |\n +-----------+------------------------------------------------------------+\n | ``\'f\'`` | Fixed point. Displays the number as a fixed-point number. |\n +-----------+------------------------------------------------------------+\n | ``\'F\'`` | Fixed point. Same as ``\'f\'``, but converts ``nan`` to |\n | | ``NAN`` and ``inf`` to ``INF``. |\n +-----------+------------------------------------------------------------+\n | ``\'g\'`` | General format. For a given precision ``p >= 1``, this |\n | | rounds the number to ``p`` significant digits and then |\n | | formats the result in either fixed-point format or in |\n | | scientific notation, depending on its magnitude. The |\n | | precise rules are as follows: suppose that the result |\n | | formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1`` would have exponent ``exp``. Then if ``-4 <= exp |\n | | < p``, the number is formatted with presentation type |\n | | ``\'f\'`` and precision ``p-1-exp``. Otherwise, the number |\n | | is formatted with presentation type ``\'e\'`` and precision |\n | | ``p-1``. In both cases insignificant trailing zeros are |\n | | removed from the significand, and the decimal point is |\n | | also removed if there are no remaining digits following |\n | | it. Positive and negative infinity, positive and negative |\n | | zero, and nans, are formatted as ``inf``, ``-inf``, ``0``, |\n | | ``-0`` and ``nan`` respectively, regardless of the |\n | | precision. A precision of ``0`` is treated as equivalent |\n | | to a precision of ``1``. |\n +-----------+------------------------------------------------------------+\n | ``\'G\'`` | General format. Same as ``\'g\'`` except switches to ``\'E\'`` |\n | | if the number gets too large. The representations of |\n | | infinity and NaN are uppercased, too. |\n +-----------+------------------------------------------------------------+\n | ``\'n\'`` | Number. This is the same as ``\'g\'``, except that it uses |\n | | the current locale setting to insert the appropriate |\n | | number separator characters. |\n +-----------+------------------------------------------------------------+\n | ``\'%\'`` | Percentage. Multiplies the number by 100 and displays in |\n | | fixed (``\'f\'``) format, followed by a percent sign. |\n +-----------+------------------------------------------------------------+\n | None | Similar to ``\'g\'``, except with at least one digit past |\n | | the decimal point and a default precision of 12. This is |\n | | intended to match ``str()``, except you can add the other |\n | | format modifiers. |\n +-----------+------------------------------------------------------------+\n\n\nFormat examples\n===============\n\nThis section contains examples of the new format syntax and comparison\nwith the old ``%``-formatting.\n\nIn most of the cases the syntax is similar to the old\n``%``-formatting, with the addition of the ``{}`` and with ``:`` used\ninstead of ``%``. For example, ``\'%03.2f\'`` can be translated to\n``\'{:03.2f}\'``.\n\nThe new format syntax also supports new and different options, shown\nin the follow examples.\n\nAccessing arguments by position:\n\n >>> \'{0}, {1}, {2}\'.format(\'a\', \'b\', \'c\')\n \'a, b, c\'\n >>> \'{}, {}, {}\'.format(\'a\', \'b\', \'c\') # 3.1+ only\n \'a, b, c\'\n >>> \'{2}, {1}, {0}\'.format(\'a\', \'b\', \'c\')\n \'c, b, a\'\n >>> \'{2}, {1}, {0}\'.format(*\'abc\') # unpacking argument sequence\n \'c, b, a\'\n >>> \'{0}{1}{0}\'.format(\'abra\', \'cad\') # arguments\' indices can be repeated\n \'abracadabra\'\n\nAccessing arguments by name:\n\n >>> \'Coordinates: {latitude}, {longitude}\'.format(latitude=\'37.24N\', longitude=\'-115.81W\')\n \'Coordinates: 37.24N, -115.81W\'\n >>> coord = {\'latitude\': \'37.24N\', \'longitude\': \'-115.81W\'}\n >>> \'Coordinates: {latitude}, {longitude}\'.format(**coord)\n \'Coordinates: 37.24N, -115.81W\'\n\nAccessing arguments\' attributes:\n\n >>> c = 3-5j\n >>> (\'The complex number {0} is formed from the real part {0.real} \'\n ... \'and the imaginary part {0.imag}.\').format(c)\n \'The complex number (3-5j) is formed from the real part 3.0 and the imaginary part -5.0.\'\n >>> class Point:\n ... def __init__(self, x, y):\n ... self.x, self.y = x, y\n ... def __str__(self):\n ... return \'Point({self.x}, {self.y})\'.format(self=self)\n ...\n >>> str(Point(4, 2))\n \'Point(4, 2)\'\n\nAccessing arguments\' items:\n\n >>> coord = (3, 5)\n >>> \'X: {0[0]}; Y: {0[1]}\'.format(coord)\n \'X: 3; Y: 5\'\n\nReplacing ``%s`` and ``%r``:\n\n >>> "repr() shows quotes: {!r}; str() doesn\'t: {!s}".format(\'test1\', \'test2\')\n "repr() shows quotes: \'test1\'; str() doesn\'t: test2"\n\nAligning the text and specifying a width:\n\n >>> \'{:<30}\'.format(\'left aligned\')\n \'left aligned \'\n >>> \'{:>30}\'.format(\'right aligned\')\n \' right aligned\'\n >>> \'{:^30}\'.format(\'centered\')\n \' centered \'\n >>> \'{:*^30}\'.format(\'centered\') # use \'*\' as a fill char\n \'***********centered***********\'\n\nReplacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign:\n\n >>> \'{:+f}; {:+f}\'.format(3.14, -3.14) # show it always\n \'+3.140000; -3.140000\'\n >>> \'{: f}; {: f}\'.format(3.14, -3.14) # show a space for positive numbers\n \' 3.140000; -3.140000\'\n >>> \'{:-f}; {:-f}\'.format(3.14, -3.14) # show only the minus -- same as \'{:f}; {:f}\'\n \'3.140000; -3.140000\'\n\nReplacing ``%x`` and ``%o`` and converting the value to different\nbases:\n\n >>> # format also supports binary numbers\n >>> "int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}".format(42)\n \'int: 42; hex: 2a; oct: 52; bin: 101010\'\n >>> # with 0x, 0o, or 0b as prefix:\n >>> "int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}".format(42)\n \'int: 42; hex: 0x2a; oct: 0o52; bin: 0b101010\'\n\nUsing the comma as a thousands separator:\n\n >>> \'{:,}\'.format(1234567890)\n \'1,234,567,890\'\n\nExpressing a percentage:\n\n >>> points = 19\n >>> total = 22\n >>> \'Correct answers: {:.2%}.\'.format(points/total)\n \'Correct answers: 86.36%\'\n\nUsing type-specific formatting:\n\n >>> import datetime\n >>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)\n >>> \'{:%Y-%m-%d %H:%M:%S}\'.format(d)\n \'2010-07-04 12:15:58\'\n\nNesting arguments and more complex examples:\n\n >>> for align, text in zip(\'<^>\', [\'left\', \'center\', \'right\']):\n ... \'{0:{align}{fill}16}\'.format(text, fill=align, align=align)\n ...\n \'left<<<<<<<<<<<<\'\n \'^^^^^center^^^^^\'\n \'>>>>>>>>>>>right\'\n >>>\n >>> octets = [192, 168, 0, 1]\n >>> \'{:02X}{:02X}{:02X}{:02X}\'.format(*octets)\n \'C0A80001\'\n >>> int(_, 16)\n 3232235521\n >>>\n >>> width = 5\n >>> for num in range(5,12):\n ... for base in \'dXob\':\n ... print(\'{0:{width}{base}}\'.format(num, base=base, width=width), end=\' \')\n ... print()\n ...\n 5 5 5 101\n 6 6 6 110\n 7 7 7 111\n 8 8 10 1000\n 9 9 11 1001\n 10 A 12 1010\n 11 B 13 1011\n', 'function': '\nFunction definitions\n********************\n\nA function definition defines a user-defined function object (see\nsection *The standard type hierarchy*):\n\n funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")" ["->" expression] ":" suite\n decorators ::= decorator+\n decorator ::= "@" dotted_name ["(" [argument_list [","]] ")"] NEWLINE\n dotted_name ::= identifier ("." identifier)*\n parameter_list ::= (defparameter ",")*\n ( "*" [parameter] ("," defparameter)*\n [, "**" parameter]\n | "**" parameter\n | defparameter [","] )\n parameter ::= identifier [":" expression]\n defparameter ::= parameter ["=" expression]\n funcname ::= identifier\n\nA function definition is an executable statement. Its execution binds\nthe function name in the current local namespace to a function object\n(a wrapper around the executable code for the function). This\nfunction object contains a reference to the current global namespace\nas the global namespace to be used when the function is called.\n\nThe function definition does not execute the function body; this gets\nexecuted only when the function is called. [3]\n\nA function definition may be wrapped by one or more *decorator*\nexpressions. Decorator expressions are evaluated when the function is\ndefined, in the scope that contains the function definition. The\nresult must be a callable, which is invoked with the function object\nas the only argument. The returned value is bound to the function name\ninstead of the function object. Multiple decorators are applied in\nnested fashion. For example, the following code\n\n @f1(arg)\n @f2\n def func(): pass\n\nis equivalent to\n\n def func(): pass\n func = f1(arg)(f2(func))\n\nWhen one or more parameters have the form *parameter* ``=``\n*expression*, the function is said to have "default parameter values."\nFor a parameter with a default value, the corresponding argument may\nbe omitted from a call, in which case the parameter\'s default value is\nsubstituted. If a parameter has a default value, all following\nparameters up until the "``*``" must also have a default value ---\nthis is a syntactic restriction that is not expressed by the grammar.\n\n**Default parameter values are evaluated when the function definition\nis executed.** This means that the expression is evaluated once, when\nthe function is defined, and that that same "pre-computed" value is\nused for each call. This is especially important to understand when a\ndefault parameter is a mutable object, such as a list or a dictionary:\nif the function modifies the object (e.g. by appending an item to a\nlist), the default value is in effect modified. This is generally not\nwhat was intended. A way around this is to use ``None`` as the\ndefault, and explicitly test for it in the body of the function, e.g.:\n\n def whats_on_the_telly(penguin=None):\n if penguin is None:\n penguin = []\n penguin.append("property of the zoo")\n return penguin\n\nFunction call semantics are described in more detail in section\n*Calls*. A function call always assigns values to all parameters\nmentioned in the parameter list, either from position arguments, from\nkeyword arguments, or from default values. If the form\n"``*identifier``" is present, it is initialized to a tuple receiving\nany excess positional parameters, defaulting to the empty tuple. If\nthe form "``**identifier``" is present, it is initialized to a new\ndictionary receiving any excess keyword arguments, defaulting to a new\nempty dictionary. Parameters after "``*``" or "``*identifier``" are\nkeyword-only parameters and may only be passed used keyword arguments.\n\nParameters may have annotations of the form "``: expression``"\nfollowing the parameter name. Any parameter may have an annotation\neven those of the form ``*identifier`` or ``**identifier``. Functions\nmay have "return" annotation of the form "``-> expression``" after the\nparameter list. These annotations can be any valid Python expression\nand are evaluated when the function definition is executed.\nAnnotations may be evaluated in a different order than they appear in\nthe source code. The presence of annotations does not change the\nsemantics of a function. The annotation values are available as\nvalues of a dictionary keyed by the parameters\' names in the\n``__annotations__`` attribute of the function object.\n\nIt is also possible to create anonymous functions (functions not bound\nto a name), for immediate use in expressions. This uses lambda forms,\ndescribed in section *Lambdas*. Note that the lambda form is merely a\nshorthand for a simplified function definition; a function defined in\na "``def``" statement can be passed around or assigned to another name\njust like a function defined by a lambda form. The "``def``" form is\nactually more powerful since it allows the execution of multiple\nstatements and annotations.\n\n**Programmer\'s note:** Functions are first-class objects. A "``def``"\nform executed inside a function definition defines a local function\nthat can be returned or passed around. Free variables used in the\nnested function can access the local variables of the function\ncontaining the def. See section *Naming and binding* for details.\n', 'global': '\nThe ``global`` statement\n************************\n\n global_stmt ::= "global" identifier ("," identifier)*\n\nThe ``global`` statement is a declaration which holds for the entire\ncurrent code block. It means that the listed identifiers are to be\ninterpreted as globals. It would be impossible to assign to a global\nvariable without ``global``, although free variables may refer to\nglobals without being declared global.\n\nNames listed in a ``global`` statement must not be used in the same\ncode block textually preceding that ``global`` statement.\n\nNames listed in a ``global`` statement must not be defined as formal\nparameters or in a ``for`` loop control target, ``class`` definition,\nfunction definition, or ``import`` statement.\n\n**CPython implementation detail:** The current implementation does not\nenforce the latter two restrictions, but programs should not abuse\nthis freedom, as future implementations may enforce them or silently\nchange the meaning of the program.\n\n**Programmer\'s note:** the ``global`` is a directive to the parser.\nIt applies only to code parsed at the same time as the ``global``\nstatement. In particular, a ``global`` statement contained in a string\nor code object supplied to the built-in ``exec()`` function does not\naffect the code block *containing* the function call, and code\ncontained in such a string is unaffected by ``global`` statements in\nthe code containing the function call. The same applies to the\n``eval()`` and ``compile()`` functions.\n', 'id-classes': '\nReserved classes of identifiers\n*******************************\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of ``__*__`` names, in any context, that does\n not follow explicitly documented use, is subject to breakage\n without warning.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', 'identifiers': '\nIdentifiers and keywords\n************************\n\nIdentifiers (also referred to as *names*) are described by the\nfollowing lexical definitions.\n\nThe syntax of identifiers in Python is based on the Unicode standard\nannex UAX-31, with elaboration and changes as defined below; see also\n**PEP 3131** for further details.\n\nWithin the ASCII range (U+0001..U+007F), the valid characters for\nidentifiers are the same as in Python 2.x: the uppercase and lowercase\nletters ``A`` through ``Z``, the underscore ``_`` and, except for the\nfirst character, the digits ``0`` through ``9``.\n\nPython 3.0 introduces additional characters from outside the ASCII\nrange (see **PEP 3131**). For these characters, the classification\nuses the version of the Unicode Character Database as included in the\n``unicodedata`` module.\n\nIdentifiers are unlimited in length. Case is significant.\n\n identifier ::= id_start id_continue*\n id_start ::= \n id_continue ::= \n\nThe Unicode category codes mentioned above stand for:\n\n* *Lu* - uppercase letters\n\n* *Ll* - lowercase letters\n\n* *Lt* - titlecase letters\n\n* *Lm* - modifier letters\n\n* *Lo* - other letters\n\n* *Nl* - letter numbers\n\n* *Mn* - nonspacing marks\n\n* *Mc* - spacing combining marks\n\n* *Nd* - decimal numbers\n\n* *Pc* - connector punctuations\n\nAll identifiers are converted into the normal form NFC while parsing;\ncomparison of identifiers is based on NFC.\n\nA non-normative HTML file listing all valid identifier characters for\nUnicode 4.1 can be found at http://www.dcl.hpi.uni-\npotsdam.de/home/loewis/table-3131.html.\n\n\nKeywords\n========\n\nThe following identifiers are used as reserved words, or *keywords* of\nthe language, and cannot be used as ordinary identifiers. They must\nbe spelled exactly as written here:\n\n False class finally is return\n None continue for lambda try\n True def from nonlocal while\n and del global not with\n as elif if or yield\n assert else import pass\n break except in raise\n\n\nReserved classes of identifiers\n===============================\n\nCertain classes of identifiers (besides keywords) have special\nmeanings. These classes are identified by the patterns of leading and\ntrailing underscore characters:\n\n``_*``\n Not imported by ``from module import *``. The special identifier\n ``_`` is used in the interactive interpreter to store the result of\n the last evaluation; it is stored in the ``builtins`` module. When\n not in interactive mode, ``_`` has no special meaning and is not\n defined. See section *The import statement*.\n\n Note: The name ``_`` is often used in conjunction with\n internationalization; refer to the documentation for the\n ``gettext`` module for more information on this convention.\n\n``__*__``\n System-defined names. These names are defined by the interpreter\n and its implementation (including the standard library). Current\n system names are discussed in the *Special method names* section\n and elsewhere. More will likely be defined in future versions of\n Python. *Any* use of ``__*__`` names, in any context, that does\n not follow explicitly documented use, is subject to breakage\n without warning.\n\n``__*``\n Class-private names. Names in this category, when used within the\n context of a class definition, are re-written to use a mangled form\n to help avoid name clashes between "private" attributes of base and\n derived classes. See section *Identifiers (Names)*.\n', 'if': '\nThe ``if`` statement\n********************\n\nThe ``if`` statement is used for conditional execution:\n\n if_stmt ::= "if" expression ":" suite\n ( "elif" expression ":" suite )*\n ["else" ":" suite]\n\nIt selects exactly one of the suites by evaluating the expressions one\nby one until one is found to be true (see section *Boolean operations*\nfor the definition of true and false); then that suite is executed\n(and no other part of the ``if`` statement is executed or evaluated).\nIf all expressions are false, the suite of the ``else`` clause, if\npresent, is executed.\n', 'imaginary': '\nImaginary literals\n******************\n\nImaginary literals are described by the following lexical definitions:\n\n imagnumber ::= (floatnumber | intpart) ("j" | "J")\n\nAn imaginary literal yields a complex number with a real part of 0.0.\nComplex numbers are represented as a pair of floating point numbers\nand have the same restrictions on their range. To create a complex\nnumber with a nonzero real part, add a floating point number to it,\ne.g., ``(3+4j)``. Some examples of imaginary literals:\n\n 3.14j 10.j 10j .001j 1e100j 3.14e-10j\n', - 'import': '\nThe ``import`` statement\n************************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nImport statements are executed in two steps: (1) find a module, and\ninitialize it if necessary; (2) define a name or names in the local\nnamespace (of the scope where the ``import`` statement occurs). The\nstatement comes in two forms differing on whether it uses the ``from``\nkeyword. The first form (without ``from``) repeats these steps for\neach identifier in the list. The form with ``from`` performs step (1)\nonce, and then performs step (2) repeatedly. For a reference\nimplementation of step (1), see the ``importlib`` module.\n\nTo understand how step (1) occurs, one must first understand how\nPython handles hierarchical naming of modules. To help organize\nmodules and provide a hierarchy in naming, Python has a concept of\npackages. A package can contain other packages and modules while\nmodules cannot contain other modules or packages. From a file system\nperspective, packages are directories and modules are files. The\noriginal specification for packages is still available to read,\nalthough minor details have changed since the writing of that\ndocument.\n\nOnce the name of the module is known (unless otherwise specified, the\nterm "module" will refer to both packages and modules), searching for\nthe module or package can begin. The first place checked is\n``sys.modules``, the cache of all modules that have been imported\npreviously. If the module is found there then it is used in step (2)\nof import unless ``None`` is found in ``sys.modules``, in which case\n``ImportError`` is raised.\n\nIf the module is not found in the cache, then ``sys.meta_path`` is\nsearched (the specification for ``sys.meta_path`` can be found in\n**PEP 302**). The object is a list of *finder* objects which are\nqueried in order as to whether they know how to load the module by\ncalling their ``find_module()`` method with the name of the module. If\nthe module happens to be contained within a package (as denoted by the\nexistence of a dot in the name), then a second argument to\n``find_module()`` is given as the value of the ``__path__`` attribute\nfrom the parent package (everything up to the last dot in the name of\nthe module being imported). If a finder can find the module it returns\na *loader* (discussed later) or returns ``None``.\n\nIf none of the finders on ``sys.meta_path`` are able to find the\nmodule then some implicitly defined finders are queried.\nImplementations of Python vary in what implicit meta path finders are\ndefined. The one they all do define, though, is one that handles\n``sys.path_hooks``, ``sys.path_importer_cache``, and ``sys.path``.\n\nThe implicit finder searches for the requested module in the "paths"\nspecified in one of two places ("paths" do not have to be file system\npaths). If the module being imported is supposed to be contained\nwithin a package then the second argument passed to ``find_module()``,\n``__path__`` on the parent package, is used as the source of paths. If\nthe module is not contained in a package then ``sys.path`` is used as\nthe source of paths.\n\nOnce the source of paths is chosen it is iterated over to find a\nfinder that can handle that path. The dict at\n``sys.path_importer_cache`` caches finders for paths and is checked\nfor a finder. If the path does not have a finder cached then\n``sys.path_hooks`` is searched by calling each object in the list with\na single argument of the path, returning a finder or raises\n``ImportError``. If a finder is returned then it is cached in\n``sys.path_importer_cache`` and then used for that path entry. If no\nfinder can be found but the path exists then a value of ``None`` is\nstored in ``sys.path_importer_cache`` to signify that an implicit,\nfile-based finder that handles modules stored as individual files\nshould be used for that path. If the path does not exist then a finder\nwhich always returns ``None`` is placed in the cache for the path.\n\nIf no finder can find the module then ``ImportError`` is raised.\nOtherwise some finder returned a loader whose ``load_module()`` method\nis called with the name of the module to load (see **PEP 302** for the\noriginal definition of loaders). A loader has several responsibilities\nto perform on a module it loads. First, if the module already exists\nin ``sys.modules`` (a possibility if the loader is called outside of\nthe import machinery) then it is to use that module for initialization\nand not a new module. But if the module does not exist in\n``sys.modules`` then it is to be added to that dict before\ninitialization begins. If an error occurs during loading of the module\nand it was added to ``sys.modules`` it is to be removed from the dict.\nIf an error occurs but the module was already in ``sys.modules`` it is\nleft in the dict.\n\nThe loader must set several attributes on the module. ``__name__`` is\nto be set to the name of the module. ``__file__`` is to be the "path"\nto the file unless the module is built-in (and thus listed in\n``sys.builtin_module_names``) in which case the attribute is not set.\nIf what is being imported is a package then ``__path__`` is to be set\nto a list of paths to be searched when looking for modules and\npackages contained within the package being imported. ``__package__``\nis optional but should be set to the name of package that contains the\nmodule or package (the empty string is used for module not contained\nin a package). ``__loader__`` is also optional but should be set to\nthe loader object that is loading the module.\n\nIf an error occurs during loading then the loader raises\n``ImportError`` if some other exception is not already being\npropagated. Otherwise the loader returns the module that was loaded\nand initialized.\n\nWhen step (1) finishes without raising an exception, step (2) can\nbegin.\n\nThe first form of ``import`` statement binds the module name in the\nlocal namespace to the module object, and then goes on to import the\nnext identifier, if any. If the module name is followed by ``as``,\nthe name following ``as`` is used as the local name for the module.\n\nThe ``from`` form does not bind the module name: it goes through the\nlist of identifiers, looks each one of them up in the module found in\nstep (1), and binds the name in the local namespace to the object thus\nfound. As with the first form of ``import``, an alternate local name\ncan be supplied by specifying "``as`` localname". If a name is not\nfound, ``ImportError`` is raised. If the list of identifiers is\nreplaced by a star (``\'*\'``), all public names defined in the module\nare bound in the local namespace of the ``import`` statement..\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named ``__all__``; if defined, it\nmust be a sequence of strings which are names defined or imported by\nthat module. The names given in ``__all__`` are all considered public\nand are required to exist. If ``__all__`` is not defined, the set of\npublic names includes all names found in the module\'s namespace which\ndo not begin with an underscore character (``\'_\'``). ``__all__``\nshould contain the entire public API. It is intended to avoid\naccidentally exporting items that are not part of the API (such as\nlibrary modules which were imported and used within the module).\n\nThe ``from`` form with ``*`` may only occur in a module scope. The\nwild card form of import --- ``import *`` --- is only allowed at the\nmodule level. Attempting to use it in class or function definitions\nwill raise a ``SyntaxError``.\n\nWhen specifying what module to import you do not have to specify the\nabsolute name of the module. When a module or package is contained\nwithin another package it is possible to make a relative import within\nthe same top package without having to mention the package name. By\nusing leading dots in the specified module or package after ``from``\nyou can specify how high to traverse up the current package hierarchy\nwithout specifying exact names. One leading dot means the current\npackage where the module making the import exists. Two dots means up\none package level. Three dots is up two levels, etc. So if you execute\n``from . import mod`` from a module in the ``pkg`` package then you\nwill end up importing ``pkg.mod``. If you execute ``from ..subpkg2\nimport mod`` from within ``pkg.subpkg1`` you will import\n``pkg.subpkg2.mod``. The specification for relative imports is\ncontained within **PEP 328**.\n\n``importlib.import_module()`` is provided to support applications that\ndetermine which modules need to be loaded dynamically.\n\n\nFuture statements\n=================\n\nA *future statement* is a directive to the compiler that a particular\nmodule should be compiled using syntax or semantics that will be\navailable in a specified future release of Python. The future\nstatement is intended to ease migration to future versions of Python\nthat introduce incompatible changes to the language. It allows use of\nthe new features on a per-module basis before the release in which the\nfeature becomes standard.\n\n future_statement ::= "from" "__future__" "import" feature ["as" name]\n ("," feature ["as" name])*\n | "from" "__future__" "import" "(" feature ["as" name]\n ("," feature ["as" name])* [","] ")"\n feature ::= identifier\n name ::= identifier\n\nA future statement must appear near the top of the module. The only\nlines that can appear before a future statement are:\n\n* the module docstring (if any),\n\n* comments,\n\n* blank lines, and\n\n* other future statements.\n\nThe features recognized by Python 3.0 are ``absolute_import``,\n``division``, ``generators``, ``unicode_literals``,\n``print_function``, ``nested_scopes`` and ``with_statement``. They\nare all redundant because they are always enabled, and only kept for\nbackwards compatibility.\n\nA future statement is recognized and treated specially at compile\ntime: Changes to the semantics of core constructs are often\nimplemented by generating different code. It may even be the case\nthat a new feature introduces new incompatible syntax (such as a new\nreserved word), in which case the compiler may need to parse the\nmodule differently. Such decisions cannot be pushed off until\nruntime.\n\nFor any given release, the compiler knows which feature names have\nbeen defined, and raises a compile-time error if a future statement\ncontains a feature not known to it.\n\nThe direct runtime semantics are the same as for any import statement:\nthere is a standard module ``__future__``, described later, and it\nwill be imported in the usual way at the time the future statement is\nexecuted.\n\nThe interesting runtime semantics depend on the specific feature\nenabled by the future statement.\n\nNote that there is nothing special about the statement:\n\n import __future__ [as name]\n\nThat is not a future statement; it\'s an ordinary import statement with\nno special semantics or syntax restrictions.\n\nCode compiled by calls to the built-in functions ``exec()`` and\n``compile()`` that occur in a module ``M`` containing a future\nstatement will, by default, use the new syntax or semantics associated\nwith the future statement. This can be controlled by optional\narguments to ``compile()`` --- see the documentation of that function\nfor details.\n\nA future statement typed at an interactive interpreter prompt will\ntake effect for the rest of the interpreter session. If an\ninterpreter is started with the *-i* option, is passed a script name\nto execute, and the script includes a future statement, it will be in\neffect in the interactive session started after the script is\nexecuted.\n\nSee also:\n\n **PEP 236** - Back to the __future__\n The original proposal for the __future__ mechanism.\n', + 'import': '\nThe ``import`` statement\n************************\n\n import_stmt ::= "import" module ["as" name] ( "," module ["as" name] )*\n | "from" relative_module "import" identifier ["as" name]\n ( "," identifier ["as" name] )*\n | "from" relative_module "import" "(" identifier ["as" name]\n ( "," identifier ["as" name] )* [","] ")"\n | "from" module "import" "*"\n module ::= (identifier ".")* identifier\n relative_module ::= "."* module | "."+\n name ::= identifier\n\nImport statements are executed in two steps: (1) find a module, and\ninitialize it if necessary; (2) define a name or names in the local\nnamespace (of the scope where the ``import`` statement occurs). The\nstatement comes in two forms differing on whether it uses the ``from``\nkeyword. The first form (without ``from``) repeats these steps for\neach identifier in the list. The form with ``from`` performs step (1)\nonce, and then performs step (2) repeatedly. For a reference\nimplementation of step (1), see the ``importlib`` module.\n\nTo understand how step (1) occurs, one must first understand how\nPython handles hierarchical naming of modules. To help organize\nmodules and provide a hierarchy in naming, Python has a concept of\npackages. A package can contain other packages and modules while\nmodules cannot contain other modules or packages. From a file system\nperspective, packages are directories and modules are files. The\noriginal specification for packages is still available to read,\nalthough minor details have changed since the writing of that\ndocument.\n\nOnce the name of the module is known (unless otherwise specified, the\nterm "module" will refer to both packages and modules), searching for\nthe module or package can begin. The first place checked is\n``sys.modules``, the cache of all modules that have been imported\npreviously. If the module is found there then it is used in step (2)\nof import unless ``None`` is found in ``sys.modules``, in which case\n``ImportError`` is raised.\n\nIf the module is not found in the cache, then ``sys.meta_path`` is\nsearched (the specification for ``sys.meta_path`` can be found in\n**PEP 302**). The object is a list of *finder* objects which are\nqueried in order as to whether they know how to load the module by\ncalling their ``find_module()`` method with the name of the module. If\nthe module happens to be contained within a package (as denoted by the\nexistence of a dot in the name), then a second argument to\n``find_module()`` is given as the value of the ``__path__`` attribute\nfrom the parent package (everything up to the last dot in the name of\nthe module being imported). If a finder can find the module it returns\na *loader* (discussed later) or returns ``None``.\n\nIf none of the finders on ``sys.meta_path`` are able to find the\nmodule then some implicitly defined finders are queried.\nImplementations of Python vary in what implicit meta path finders are\ndefined. The one they all do define, though, is one that handles\n``sys.path_hooks``, ``sys.path_importer_cache``, and ``sys.path``.\n\nThe implicit finder searches for the requested module in the "paths"\nspecified in one of two places ("paths" do not have to be file system\npaths). If the module being imported is supposed to be contained\nwithin a package then the second argument passed to ``find_module()``,\n``__path__`` on the parent package, is used as the source of paths. If\nthe module is not contained in a package then ``sys.path`` is used as\nthe source of paths.\n\nOnce the source of paths is chosen it is iterated over to find a\nfinder that can handle that path. The dict at\n``sys.path_importer_cache`` caches finders for paths and is checked\nfor a finder. If the path does not have a finder cached then\n``sys.path_hooks`` is searched by calling each object in the list with\na single argument of the path, returning a finder or raises\n``ImportError``. If a finder is returned then it is cached in\n``sys.path_importer_cache`` and then used for that path entry. If no\nfinder can be found but the path exists then a value of ``None`` is\nstored in ``sys.path_importer_cache`` to signify that an implicit,\nfile-based finder that handles modules stored as individual files\nshould be used for that path. If the path does not exist then a finder\nwhich always returns ``None`` is placed in the cache for the path.\n\nIf no finder can find the module then ``ImportError`` is raised.\nOtherwise some finder returned a loader whose ``load_module()`` method\nis called with the name of the module to load (see **PEP 302** for the\noriginal definition of loaders). A loader has several responsibilities\nto perform on a module it loads. First, if the module already exists\nin ``sys.modules`` (a possibility if the loader is called outside of\nthe import machinery) then it is to use that module for initialization\nand not a new module. But if the module does not exist in\n``sys.modules`` then it is to be added to that dict before\ninitialization begins. If an error occurs during loading of the module\nand it was added to ``sys.modules`` it is to be removed from the dict.\nIf an error occurs but the module was already in ``sys.modules`` it is\nleft in the dict.\n\nThe loader must set several attributes on the module. ``__name__`` is\nto be set to the name of the module. ``__file__`` is to be the "path"\nto the file unless the module is built-in (and thus listed in\n``sys.builtin_module_names``) in which case the attribute is not set.\nIf what is being imported is a package then ``__path__`` is to be set\nto a list of paths to be searched when looking for modules and\npackages contained within the package being imported. ``__package__``\nis optional but should be set to the name of package that contains the\nmodule or package (the empty string is used for module not contained\nin a package). ``__loader__`` is also optional but should be set to\nthe loader object that is loading the module.\n\nIf an error occurs during loading then the loader raises\n``ImportError`` if some other exception is not already being\npropagated. Otherwise the loader returns the module that was loaded\nand initialized.\n\nWhen step (1) finishes without raising an exception, step (2) can\nbegin.\n\nThe first form of ``import`` statement binds the module name in the\nlocal namespace to the module object, and then goes on to import the\nnext identifier, if any. If the module name is followed by ``as``,\nthe name following ``as`` is used as the local name for the module.\n\nThe ``from`` form does not bind the module name: it goes through the\nlist of identifiers, looks each one of them up in the module found in\nstep (1), and binds the name in the local namespace to the object thus\nfound. As with the first form of ``import``, an alternate local name\ncan be supplied by specifying "``as`` localname". If a name is not\nfound, ``ImportError`` is raised. If the list of identifiers is\nreplaced by a star (``\'*\'``), all public names defined in the module\nare bound in the local namespace of the ``import`` statement.\n\nThe *public names* defined by a module are determined by checking the\nmodule\'s namespace for a variable named ``__all__``; if defined, it\nmust be a sequence of strings which are names defined or imported by\nthat module. The names given in ``__all__`` are all considered public\nand are required to exist. If ``__all__`` is not defined, the set of\npublic names includes all names found in the module\'s namespace which\ndo not begin with an underscore character (``\'_\'``). ``__all__``\nshould contain the entire public API. It is intended to avoid\naccidentally exporting items that are not part of the API (such as\nlibrary modules which were imported and used within the module).\n\nThe ``from`` form with ``*`` may only occur in a module scope. The\nwild card form of import --- ``import *`` --- is only allowed at the\nmodule level. Attempting to use it in class or function definitions\nwill raise a ``SyntaxError``.\n\nWhen specifying what module to import you do not have to specify the\nabsolute name of the module. When a module or package is contained\nwithin another package it is possible to make a relative import within\nthe same top package without having to mention the package name. By\nusing leading dots in the specified module or package after ``from``\nyou can specify how high to traverse up the current package hierarchy\nwithout specifying exact names. One leading dot means the current\npackage where the module making the import exists. Two dots means up\none package level. Three dots is up two levels, etc. So if you execute\n``from . import mod`` from a module in the ``pkg`` package then you\nwill end up importing ``pkg.mod``. If you execute ``from ..subpkg2\nimport mod`` from within ``pkg.subpkg1`` you will import\n``pkg.subpkg2.mod``. The specification for relative imports is\ncontained within **PEP 328**.\n\n``importlib.import_module()`` is provided to support applications that\ndetermine which modules need to be loaded dynamically.\n\n\nFuture statements\n=================\n\nA *future statement* is a directive to the compiler that a particular\nmodule should be compiled using syntax or semantics that will be\navailable in a specified future release of Python. The future\nstatement is intended to ease migration to future versions of Python\nthat introduce incompatible changes to the language. It allows use of\nthe new features on a per-module basis before the release in which the\nfeature becomes standard.\n\n future_statement ::= "from" "__future__" "import" feature ["as" name]\n ("," feature ["as" name])*\n | "from" "__future__" "import" "(" feature ["as" name]\n ("," feature ["as" name])* [","] ")"\n feature ::= identifier\n name ::= identifier\n\nA future statement must appear near the top of the module. The only\nlines that can appear before a future statement are:\n\n* the module docstring (if any),\n\n* comments,\n\n* blank lines, and\n\n* other future statements.\n\nThe features recognized by Python 3.0 are ``absolute_import``,\n``division``, ``generators``, ``unicode_literals``,\n``print_function``, ``nested_scopes`` and ``with_statement``. They\nare all redundant because they are always enabled, and only kept for\nbackwards compatibility.\n\nA future statement is recognized and treated specially at compile\ntime: Changes to the semantics of core constructs are often\nimplemented by generating different code. It may even be the case\nthat a new feature introduces new incompatible syntax (such as a new\nreserved word), in which case the compiler may need to parse the\nmodule differently. Such decisions cannot be pushed off until\nruntime.\n\nFor any given release, the compiler knows which feature names have\nbeen defined, and raises a compile-time error if a future statement\ncontains a feature not known to it.\n\nThe direct runtime semantics are the same as for any import statement:\nthere is a standard module ``__future__``, described later, and it\nwill be imported in the usual way at the time the future statement is\nexecuted.\n\nThe interesting runtime semantics depend on the specific feature\nenabled by the future statement.\n\nNote that there is nothing special about the statement:\n\n import __future__ [as name]\n\nThat is not a future statement; it\'s an ordinary import statement with\nno special semantics or syntax restrictions.\n\nCode compiled by calls to the built-in functions ``exec()`` and\n``compile()`` that occur in a module ``M`` containing a future\nstatement will, by default, use the new syntax or semantics associated\nwith the future statement. This can be controlled by optional\narguments to ``compile()`` --- see the documentation of that function\nfor details.\n\nA future statement typed at an interactive interpreter prompt will\ntake effect for the rest of the interpreter session. If an\ninterpreter is started with the *-i* option, is passed a script name\nto execute, and the script includes a future statement, it will be in\neffect in the interactive session started after the script is\nexecuted.\n\nSee also:\n\n **PEP 236** - Back to the __future__\n The original proposal for the __future__ mechanism.\n', 'in': '\nComparisons\n***********\n\nUnlike C, all comparison operations in Python have the same priority,\nwhich is lower than that of any arithmetic, shifting or bitwise\noperation. Also unlike C, expressions like ``a < b < c`` have the\ninterpretation that is conventional in mathematics:\n\n comparison ::= or_expr ( comp_operator or_expr )*\n comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="\n | "is" ["not"] | ["not"] "in"\n\nComparisons yield boolean values: ``True`` or ``False``.\n\nComparisons can be chained arbitrarily, e.g., ``x < y <= z`` is\nequivalent to ``x < y and y <= z``, except that ``y`` is evaluated\nonly once (but in both cases ``z`` is not evaluated at all when ``x <\ny`` is found to be false).\n\nFormally, if *a*, *b*, *c*, ..., *y*, *z* are expressions and *op1*,\n*op2*, ..., *opN* are comparison operators, then ``a op1 b op2 c ... y\nopN z`` is equivalent to ``a op1 b and b op2 c and ... y opN z``,\nexcept that each expression is evaluated at most once.\n\nNote that ``a op1 b op2 c`` doesn\'t imply any kind of comparison\nbetween *a* and *c*, so that, e.g., ``x < y > z`` is perfectly legal\n(though perhaps not pretty).\n\nThe operators ``<``, ``>``, ``==``, ``>=``, ``<=``, and ``!=`` compare\nthe values of two objects. The objects need not have the same type.\nIf both are numbers, they are converted to a common type. Otherwise,\nthe ``==`` and ``!=`` operators *always* consider objects of different\ntypes to be unequal, while the ``<``, ``>``, ``>=`` and ``<=``\noperators raise a ``TypeError`` when comparing objects of different\ntypes that do not implement these operators for the given pair of\ntypes. You can control comparison behavior of objects of non-built-in\ntypes by defining rich comparison methods like ``__gt__()``, described\nin section *Basic customization*.\n\nComparison of objects of the same type depends on the type:\n\n* Numbers are compared arithmetically.\n\n* The values ``float(\'NaN\')`` and ``Decimal(\'NaN\')`` are special. The\n are identical to themselves, ``x is x`` but are not equal to\n themselves, ``x != x``. Additionally, comparing any value to a\n not-a-number value will return ``False``. For example, both ``3 <\n float(\'NaN\')`` and ``float(\'NaN\') < 3`` will return ``False``.\n\n* Bytes objects are compared lexicographically using the numeric\n values of their elements.\n\n* Strings are compared lexicographically using the numeric equivalents\n (the result of the built-in function ``ord()``) of their characters.\n [3] String and bytes object can\'t be compared!\n\n* Tuples and lists are compared lexicographically using comparison of\n corresponding elements. This means that to compare equal, each\n element must compare equal and the two sequences must be of the same\n type and have the same length.\n\n If not equal, the sequences are ordered the same as their first\n differing elements. For example, ``[1,2,x] <= [1,2,y]`` has the\n same value as ``x <= y``. If the corresponding element does not\n exist, the shorter sequence is ordered first (for example, ``[1,2] <\n [1,2,3]``).\n\n* Mappings (dictionaries) compare equal if and only if they have the\n same ``(key, value)`` pairs. Order comparisons ``(\'<\', \'<=\', \'>=\',\n \'>\')`` raise ``TypeError``.\n\n* Sets and frozensets define comparison operators to mean subset and\n superset tests. Those relations do not define total orderings (the\n two sets ``{1,2}`` and {2,3} are not equal, nor subsets of one\n another, nor supersets of one another). Accordingly, sets are not\n appropriate arguments for functions which depend on total ordering.\n For example, ``min()``, ``max()``, and ``sorted()`` produce\n undefined results given a list of sets as inputs.\n\n* Most other objects of built-in types compare unequal unless they are\n the same object; the choice whether one object is considered smaller\n or larger than another one is made arbitrarily but consistently\n within one execution of a program.\n\nComparison of objects of the differing types depends on whether either\nof the types provide explicit support for the comparison. Most\nnumeric types can be compared with one another, but comparisons of\n``float`` and ``Decimal`` are not supported to avoid the inevitable\nconfusion arising from representation issues such as ``float(\'1.1\')``\nbeing inexactly represented and therefore not exactly equal to\n``Decimal(\'1.1\')`` which is. When cross-type comparison is not\nsupported, the comparison method returns ``NotImplemented``. This can\ncreate the illusion of non-transitivity between supported cross-type\ncomparisons and unsupported comparisons. For example, ``Decimal(2) ==\n2`` and ``2 == float(2)`` but ``Decimal(2) != float(2)``.\n\nThe operators ``in`` and ``not in`` test for membership. ``x in s``\nevaluates to true if *x* is a member of *s*, and false otherwise. ``x\nnot in s`` returns the negation of ``x in s``. All built-in sequences\nand set types support this as well as dictionary, for which ``in``\ntests whether a the dictionary has a given key. For container types\nsuch as list, tuple, set, frozenset, dict, or collections.deque, the\nexpression ``x in y`` is equivalent to ``any(x is e or x == e for e in\ny)``.\n\nFor the string and bytes types, ``x in y`` is true if and only if *x*\nis a substring of *y*. An equivalent test is ``y.find(x) != -1``.\nEmpty strings are always considered to be a substring of any other\nstring, so ``"" in "abc"`` will return ``True``.\n\nFor user-defined classes which define the ``__contains__()`` method,\n``x in y`` is true if and only if ``y.__contains__(x)`` is true.\n\nFor user-defined classes which do not define ``__contains__()`` but do\ndefine ``__iter__()``, ``x in y`` is true if some value ``z`` with ``x\n== z`` is produced while iterating over ``y``. If an exception is\nraised during the iteration, it is as if ``in`` raised that exception.\n\nLastly, the old-style iteration protocol is tried: if a class defines\n``__getitem__()``, ``x in y`` is true if and only if there is a non-\nnegative integer index *i* such that ``x == y[i]``, and all lower\ninteger indices do not raise ``IndexError`` exception. (If any other\nexception is raised, it is as if ``in`` raised that exception).\n\nThe operator ``not in`` is defined to have the inverse true value of\n``in``.\n\nThe operators ``is`` and ``is not`` test for object identity: ``x is\ny`` is true if and only if *x* and *y* are the same object. ``x is\nnot y`` yields the inverse truth value. [4]\n', 'integers': '\nInteger literals\n****************\n\nInteger literals are described by the following lexical definitions:\n\n integer ::= decimalinteger | octinteger | hexinteger | bininteger\n decimalinteger ::= nonzerodigit digit* | "0"+\n nonzerodigit ::= "1"..."9"\n digit ::= "0"..."9"\n octinteger ::= "0" ("o" | "O") octdigit+\n hexinteger ::= "0" ("x" | "X") hexdigit+\n bininteger ::= "0" ("b" | "B") bindigit+\n octdigit ::= "0"..."7"\n hexdigit ::= digit | "a"..."f" | "A"..."F"\n bindigit ::= "0" | "1"\n\nThere is no limit for the length of integer literals apart from what\ncan be stored in available memory.\n\nNote that leading zeros in a non-zero decimal number are not allowed.\nThis is for disambiguation with C-style octal literals, which Python\nused before version 3.0.\n\nSome examples of integer literals:\n\n 7 2147483647 0o177 0b100110111\n 3 79228162514264337593543950336 0o377 0x100000000\n 79228162514264337593543950336 0xdeadbeef\n', 'lambda': '\nLambdas\n*******\n\n lambda_form ::= "lambda" [parameter_list]: expression\n lambda_form_nocond ::= "lambda" [parameter_list]: expression_nocond\n\nLambda forms (lambda expressions) have the same syntactic position as\nexpressions. They are a shorthand to create anonymous functions; the\nexpression ``lambda arguments: expression`` yields a function object.\nThe unnamed object behaves like a function object defined with\n\n def (arguments):\n return expression\n\nSee section *Function definitions* for the syntax of parameter lists.\nNote that functions created with lambda forms cannot contain\nstatements or annotations.\n', @@ -50,7 +50,7 @@ 'numbers': "\nNumeric literals\n****************\n\nThere are three types of numeric literals: integers, floating point\nnumbers, and imaginary numbers. There are no complex literals\n(complex numbers can be formed by adding a real number and an\nimaginary number).\n\nNote that numeric literals do not include a sign; a phrase like ``-1``\nis actually an expression composed of the unary operator '``-``' and\nthe literal ``1``.\n", 'numeric-types': "\nEmulating numeric types\n***********************\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand's type is a subclass of the left operand's\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand's\n non-reflected method. This behavior allows subclasses to\n override their ancestors' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n", 'objects': '\nObjects, values and types\n*************************\n\n*Objects* are Python\'s abstraction for data. All data in a Python\nprogram is represented by objects or by relations between objects. (In\na sense, and in conformance to Von Neumann\'s model of a "stored\nprogram computer," code is also represented by objects.)\n\nEvery object has an identity, a type and a value. An object\'s\n*identity* never changes once it has been created; you may think of it\nas the object\'s address in memory. The \'``is``\' operator compares the\nidentity of two objects; the ``id()`` function returns an integer\nrepresenting its identity (currently implemented as its address). An\nobject\'s *type* is also unchangeable. [1] An object\'s type determines\nthe operations that the object supports (e.g., "does it have a\nlength?") and also defines the possible values for objects of that\ntype. The ``type()`` function returns an object\'s type (which is an\nobject itself). The *value* of some objects can change. Objects\nwhose value can change are said to be *mutable*; objects whose value\nis unchangeable once they are created are called *immutable*. (The\nvalue of an immutable container object that contains a reference to a\nmutable object can change when the latter\'s value is changed; however\nthe container is still considered immutable, because the collection of\nobjects it contains cannot be changed. So, immutability is not\nstrictly the same as having an unchangeable value, it is more subtle.)\nAn object\'s mutability is determined by its type; for instance,\nnumbers, strings and tuples are immutable, while dictionaries and\nlists are mutable.\n\nObjects are never explicitly destroyed; however, when they become\nunreachable they may be garbage-collected. An implementation is\nallowed to postpone garbage collection or omit it altogether --- it is\na matter of implementation quality how garbage collection is\nimplemented, as long as no objects are collected that are still\nreachable.\n\n**CPython implementation detail:** CPython currently uses a reference-\ncounting scheme with (optional) delayed detection of cyclically linked\ngarbage, which collects most objects as soon as they become\nunreachable, but is not guaranteed to collect garbage containing\ncircular references. See the documentation of the ``gc`` module for\ninformation on controlling the collection of cyclic garbage. Other\nimplementations act differently and CPython may change.\n\nNote that the use of the implementation\'s tracing or debugging\nfacilities may keep objects alive that would normally be collectable.\nAlso note that catching an exception with a \'``try``...``except``\'\nstatement may keep objects alive.\n\nSome objects contain references to "external" resources such as open\nfiles or windows. It is understood that these resources are freed\nwhen the object is garbage-collected, but since garbage collection is\nnot guaranteed to happen, such objects also provide an explicit way to\nrelease the external resource, usually a ``close()`` method. Programs\nare strongly recommended to explicitly close such objects. The\n\'``try``...``finally``\' statement and the \'``with``\' statement provide\nconvenient ways to do this.\n\nSome objects contain references to other objects; these are called\n*containers*. Examples of containers are tuples, lists and\ndictionaries. The references are part of a container\'s value. In\nmost cases, when we talk about the value of a container, we imply the\nvalues, not the identities of the contained objects; however, when we\ntalk about the mutability of a container, only the identities of the\nimmediately contained objects are implied. So, if an immutable\ncontainer (like a tuple) contains a reference to a mutable object, its\nvalue changes if that mutable object is changed.\n\nTypes affect almost all aspects of object behavior. Even the\nimportance of object identity is affected in some sense: for immutable\ntypes, operations that compute new values may actually return a\nreference to any existing object with the same type and value, while\nfor mutable objects this is not allowed. E.g., after ``a = 1; b =\n1``, ``a`` and ``b`` may or may not refer to the same object with the\nvalue one, depending on the implementation, but after ``c = []; d =\n[]``, ``c`` and ``d`` are guaranteed to refer to two different,\nunique, newly created empty lists. (Note that ``c = d = []`` assigns\nthe same object to both ``c`` and ``d``.)\n', - 'operator-summary': '\nSummary\n*******\n\nThe following table summarizes the operator precedences in Python,\nfrom lowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for comparisons, including\ntests, which all have the same precedence and chain from left to right\n--- see section *Comparisons* --- and exponentiation, which groups\nfrom right to left).\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| ``lambda`` | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| ``if`` -- ``else`` | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| ``or`` | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| ``and`` | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| ``not`` *x* | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``in``, ``not`` ``in``, ``is``, ``is not``, | Comparisons, including membership |\n| ``<``, ``<=``, ``>``, ``>=``, ``!=``, ``==`` | tests and identity tests, |\n+-------------------------------------------------+---------------------------------------+\n| ``|`` | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| ``^`` | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| ``&`` | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| ``<<``, ``>>`` | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| ``+``, ``-`` | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| ``*``, ``/``, ``//``, ``%`` | Multiplication, division, remainder |\n| | [5] |\n+-------------------------------------------------+---------------------------------------+\n| ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``**`` | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| ``x[index]``, ``x[index:index]``, | Subscription, slicing, call, |\n| ``x(arguments...)``, ``x.attribute`` | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| ``(expressions...)``, ``[expressions...]``, | Binding or tuple display, list |\n| ``{key:datum...}``, | display, dictionary display, |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While ``abs(x%y) < abs(y)`` is true mathematically, for floats it\n may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that ``-1e-100 % 1e100`` have the same\n sign as ``1e100``, the computed result is ``-1e-100 + 1e100``,\n which is numerically exactly equal to ``1e100``. Function\n ``fmod()`` in the ``math`` module returns a result whose sign\n matches the sign of the first argument instead, and so returns\n ``-1e-100`` in this case. Which approach is more appropriate\n depends on the application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for ``x//y`` to be one larger than ``(x-x%y)//y`` due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that ``divmod(x,y)[0] * y + x % y`` be very\n close to ``x``.\n\n[3] While comparisons between strings make sense at the byte level,\n they may be counter-intuitive to users. For example, the strings\n ``"\\u00C7"`` and ``"\\u0327\\u0043"`` compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using ``unicodedata.normalize()``.\n\n[4] Due to automatic garbage-collection, free lists, and the dynamic\n nature of descriptors, you may notice seemingly unusual behaviour\n in certain uses of the ``is`` operator, like those involving\n comparisons between instance methods, or constants. Check their\n documentation for more info.\n\n[5] The ``%`` is also used for string formatting; the same precedence\n applies.\n\n[6] The power operator ``**`` binds less tightly than an arithmetic or\n bitwise unary operator on its right, that is, ``2**-1`` is\n ``0.5``.\n', + 'operator-summary': '\nSummary\n*******\n\nThe following table summarizes the operator precedences in Python,\nfrom lowest precedence (least binding) to highest precedence (most\nbinding). Operators in the same box have the same precedence. Unless\nthe syntax is explicitly given, operators are binary. Operators in\nthe same box group left to right (except for comparisons, including\ntests, which all have the same precedence and chain from left to right\n--- see section *Comparisons* --- and exponentiation, which groups\nfrom right to left).\n\n+-------------------------------------------------+---------------------------------------+\n| Operator | Description |\n+=================================================+=======================================+\n| ``lambda`` | Lambda expression |\n+-------------------------------------------------+---------------------------------------+\n| ``if`` -- ``else`` | Conditional expression |\n+-------------------------------------------------+---------------------------------------+\n| ``or`` | Boolean OR |\n+-------------------------------------------------+---------------------------------------+\n| ``and`` | Boolean AND |\n+-------------------------------------------------+---------------------------------------+\n| ``not`` *x* | Boolean NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``in``, ``not`` ``in``, ``is``, ``is not``, | Comparisons, including membership |\n| ``<``, ``<=``, ``>``, ``>=``, ``!=``, ``==`` | tests and identity tests, |\n+-------------------------------------------------+---------------------------------------+\n| ``|`` | Bitwise OR |\n+-------------------------------------------------+---------------------------------------+\n| ``^`` | Bitwise XOR |\n+-------------------------------------------------+---------------------------------------+\n| ``&`` | Bitwise AND |\n+-------------------------------------------------+---------------------------------------+\n| ``<<``, ``>>`` | Shifts |\n+-------------------------------------------------+---------------------------------------+\n| ``+``, ``-`` | Addition and subtraction |\n+-------------------------------------------------+---------------------------------------+\n| ``*``, ``/``, ``//``, ``%`` | Multiplication, division, remainder |\n| | [5] |\n+-------------------------------------------------+---------------------------------------+\n| ``+x``, ``-x``, ``~x`` | Positive, negative, bitwise NOT |\n+-------------------------------------------------+---------------------------------------+\n| ``**`` | Exponentiation [6] |\n+-------------------------------------------------+---------------------------------------+\n| ``x[index]``, ``x[index:index]``, | Subscription, slicing, call, |\n| ``x(arguments...)``, ``x.attribute`` | attribute reference |\n+-------------------------------------------------+---------------------------------------+\n| ``(expressions...)``, ``[expressions...]``, | Binding or tuple display, list |\n| ``{key:datum...}``, ``{expressions...}`` | display, dictionary display, set |\n| | display |\n+-------------------------------------------------+---------------------------------------+\n\n-[ Footnotes ]-\n\n[1] While ``abs(x%y) < abs(y)`` is true mathematically, for floats it\n may not be true numerically due to roundoff. For example, and\n assuming a platform on which a Python float is an IEEE 754 double-\n precision number, in order that ``-1e-100 % 1e100`` have the same\n sign as ``1e100``, the computed result is ``-1e-100 + 1e100``,\n which is numerically exactly equal to ``1e100``. The function\n ``math.fmod()`` returns a result whose sign matches the sign of\n the first argument instead, and so returns ``-1e-100`` in this\n case. Which approach is more appropriate depends on the\n application.\n\n[2] If x is very close to an exact integer multiple of y, it\'s\n possible for ``x//y`` to be one larger than ``(x-x%y)//y`` due to\n rounding. In such cases, Python returns the latter result, in\n order to preserve that ``divmod(x,y)[0] * y + x % y`` be very\n close to ``x``.\n\n[3] While comparisons between strings make sense at the byte level,\n they may be counter-intuitive to users. For example, the strings\n ``"\\u00C7"`` and ``"\\u0327\\u0043"`` compare differently, even\n though they both represent the same unicode character (LATIN\n CAPITAL LETTER C WITH CEDILLA). To compare strings in a human\n recognizable way, compare using ``unicodedata.normalize()``.\n\n[4] Due to automatic garbage-collection, free lists, and the dynamic\n nature of descriptors, you may notice seemingly unusual behaviour\n in certain uses of the ``is`` operator, like those involving\n comparisons between instance methods, or constants. Check their\n documentation for more info.\n\n[5] The ``%`` operator is also used for string formatting; the same\n precedence applies.\n\n[6] The power operator ``**`` binds less tightly than an arithmetic or\n bitwise unary operator on its right, that is, ``2**-1`` is\n ``0.5``.\n', 'pass': '\nThe ``pass`` statement\n**********************\n\n pass_stmt ::= "pass"\n\n``pass`` is a null operation --- when it is executed, nothing happens.\nIt is useful as a placeholder when a statement is required\nsyntactically, but no code needs to be executed, for example:\n\n def f(arg): pass # a function that does nothing (yet)\n\n class C: pass # a class with no methods (yet)\n', 'power': '\nThe power operator\n******************\n\nThe power operator binds more tightly than unary operators on its\nleft; it binds less tightly than unary operators on its right. The\nsyntax is:\n\n power ::= primary ["**" u_expr]\n\nThus, in an unparenthesized sequence of power and unary operators, the\noperators are evaluated from right to left (this does not constrain\nthe evaluation order for the operands): ``-1**2`` results in ``-1``.\n\nThe power operator has the same semantics as the built-in ``pow()``\nfunction, when called with two arguments: it yields its left argument\nraised to the power of its right argument. The numeric arguments are\nfirst converted to a common type, and the result is of that type.\n\nFor int operands, the result has the same type as the operands unless\nthe second argument is negative; in that case, all arguments are\nconverted to float and a float result is delivered. For example,\n``10**2`` returns ``100``, but ``10**-2`` returns ``0.01``.\n\nRaising ``0.0`` to a negative power results in a\n``ZeroDivisionError``. Raising a negative number to a fractional power\nresults in a ``complex`` number. (In earlier versions it raised a\n``ValueError``.)\n', 'raise': '\nThe ``raise`` statement\n***********************\n\n raise_stmt ::= "raise" [expression ["from" expression]]\n\nIf no expressions are present, ``raise`` re-raises the last exception\nthat was active in the current scope. If no exception is active in\nthe current scope, a ``TypeError`` exception is raised indicating that\nthis is an error (if running under IDLE, a ``queue.Empty`` exception\nis raised instead).\n\nOtherwise, ``raise`` evaluates the first expression as the exception\nobject. It must be either a subclass or an instance of\n``BaseException``. If it is a class, the exception instance will be\nobtained when needed by instantiating the class with no arguments.\n\nThe *type* of the exception is the exception instance\'s class, the\n*value* is the instance itself.\n\nA traceback object is normally created automatically when an exception\nis raised and attached to it as the ``__traceback__`` attribute, which\nis writable. You can create an exception and set your own traceback in\none step using the ``with_traceback()`` exception method (which\nreturns the same exception instance, with its traceback set to its\nargument), like so:\n\n raise Exception("foo occurred").with_traceback(tracebackobj)\n\nThe ``from`` clause is used for exception chaining: if given, the\nsecond *expression* must be another exception class or instance, which\nwill then be attached to the raised exception as the ``__cause__``\nattribute (which is writable). If the raised exception is not\nhandled, both exceptions will be printed:\n\n >>> try:\n ... print(1 / 0)\n ... except Exception as exc:\n ... raise RuntimeError("Something bad happened") from exc\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n The above exception was the direct cause of the following exception:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nA similar mechanism works implicitly if an exception is raised inside\nan exception handler: the previous exception is then attached as the\nnew exception\'s ``__context__`` attribute:\n\n >>> try:\n ... print(1 / 0)\n ... except:\n ... raise RuntimeError("Something bad happened")\n ...\n Traceback (most recent call last):\n File "", line 2, in \n ZeroDivisionError: int division or modulo by zero\n\n During handling of the above exception, another exception occurred:\n\n Traceback (most recent call last):\n File "", line 4, in \n RuntimeError: Something bad happened\n\nAdditional information on exceptions can be found in section\n*Exceptions*, and information about handling exceptions is in section\n*The try statement*.\n', @@ -59,7 +59,7 @@ 'shifting': '\nShifting operations\n*******************\n\nThe shifting operations have lower priority than the arithmetic\noperations:\n\n shift_expr ::= a_expr | shift_expr ( "<<" | ">>" ) a_expr\n\nThese operators accept integers as arguments. They shift the first\nargument to the left or right by the number of bits given by the\nsecond argument.\n\nA right shift by *n* bits is defined as division by ``pow(2,n)``. A\nleft shift by *n* bits is defined as multiplication with ``pow(2,n)``.\n\nNote: In the current implementation, the right-hand operand is required to\n be at most ``sys.maxsize``. If the right-hand operand is larger\n than ``sys.maxsize`` an ``OverflowError`` exception is raised.\n', 'slicings': '\nSlicings\n********\n\nA slicing selects a range of items in a sequence object (e.g., a\nstring, tuple or list). Slicings may be used as expressions or as\ntargets in assignment or ``del`` statements. The syntax for a\nslicing:\n\n slicing ::= primary "[" slice_list "]"\n slice_list ::= slice_item ("," slice_item)* [","]\n slice_item ::= expression | proper_slice\n proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]\n lower_bound ::= expression\n upper_bound ::= expression\n stride ::= expression\n\nThere is ambiguity in the formal syntax here: anything that looks like\nan expression list also looks like a slice list, so any subscription\ncan be interpreted as a slicing. Rather than further complicating the\nsyntax, this is disambiguated by defining that in this case the\ninterpretation as a subscription takes priority over the\ninterpretation as a slicing (this is the case if the slice list\ncontains no proper slice).\n\nThe semantics for a slicing are as follows. The primary must evaluate\nto a mapping object, and it is indexed (using the same\n``__getitem__()`` method as normal subscription) with a key that is\nconstructed from the slice list, as follows. If the slice list\ncontains at least one comma, the key is a tuple containing the\nconversion of the slice items; otherwise, the conversion of the lone\nslice item is the key. The conversion of a slice item that is an\nexpression is that expression. The conversion of a proper slice is a\nslice object (see section *The standard type hierarchy*) whose\n``start``, ``stop`` and ``step`` attributes are the values of the\nexpressions given as lower bound, upper bound and stride,\nrespectively, substituting ``None`` for missing expressions.\n', 'specialattrs': "\nSpecial Attributes\n******************\n\nThe implementation adds a few special read-only attributes to several\nobject types, where they are relevant. Some of these are not reported\nby the ``dir()`` built-in function.\n\nobject.__dict__\n\n A dictionary or other mapping object used to store an object's\n (writable) attributes.\n\ninstance.__class__\n\n The class to which a class instance belongs.\n\nclass.__bases__\n\n The tuple of base classes of a class object.\n\nclass.__name__\n\n The name of the class or type.\n\nThe following attributes are only supported by *new-style class*es.\n\nclass.__mro__\n\n This attribute is a tuple of classes that are considered when\n looking for base classes during method resolution.\n\nclass.mro()\n\n This method can be overridden by a metaclass to customize the\n method resolution order for its instances. It is called at class\n instantiation, and its result is stored in ``__mro__``.\n\nclass.__subclasses__()\n\n Each new-style class keeps a list of weak references to its\n immediate subclasses. This method returns a list of all those\n references still alive. Example:\n\n >>> int.__subclasses__()\n []\n\n-[ Footnotes ]-\n\n[1] Additional information on these special methods may be found in\n the Python Reference Manual (*Basic customization*).\n\n[2] As a consequence, the list ``[1, 2]`` is considered equal to\n ``[1.0, 2.0]``, and similarly for tuples.\n\n[3] They must have since the parser can't tell the type of the\n operands.\n\n[4] To format only a tuple you should therefore provide a singleton\n tuple whose only element is the tuple to be formatted.\n", - 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in the\nclass dictionary of another class, known as the *owner* class. In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, A)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is passed with the bases, it\n is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C(object):\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', + 'specialnames': '\nSpecial method names\n********************\n\nA class can implement certain operations that are invoked by special\nsyntax (such as arithmetic operations or subscripting and slicing) by\ndefining methods with special names. This is Python\'s approach to\n*operator overloading*, allowing classes to define their own behavior\nwith respect to language operators. For instance, if a class defines\na method named ``__getitem__()``, and ``x`` is an instance of this\nclass, then ``x[i]`` is roughly equivalent to ``type(x).__getitem__(x,\ni)``. Except where mentioned, attempts to execute an operation raise\nan exception when no appropriate method is defined (typically\n``AttributeError`` or ``TypeError``).\n\nWhen implementing a class that emulates any built-in type, it is\nimportant that the emulation only be implemented to the degree that it\nmakes sense for the object being modelled. For example, some\nsequences may work well with retrieval of individual elements, but\nextracting a slice may not make sense. (One example of this is the\n``NodeList`` interface in the W3C\'s Document Object Model.)\n\n\nBasic customization\n===================\n\nobject.__new__(cls[, ...])\n\n Called to create a new instance of class *cls*. ``__new__()`` is a\n static method (special-cased so you need not declare it as such)\n that takes the class of which an instance was requested as its\n first argument. The remaining arguments are those passed to the\n object constructor expression (the call to the class). The return\n value of ``__new__()`` should be the new object instance (usually\n an instance of *cls*).\n\n Typical implementations create a new instance of the class by\n invoking the superclass\'s ``__new__()`` method using\n ``super(currentclass, cls).__new__(cls[, ...])`` with appropriate\n arguments and then modifying the newly-created instance as\n necessary before returning it.\n\n If ``__new__()`` returns an instance of *cls*, then the new\n instance\'s ``__init__()`` method will be invoked like\n ``__init__(self[, ...])``, where *self* is the new instance and the\n remaining arguments are the same as were passed to ``__new__()``.\n\n If ``__new__()`` does not return an instance of *cls*, then the new\n instance\'s ``__init__()`` method will not be invoked.\n\n ``__new__()`` is intended mainly to allow subclasses of immutable\n types (like int, str, or tuple) to customize instance creation. It\n is also commonly overridden in custom metaclasses in order to\n customize class creation.\n\nobject.__init__(self[, ...])\n\n Called when the instance is created. The arguments are those\n passed to the class constructor expression. If a base class has an\n ``__init__()`` method, the derived class\'s ``__init__()`` method,\n if any, must explicitly call it to ensure proper initialization of\n the base class part of the instance; for example:\n ``BaseClass.__init__(self, [args...])``. As a special constraint\n on constructors, no value may be returned; doing so will cause a\n ``TypeError`` to be raised at runtime.\n\nobject.__del__(self)\n\n Called when the instance is about to be destroyed. This is also\n called a destructor. If a base class has a ``__del__()`` method,\n the derived class\'s ``__del__()`` method, if any, must explicitly\n call it to ensure proper deletion of the base class part of the\n instance. Note that it is possible (though not recommended!) for\n the ``__del__()`` method to postpone destruction of the instance by\n creating a new reference to it. It may then be called at a later\n time when this new reference is deleted. It is not guaranteed that\n ``__del__()`` methods are called for objects that still exist when\n the interpreter exits.\n\n Note: ``del x`` doesn\'t directly call ``x.__del__()`` --- the former\n decrements the reference count for ``x`` by one, and the latter\n is only called when ``x``\'s reference count reaches zero. Some\n common situations that may prevent the reference count of an\n object from going to zero include: circular references between\n objects (e.g., a doubly-linked list or a tree data structure with\n parent and child pointers); a reference to the object on the\n stack frame of a function that caught an exception (the traceback\n stored in ``sys.exc_info()[2]`` keeps the stack frame alive); or\n a reference to the object on the stack frame that raised an\n unhandled exception in interactive mode (the traceback stored in\n ``sys.last_traceback`` keeps the stack frame alive). The first\n situation can only be remedied by explicitly breaking the cycles;\n the latter two situations can be resolved by storing ``None`` in\n ``sys.last_traceback``. Circular references which are garbage are\n detected when the option cycle detector is enabled (it\'s on by\n default), but can only be cleaned up if there are no Python-\n level ``__del__()`` methods involved. Refer to the documentation\n for the ``gc`` module for more information about how\n ``__del__()`` methods are handled by the cycle detector,\n particularly the description of the ``garbage`` value.\n\n Warning: Due to the precarious circumstances under which ``__del__()``\n methods are invoked, exceptions that occur during their execution\n are ignored, and a warning is printed to ``sys.stderr`` instead.\n Also, when ``__del__()`` is invoked in response to a module being\n deleted (e.g., when execution of the program is done), other\n globals referenced by the ``__del__()`` method may already have\n been deleted or in the process of being torn down (e.g. the\n import machinery shutting down). For this reason, ``__del__()``\n methods should do the absolute minimum needed to maintain\n external invariants. Starting with version 1.5, Python\n guarantees that globals whose name begins with a single\n underscore are deleted from their module before other globals are\n deleted; if no other references to such globals exist, this may\n help in assuring that imported modules are still available at the\n time when the ``__del__()`` method is called.\n\nobject.__repr__(self)\n\n Called by the ``repr()`` built-in function to compute the\n "official" string representation of an object. If at all possible,\n this should look like a valid Python expression that could be used\n to recreate an object with the same value (given an appropriate\n environment). If this is not possible, a string of the form\n ``<...some useful description...>`` should be returned. The return\n value must be a string object. If a class defines ``__repr__()``\n but not ``__str__()``, then ``__repr__()`` is also used when an\n "informal" string representation of instances of that class is\n required.\n\n This is typically used for debugging, so it is important that the\n representation is information-rich and unambiguous.\n\nobject.__str__(self)\n\n Called by the ``str()`` built-in function and by the ``print()``\n function to compute the "informal" string representation of an\n object. This differs from ``__repr__()`` in that it does not have\n to be a valid Python expression: a more convenient or concise\n representation may be used instead. The return value must be a\n string object.\n\nobject.__format__(self, format_spec)\n\n Called by the ``format()`` built-in function (and by extension, the\n ``format()`` method of class ``str``) to produce a "formatted"\n string representation of an object. The ``format_spec`` argument is\n a string that contains a description of the formatting options\n desired. The interpretation of the ``format_spec`` argument is up\n to the type implementing ``__format__()``, however most classes\n will either delegate formatting to one of the built-in types, or\n use a similar formatting option syntax.\n\n See *Format Specification Mini-Language* for a description of the\n standard formatting syntax.\n\n The return value must be a string object.\n\nobject.__lt__(self, other)\nobject.__le__(self, other)\nobject.__eq__(self, other)\nobject.__ne__(self, other)\nobject.__gt__(self, other)\nobject.__ge__(self, other)\n\n These are the so-called "rich comparison" methods. The\n correspondence between operator symbols and method names is as\n follows: ``xy`` calls ``x.__gt__(y)``, and ``x>=y`` calls\n ``x.__ge__(y)``.\n\n A rich comparison method may return the singleton\n ``NotImplemented`` if it does not implement the operation for a\n given pair of arguments. By convention, ``False`` and ``True`` are\n returned for a successful comparison. However, these methods can\n return any value, so if the comparison operator is used in a\n Boolean context (e.g., in the condition of an ``if`` statement),\n Python will call ``bool()`` on the value to determine if the result\n is true or false.\n\n There are no implied relationships among the comparison operators.\n The truth of ``x==y`` does not imply that ``x!=y`` is false.\n Accordingly, when defining ``__eq__()``, one should also define\n ``__ne__()`` so that the operators will behave as expected. See\n the paragraph on ``__hash__()`` for some important notes on\n creating *hashable* objects which support custom comparison\n operations and are usable as dictionary keys.\n\n There are no swapped-argument versions of these methods (to be used\n when the left argument does not support the operation but the right\n argument does); rather, ``__lt__()`` and ``__gt__()`` are each\n other\'s reflection, ``__le__()`` and ``__ge__()`` are each other\'s\n reflection, and ``__eq__()`` and ``__ne__()`` are their own\n reflection.\n\n Arguments to rich comparison methods are never coerced.\n\n To automatically generate ordering operations from a single root\n operation, see ``functools.total_ordering()``.\n\nobject.__hash__(self)\n\n Called by built-in function ``hash()`` and for operations on\n members of hashed collections including ``set``, ``frozenset``, and\n ``dict``. ``__hash__()`` should return an integer. The only\n required property is that objects which compare equal have the same\n hash value; it is advised to somehow mix together (e.g. using\n exclusive or) the hash values for the components of the object that\n also play a part in comparison of objects.\n\n If a class does not define an ``__eq__()`` method it should not\n define a ``__hash__()`` operation either; if it defines\n ``__eq__()`` but not ``__hash__()``, its instances will not be\n usable as items in hashable collections. If a class defines\n mutable objects and implements an ``__eq__()`` method, it should\n not implement ``__hash__()``, since the implementation of hashable\n collections requires that a key\'s hash value is immutable (if the\n object\'s hash value changes, it will be in the wrong hash bucket).\n\n User-defined classes have ``__eq__()`` and ``__hash__()`` methods\n by default; with them, all objects compare unequal (except with\n themselves) and ``x.__hash__()`` returns ``id(x)``.\n\n Classes which inherit a ``__hash__()`` method from a parent class\n but change the meaning of ``__eq__()`` such that the hash value\n returned is no longer appropriate (e.g. by switching to a value-\n based concept of equality instead of the default identity based\n equality) can explicitly flag themselves as being unhashable by\n setting ``__hash__ = None`` in the class definition. Doing so means\n that not only will instances of the class raise an appropriate\n ``TypeError`` when a program attempts to retrieve their hash value,\n but they will also be correctly identified as unhashable when\n checking ``isinstance(obj, collections.Hashable)`` (unlike classes\n which define their own ``__hash__()`` to explicitly raise\n ``TypeError``).\n\n If a class that overrides ``__eq__()`` needs to retain the\n implementation of ``__hash__()`` from a parent class, the\n interpreter must be told this explicitly by setting ``__hash__ =\n .__hash__``. Otherwise the inheritance of\n ``__hash__()`` will be blocked, just as if ``__hash__`` had been\n explicitly set to ``None``.\n\nobject.__bool__(self)\n\n Called to implement truth value testing and the built-in operation\n ``bool()``; should return ``False`` or ``True``. When this method\n is not defined, ``__len__()`` is called, if it is defined, and the\n object is considered true if its result is nonzero. If a class\n defines neither ``__len__()`` nor ``__bool__()``, all its instances\n are considered true.\n\n\nCustomizing attribute access\n============================\n\nThe following methods can be defined to customize the meaning of\nattribute access (use of, assignment to, or deletion of ``x.name``)\nfor class instances.\n\nobject.__getattr__(self, name)\n\n Called when an attribute lookup has not found the attribute in the\n usual places (i.e. it is not an instance attribute nor is it found\n in the class tree for ``self``). ``name`` is the attribute name.\n This method should return the (computed) attribute value or raise\n an ``AttributeError`` exception.\n\n Note that if the attribute is found through the normal mechanism,\n ``__getattr__()`` is not called. (This is an intentional asymmetry\n between ``__getattr__()`` and ``__setattr__()``.) This is done both\n for efficiency reasons and because otherwise ``__getattr__()``\n would have no way to access other attributes of the instance. Note\n that at least for instance variables, you can fake total control by\n not inserting any values in the instance attribute dictionary (but\n instead inserting them in another object). See the\n ``__getattribute__()`` method below for a way to actually get total\n control over attribute access.\n\nobject.__getattribute__(self, name)\n\n Called unconditionally to implement attribute accesses for\n instances of the class. If the class also defines\n ``__getattr__()``, the latter will not be called unless\n ``__getattribute__()`` either calls it explicitly or raises an\n ``AttributeError``. This method should return the (computed)\n attribute value or raise an ``AttributeError`` exception. In order\n to avoid infinite recursion in this method, its implementation\n should always call the base class method with the same name to\n access any attributes it needs, for example,\n ``object.__getattribute__(self, name)``.\n\n Note: This method may still be bypassed when looking up special methods\n as the result of implicit invocation via language syntax or\n built-in functions. See *Special method lookup*.\n\nobject.__setattr__(self, name, value)\n\n Called when an attribute assignment is attempted. This is called\n instead of the normal mechanism (i.e. store the value in the\n instance dictionary). *name* is the attribute name, *value* is the\n value to be assigned to it.\n\n If ``__setattr__()`` wants to assign to an instance attribute, it\n should call the base class method with the same name, for example,\n ``object.__setattr__(self, name, value)``.\n\nobject.__delattr__(self, name)\n\n Like ``__setattr__()`` but for attribute deletion instead of\n assignment. This should only be implemented if ``del obj.name`` is\n meaningful for the object.\n\nobject.__dir__(self)\n\n Called when ``dir()`` is called on the object. A list must be\n returned.\n\n\nImplementing Descriptors\n------------------------\n\nThe following methods only apply when an instance of the class\ncontaining the method (a so-called *descriptor* class) appears in the\nclass dictionary of another class, known as the *owner* class. In the\nexamples below, "the attribute" refers to the attribute whose name is\nthe key of the property in the owner class\' ``__dict__``.\n\nobject.__get__(self, instance, owner)\n\n Called to get the attribute of the owner class (class attribute\n access) or of an instance of that class (instance attribute\n access). *owner* is always the owner class, while *instance* is the\n instance that the attribute was accessed through, or ``None`` when\n the attribute is accessed through the *owner*. This method should\n return the (computed) attribute value or raise an\n ``AttributeError`` exception.\n\nobject.__set__(self, instance, value)\n\n Called to set the attribute on an instance *instance* of the owner\n class to a new value, *value*.\n\nobject.__delete__(self, instance)\n\n Called to delete the attribute on an instance *instance* of the\n owner class.\n\n\nInvoking Descriptors\n--------------------\n\nIn general, a descriptor is an object attribute with "binding\nbehavior", one whose attribute access has been overridden by methods\nin the descriptor protocol: ``__get__()``, ``__set__()``, and\n``__delete__()``. If any of those methods are defined for an object,\nit is said to be a descriptor.\n\nThe default behavior for attribute access is to get, set, or delete\nthe attribute from an object\'s dictionary. For instance, ``a.x`` has a\nlookup chain starting with ``a.__dict__[\'x\']``, then\n``type(a).__dict__[\'x\']``, and continuing through the base classes of\n``type(a)`` excluding metaclasses.\n\nHowever, if the looked-up value is an object defining one of the\ndescriptor methods, then Python may override the default behavior and\ninvoke the descriptor method instead. Where this occurs in the\nprecedence chain depends on which descriptor methods were defined and\nhow they were called.\n\nThe starting point for descriptor invocation is a binding, ``a.x``.\nHow the arguments are assembled depends on ``a``:\n\nDirect Call\n The simplest and least common call is when user code directly\n invokes a descriptor method: ``x.__get__(a)``.\n\nInstance Binding\n If binding to an object instance, ``a.x`` is transformed into the\n call: ``type(a).__dict__[\'x\'].__get__(a, type(a))``.\n\nClass Binding\n If binding to a class, ``A.x`` is transformed into the call:\n ``A.__dict__[\'x\'].__get__(None, A)``.\n\nSuper Binding\n If ``a`` is an instance of ``super``, then the binding ``super(B,\n obj).m()`` searches ``obj.__class__.__mro__`` for the base class\n ``A`` immediately preceding ``B`` and then invokes the descriptor\n with the call: ``A.__dict__[\'m\'].__get__(obj, A)``.\n\nFor instance bindings, the precedence of descriptor invocation depends\non the which descriptor methods are defined. A descriptor can define\nany combination of ``__get__()``, ``__set__()`` and ``__delete__()``.\nIf it does not define ``__get__()``, then accessing the attribute will\nreturn the descriptor object itself unless there is a value in the\nobject\'s instance dictionary. If the descriptor defines ``__set__()``\nand/or ``__delete__()``, it is a data descriptor; if it defines\nneither, it is a non-data descriptor. Normally, data descriptors\ndefine both ``__get__()`` and ``__set__()``, while non-data\ndescriptors have just the ``__get__()`` method. Data descriptors with\n``__set__()`` and ``__get__()`` defined always override a redefinition\nin an instance dictionary. In contrast, non-data descriptors can be\noverridden by instances.\n\nPython methods (including ``staticmethod()`` and ``classmethod()``)\nare implemented as non-data descriptors. Accordingly, instances can\nredefine and override methods. This allows individual instances to\nacquire behaviors that differ from other instances of the same class.\n\nThe ``property()`` function is implemented as a data descriptor.\nAccordingly, instances cannot override the behavior of a property.\n\n\n__slots__\n---------\n\nBy default, instances of classes have a dictionary for attribute\nstorage. This wastes space for objects having very few instance\nvariables. The space consumption can become acute when creating large\nnumbers of instances.\n\nThe default can be overridden by defining *__slots__* in a class\ndefinition. The *__slots__* declaration takes a sequence of instance\nvariables and reserves just enough space in each instance to hold a\nvalue for each variable. Space is saved because *__dict__* is not\ncreated for each instance.\n\nobject.__slots__\n\n This class variable can be assigned a string, iterable, or sequence\n of strings with variable names used by instances. If defined in a\n class, *__slots__* reserves space for the declared variables and\n prevents the automatic creation of *__dict__* and *__weakref__* for\n each instance.\n\n\nNotes on using *__slots__*\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* When inheriting from a class without *__slots__*, the *__dict__*\n attribute of that class will always be accessible, so a *__slots__*\n definition in the subclass is meaningless.\n\n* Without a *__dict__* variable, instances cannot be assigned new\n variables not listed in the *__slots__* definition. Attempts to\n assign to an unlisted variable name raises ``AttributeError``. If\n dynamic assignment of new variables is desired, then add\n ``\'__dict__\'`` to the sequence of strings in the *__slots__*\n declaration.\n\n* Without a *__weakref__* variable for each instance, classes defining\n *__slots__* do not support weak references to its instances. If weak\n reference support is needed, then add ``\'__weakref__\'`` to the\n sequence of strings in the *__slots__* declaration.\n\n* *__slots__* are implemented at the class level by creating\n descriptors (*Implementing Descriptors*) for each variable name. As\n a result, class attributes cannot be used to set default values for\n instance variables defined by *__slots__*; otherwise, the class\n attribute would overwrite the descriptor assignment.\n\n* The action of a *__slots__* declaration is limited to the class\n where it is defined. As a result, subclasses will have a *__dict__*\n unless they also define *__slots__* (which must only contain names\n of any *additional* slots).\n\n* If a class defines a slot also defined in a base class, the instance\n variable defined by the base class slot is inaccessible (except by\n retrieving its descriptor directly from the base class). This\n renders the meaning of the program undefined. In the future, a\n check may be added to prevent this.\n\n* Nonempty *__slots__* does not work for classes derived from\n "variable-length" built-in types such as ``int``, ``str`` and\n ``tuple``.\n\n* Any non-string iterable may be assigned to *__slots__*. Mappings may\n also be used; however, in the future, special meaning may be\n assigned to the values corresponding to each key.\n\n* *__class__* assignment works only if both classes have the same\n *__slots__*.\n\n\nCustomizing class creation\n==========================\n\nBy default, classes are constructed using ``type()``. A class\ndefinition is read into a separate namespace and the value of class\nname is bound to the result of ``type(name, bases, dict)``.\n\nWhen the class definition is read, if a callable ``metaclass`` keyword\nargument is passed after the bases in the class definition, the\ncallable given will be called instead of ``type()``. If other keyword\narguments are passed, they will also be passed to the metaclass. This\nallows classes or functions to be written which monitor or alter the\nclass creation process:\n\n* Modifying the class dictionary prior to the class being created.\n\n* Returning an instance of another class -- essentially performing the\n role of a factory function.\n\nThese steps will have to be performed in the metaclass\'s ``__new__()``\nmethod -- ``type.__new__()`` can then be called from this method to\ncreate a class with different properties. This example adds a new\nelement to the class dictionary before creating the class:\n\n class metacls(type):\n def __new__(mcs, name, bases, dict):\n dict[\'foo\'] = \'metacls was here\'\n return type.__new__(mcs, name, bases, dict)\n\nYou can of course also override other class methods (or add new\nmethods); for example defining a custom ``__call__()`` method in the\nmetaclass allows custom behavior when the class is called, e.g. not\nalways creating a new instance.\n\nIf the metaclass has a ``__prepare__()`` attribute (usually\nimplemented as a class or static method), it is called before the\nclass body is evaluated with the name of the class and a tuple of its\nbases for arguments. It should return an object that supports the\nmapping interface that will be used to store the namespace of the\nclass. The default is a plain dictionary. This could be used, for\nexample, to keep track of the order that class attributes are declared\nin by returning an ordered dictionary.\n\nThe appropriate metaclass is determined by the following precedence\nrules:\n\n* If the ``metaclass`` keyword argument is passed with the bases, it\n is used.\n\n* Otherwise, if there is at least one base class, its metaclass is\n used.\n\n* Otherwise, the default metaclass (``type``) is used.\n\nThe potential uses for metaclasses are boundless. Some ideas that have\nbeen explored including logging, interface checking, automatic\ndelegation, automatic property creation, proxies, frameworks, and\nautomatic resource locking/synchronization.\n\nHere is an example of a metaclass that uses an\n``collections.OrderedDict`` to remember the order that class members\nwere defined:\n\n class OrderedClass(type):\n\n @classmethod\n def __prepare__(metacls, name, bases, **kwds):\n return collections.OrderedDict()\n\n def __new__(cls, name, bases, classdict):\n result = type.__new__(cls, name, bases, dict(classdict))\n result.members = tuple(classdict)\n return result\n\n class A(metaclass=OrderedClass):\n def one(self): pass\n def two(self): pass\n def three(self): pass\n def four(self): pass\n\n >>> A.members\n (\'__module__\', \'one\', \'two\', \'three\', \'four\')\n\nWhen the class definition for *A* gets executed, the process begins\nwith calling the metaclass\'s ``__prepare__()`` method which returns an\nempty ``collections.OrderedDict``. That mapping records the methods\nand attributes of *A* as they are defined within the body of the class\nstatement. Once those definitions are executed, the ordered dictionary\nis fully populated and the metaclass\'s ``__new__()`` method gets\ninvoked. That method builds the new type and it saves the ordered\ndictionary keys in an attribute called ``members``.\n\n\nCustomizing instance and subclass checks\n========================================\n\nThe following methods are used to override the default behavior of the\n``isinstance()`` and ``issubclass()`` built-in functions.\n\nIn particular, the metaclass ``abc.ABCMeta`` implements these methods\nin order to allow the addition of Abstract Base Classes (ABCs) as\n"virtual base classes" to any class or type (including built-in\ntypes), including other ABCs.\n\nclass.__instancecheck__(self, instance)\n\n Return true if *instance* should be considered a (direct or\n indirect) instance of *class*. If defined, called to implement\n ``isinstance(instance, class)``.\n\nclass.__subclasscheck__(self, subclass)\n\n Return true if *subclass* should be considered a (direct or\n indirect) subclass of *class*. If defined, called to implement\n ``issubclass(subclass, class)``.\n\nNote that these methods are looked up on the type (metaclass) of a\nclass. They cannot be defined as class methods in the actual class.\nThis is consistent with the lookup of special methods that are called\non instances, only in this case the instance is itself a class.\n\nSee also:\n\n **PEP 3119** - Introducing Abstract Base Classes\n Includes the specification for customizing ``isinstance()`` and\n ``issubclass()`` behavior through ``__instancecheck__()`` and\n ``__subclasscheck__()``, with motivation for this functionality\n in the context of adding Abstract Base Classes (see the ``abc``\n module) to the language.\n\n\nEmulating callable objects\n==========================\n\nobject.__call__(self[, args...])\n\n Called when the instance is "called" as a function; if this method\n is defined, ``x(arg1, arg2, ...)`` is a shorthand for\n ``x.__call__(arg1, arg2, ...)``.\n\n\nEmulating container types\n=========================\n\nThe following methods can be defined to implement container objects.\nContainers usually are sequences (such as lists or tuples) or mappings\n(like dictionaries), but can represent other containers as well. The\nfirst set of methods is used either to emulate a sequence or to\nemulate a mapping; the difference is that for a sequence, the\nallowable keys should be the integers *k* for which ``0 <= k < N``\nwhere *N* is the length of the sequence, or slice objects, which\ndefine a range of items. It is also recommended that mappings provide\nthe methods ``keys()``, ``values()``, ``items()``, ``get()``,\n``clear()``, ``setdefault()``, ``pop()``, ``popitem()``, ``copy()``,\nand ``update()`` behaving similar to those for Python\'s standard\ndictionary objects. The ``collections`` module provides a\n``MutableMapping`` abstract base class to help create those methods\nfrom a base set of ``__getitem__()``, ``__setitem__()``,\n``__delitem__()``, and ``keys()``. Mutable sequences should provide\nmethods ``append()``, ``count()``, ``index()``, ``extend()``,\n``insert()``, ``pop()``, ``remove()``, ``reverse()`` and ``sort()``,\nlike Python standard list objects. Finally, sequence types should\nimplement addition (meaning concatenation) and multiplication (meaning\nrepetition) by defining the methods ``__add__()``, ``__radd__()``,\n``__iadd__()``, ``__mul__()``, ``__rmul__()`` and ``__imul__()``\ndescribed below; they should not define other numerical operators. It\nis recommended that both mappings and sequences implement the\n``__contains__()`` method to allow efficient use of the ``in``\noperator; for mappings, ``in`` should search the mapping\'s keys; for\nsequences, it should search through the values. It is further\nrecommended that both mappings and sequences implement the\n``__iter__()`` method to allow efficient iteration through the\ncontainer; for mappings, ``__iter__()`` should be the same as\n``keys()``; for sequences, it should iterate through the values.\n\nobject.__len__(self)\n\n Called to implement the built-in function ``len()``. Should return\n the length of the object, an integer ``>=`` 0. Also, an object\n that doesn\'t define a ``__bool__()`` method and whose ``__len__()``\n method returns zero is considered to be false in a Boolean context.\n\nNote: Slicing is done exclusively with the following three methods. A\n call like\n\n a[1:2] = b\n\n is translated to\n\n a[slice(1, 2, None)] = b\n\n and so forth. Missing slice items are always filled in with\n ``None``.\n\nobject.__getitem__(self, key)\n\n Called to implement evaluation of ``self[key]``. For sequence\n types, the accepted keys should be integers and slice objects.\n Note that the special interpretation of negative indexes (if the\n class wishes to emulate a sequence type) is up to the\n ``__getitem__()`` method. If *key* is of an inappropriate type,\n ``TypeError`` may be raised; if of a value outside the set of\n indexes for the sequence (after any special interpretation of\n negative values), ``IndexError`` should be raised. For mapping\n types, if *key* is missing (not in the container), ``KeyError``\n should be raised.\n\n Note: ``for`` loops expect that an ``IndexError`` will be raised for\n illegal indexes to allow proper detection of the end of the\n sequence.\n\nobject.__setitem__(self, key, value)\n\n Called to implement assignment to ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support changes to the values for keys, or if new keys\n can be added, or for sequences if elements can be replaced. The\n same exceptions should be raised for improper *key* values as for\n the ``__getitem__()`` method.\n\nobject.__delitem__(self, key)\n\n Called to implement deletion of ``self[key]``. Same note as for\n ``__getitem__()``. This should only be implemented for mappings if\n the objects support removal of keys, or for sequences if elements\n can be removed from the sequence. The same exceptions should be\n raised for improper *key* values as for the ``__getitem__()``\n method.\n\nobject.__iter__(self)\n\n This method is called when an iterator is required for a container.\n This method should return a new iterator object that can iterate\n over all the objects in the container. For mappings, it should\n iterate over the keys of the container, and should also be made\n available as the method ``keys()``.\n\n Iterator objects also need to implement this method; they are\n required to return themselves. For more information on iterator\n objects, see *Iterator Types*.\n\nobject.__reversed__(self)\n\n Called (if present) by the ``reversed()`` built-in to implement\n reverse iteration. It should return a new iterator object that\n iterates over all the objects in the container in reverse order.\n\n If the ``__reversed__()`` method is not provided, the\n ``reversed()`` built-in will fall back to using the sequence\n protocol (``__len__()`` and ``__getitem__()``). Objects that\n support the sequence protocol should only provide\n ``__reversed__()`` if they can provide an implementation that is\n more efficient than the one provided by ``reversed()``.\n\nThe membership test operators (``in`` and ``not in``) are normally\nimplemented as an iteration through a sequence. However, container\nobjects can supply the following special method with a more efficient\nimplementation, which also does not require the object be a sequence.\n\nobject.__contains__(self, item)\n\n Called to implement membership test operators. Should return true\n if *item* is in *self*, false otherwise. For mapping objects, this\n should consider the keys of the mapping rather than the values or\n the key-item pairs.\n\n For objects that don\'t define ``__contains__()``, the membership\n test first tries iteration via ``__iter__()``, then the old\n sequence iteration protocol via ``__getitem__()``, see *this\n section in the language reference*.\n\n\nEmulating numeric types\n=======================\n\nThe following methods can be defined to emulate numeric objects.\nMethods corresponding to operations that are not supported by the\nparticular kind of number implemented (e.g., bitwise operations for\nnon-integral numbers) should be left undefined.\n\nobject.__add__(self, other)\nobject.__sub__(self, other)\nobject.__mul__(self, other)\nobject.__truediv__(self, other)\nobject.__floordiv__(self, other)\nobject.__mod__(self, other)\nobject.__divmod__(self, other)\nobject.__pow__(self, other[, modulo])\nobject.__lshift__(self, other)\nobject.__rshift__(self, other)\nobject.__and__(self, other)\nobject.__xor__(self, other)\nobject.__or__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``). For instance, to evaluate the expression ``x + y``, where\n *x* is an instance of a class that has an ``__add__()`` method,\n ``x.__add__(y)`` is called. The ``__divmod__()`` method should be\n the equivalent to using ``__floordiv__()`` and ``__mod__()``; it\n should not be related to ``__truediv__()``. Note that\n ``__pow__()`` should be defined to accept an optional third\n argument if the ternary version of the built-in ``pow()`` function\n is to be supported.\n\n If one of those methods does not support the operation with the\n supplied arguments, it should return ``NotImplemented``.\n\nobject.__radd__(self, other)\nobject.__rsub__(self, other)\nobject.__rmul__(self, other)\nobject.__rtruediv__(self, other)\nobject.__rfloordiv__(self, other)\nobject.__rmod__(self, other)\nobject.__rdivmod__(self, other)\nobject.__rpow__(self, other)\nobject.__rlshift__(self, other)\nobject.__rrshift__(self, other)\nobject.__rand__(self, other)\nobject.__rxor__(self, other)\nobject.__ror__(self, other)\n\n These methods are called to implement the binary arithmetic\n operations (``+``, ``-``, ``*``, ``/``, ``//``, ``%``,\n ``divmod()``, ``pow()``, ``**``, ``<<``, ``>>``, ``&``, ``^``,\n ``|``) with reflected (swapped) operands. These functions are only\n called if the left operand does not support the corresponding\n operation and the operands are of different types. [2] For\n instance, to evaluate the expression ``x - y``, where *y* is an\n instance of a class that has an ``__rsub__()`` method,\n ``y.__rsub__(x)`` is called if ``x.__sub__(y)`` returns\n *NotImplemented*.\n\n Note that ternary ``pow()`` will not try calling ``__rpow__()``\n (the coercion rules would become too complicated).\n\n Note: If the right operand\'s type is a subclass of the left operand\'s\n type and that subclass provides the reflected method for the\n operation, this method will be called before the left operand\'s\n non-reflected method. This behavior allows subclasses to\n override their ancestors\' operations.\n\nobject.__iadd__(self, other)\nobject.__isub__(self, other)\nobject.__imul__(self, other)\nobject.__itruediv__(self, other)\nobject.__ifloordiv__(self, other)\nobject.__imod__(self, other)\nobject.__ipow__(self, other[, modulo])\nobject.__ilshift__(self, other)\nobject.__irshift__(self, other)\nobject.__iand__(self, other)\nobject.__ixor__(self, other)\nobject.__ior__(self, other)\n\n These methods are called to implement the augmented arithmetic\n assignments (``+=``, ``-=``, ``*=``, ``/=``, ``//=``, ``%=``,\n ``**=``, ``<<=``, ``>>=``, ``&=``, ``^=``, ``|=``). These methods\n should attempt to do the operation in-place (modifying *self*) and\n return the result (which could be, but does not have to be,\n *self*). If a specific method is not defined, the augmented\n assignment falls back to the normal methods. For instance, to\n execute the statement ``x += y``, where *x* is an instance of a\n class that has an ``__iadd__()`` method, ``x.__iadd__(y)`` is\n called. If *x* is an instance of a class that does not define a\n ``__iadd__()`` method, ``x.__add__(y)`` and ``y.__radd__(x)`` are\n considered, as with the evaluation of ``x + y``.\n\nobject.__neg__(self)\nobject.__pos__(self)\nobject.__abs__(self)\nobject.__invert__(self)\n\n Called to implement the unary arithmetic operations (``-``, ``+``,\n ``abs()`` and ``~``).\n\nobject.__complex__(self)\nobject.__int__(self)\nobject.__float__(self)\nobject.__round__(self[, n])\n\n Called to implement the built-in functions ``complex()``,\n ``int()``, ``float()`` and ``round()``. Should return a value of\n the appropriate type.\n\nobject.__index__(self)\n\n Called to implement ``operator.index()``. Also called whenever\n Python needs an integer object (such as in slicing, or in the\n built-in ``bin()``, ``hex()`` and ``oct()`` functions). Must return\n an integer.\n\n\nWith Statement Context Managers\n===============================\n\nA *context manager* is an object that defines the runtime context to\nbe established when executing a ``with`` statement. The context\nmanager handles the entry into, and the exit from, the desired runtime\ncontext for the execution of the block of code. Context managers are\nnormally invoked using the ``with`` statement (described in section\n*The with statement*), but can also be used by directly invoking their\nmethods.\n\nTypical uses of context managers include saving and restoring various\nkinds of global state, locking and unlocking resources, closing opened\nfiles, etc.\n\nFor more information on context managers, see *Context Manager Types*.\n\nobject.__enter__(self)\n\n Enter the runtime context related to this object. The ``with``\n statement will bind this method\'s return value to the target(s)\n specified in the ``as`` clause of the statement, if any.\n\nobject.__exit__(self, exc_type, exc_value, traceback)\n\n Exit the runtime context related to this object. The parameters\n describe the exception that caused the context to be exited. If the\n context was exited without an exception, all three arguments will\n be ``None``.\n\n If an exception is supplied, and the method wishes to suppress the\n exception (i.e., prevent it from being propagated), it should\n return a true value. Otherwise, the exception will be processed\n normally upon exit from this method.\n\n Note that ``__exit__()`` methods should not reraise the passed-in\n exception; this is the caller\'s responsibility.\n\nSee also:\n\n **PEP 0343** - The "with" statement\n The specification, background, and examples for the Python\n ``with`` statement.\n\n\nSpecial method lookup\n=====================\n\nFor custom classes, implicit invocations of special methods are only\nguaranteed to work correctly if defined on an object\'s type, not in\nthe object\'s instance dictionary. That behaviour is the reason why\nthe following code raises an exception:\n\n >>> class C:\n ... pass\n ...\n >>> c = C()\n >>> c.__len__ = lambda: 5\n >>> len(c)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: object of type \'C\' has no len()\n\nThe rationale behind this behaviour lies with a number of special\nmethods such as ``__hash__()`` and ``__repr__()`` that are implemented\nby all objects, including type objects. If the implicit lookup of\nthese methods used the conventional lookup process, they would fail\nwhen invoked on the type object itself:\n\n >>> 1 .__hash__() == hash(1)\n True\n >>> int.__hash__() == hash(int)\n Traceback (most recent call last):\n File "", line 1, in \n TypeError: descriptor \'__hash__\' of \'int\' object needs an argument\n\nIncorrectly attempting to invoke an unbound method of a class in this\nway is sometimes referred to as \'metaclass confusion\', and is avoided\nby bypassing the instance when looking up special methods:\n\n >>> type(1).__hash__(1) == hash(1)\n True\n >>> type(int).__hash__(int) == hash(int)\n True\n\nIn addition to bypassing any instance attributes in the interest of\ncorrectness, implicit special method lookup generally also bypasses\nthe ``__getattribute__()`` method even of the object\'s metaclass:\n\n >>> class Meta(type):\n ... def __getattribute__(*args):\n ... print("Metaclass getattribute invoked")\n ... return type.__getattribute__(*args)\n ...\n >>> class C(object, metaclass=Meta):\n ... def __len__(self):\n ... return 10\n ... def __getattribute__(*args):\n ... print("Class getattribute invoked")\n ... return object.__getattribute__(*args)\n ...\n >>> c = C()\n >>> c.__len__() # Explicit lookup via instance\n Class getattribute invoked\n 10\n >>> type(c).__len__(c) # Explicit lookup via type\n Metaclass getattribute invoked\n 10\n >>> len(c) # Implicit lookup\n 10\n\nBypassing the ``__getattribute__()`` machinery in this fashion\nprovides significant scope for speed optimisations within the\ninterpreter, at the cost of some flexibility in the handling of\nspecial methods (the special method *must* be set on the class object\nitself in order to be consistently invoked by the interpreter).\n\n-[ Footnotes ]-\n\n[1] It *is* possible in some cases to change an object\'s type, under\n certain controlled conditions. It generally isn\'t a good idea\n though, since it can lead to some very strange behaviour if it is\n handled incorrectly.\n\n[2] For operands of the same type, it is assumed that if the non-\n reflected method (such as ``__add__()``) fails the operation is\n not supported, which is why the reflected method is not called.\n', 'string-methods': '\nString Methods\n**************\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters include digit characters, and all characters that that\n can be used to form decimal-radix numbers, e.g. U+0660, ARABIC-\n INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise.\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n', 'strings': '\nString and Bytes literals\n*************************\n\nString literals are described by the following lexical definitions:\n\n stringliteral ::= [stringprefix](shortstring | longstring)\n stringprefix ::= "r" | "R"\n shortstring ::= "\'" shortstringitem* "\'" | \'"\' shortstringitem* \'"\'\n longstring ::= "\'\'\'" longstringitem* "\'\'\'" | \'"""\' longstringitem* \'"""\'\n shortstringitem ::= shortstringchar | stringescapeseq\n longstringitem ::= longstringchar | stringescapeseq\n shortstringchar ::= \n longstringchar ::= \n stringescapeseq ::= "\\" \n\n bytesliteral ::= bytesprefix(shortbytes | longbytes)\n bytesprefix ::= "b" | "B" | "br" | "Br" | "bR" | "BR"\n shortbytes ::= "\'" shortbytesitem* "\'" | \'"\' shortbytesitem* \'"\'\n longbytes ::= "\'\'\'" longbytesitem* "\'\'\'" | \'"""\' longbytesitem* \'"""\'\n shortbytesitem ::= shortbyteschar | bytesescapeseq\n longbytesitem ::= longbyteschar | bytesescapeseq\n shortbyteschar ::= \n longbyteschar ::= \n bytesescapeseq ::= "\\" \n\nOne syntactic restriction not indicated by these productions is that\nwhitespace is not allowed between the ``stringprefix`` or\n``bytesprefix`` and the rest of the literal. The source character set\nis defined by the encoding declaration; it is UTF-8 if no encoding\ndeclaration is given in the source file; see section *Encoding\ndeclarations*.\n\nIn plain English: Both types of literals can be enclosed in matching\nsingle quotes (``\'``) or double quotes (``"``). They can also be\nenclosed in matching groups of three single or double quotes (these\nare generally referred to as *triple-quoted strings*). The backslash\n(``\\``) character is used to escape characters that otherwise have a\nspecial meaning, such as newline, backslash itself, or the quote\ncharacter.\n\nBytes literals are always prefixed with ``\'b\'`` or ``\'B\'``; they\nproduce an instance of the ``bytes`` type instead of the ``str`` type.\nThey may only contain ASCII characters; bytes with a numeric value of\n128 or greater must be expressed with escapes.\n\nBoth string and bytes literals may optionally be prefixed with a\nletter ``\'r\'`` or ``\'R\'``; such strings are called *raw strings* and\ntreat backslashes as literal characters. As a result, in string\nliterals, ``\'\\U\'`` and ``\'\\u\'`` escapes in raw strings are not treated\nspecially.\n\nIn triple-quoted strings, unescaped newlines and quotes are allowed\n(and are retained), except that three unescaped quotes in a row\nterminate the string. (A "quote" is the character used to open the\nstring, i.e. either ``\'`` or ``"``.)\n\nUnless an ``\'r\'`` or ``\'R\'`` prefix is present, escape sequences in\nstrings are interpreted according to rules similar to those used by\nStandard C. The recognized escape sequences are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\newline`` | Backslash and newline ignored | |\n+-------------------+-----------------------------------+---------+\n| ``\\\\`` | Backslash (``\\``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\\'`` | Single quote (``\'``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\"`` | Double quote (``"``) | |\n+-------------------+-----------------------------------+---------+\n| ``\\a`` | ASCII Bell (BEL) | |\n+-------------------+-----------------------------------+---------+\n| ``\\b`` | ASCII Backspace (BS) | |\n+-------------------+-----------------------------------+---------+\n| ``\\f`` | ASCII Formfeed (FF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\n`` | ASCII Linefeed (LF) | |\n+-------------------+-----------------------------------+---------+\n| ``\\r`` | ASCII Carriage Return (CR) | |\n+-------------------+-----------------------------------+---------+\n| ``\\t`` | ASCII Horizontal Tab (TAB) | |\n+-------------------+-----------------------------------+---------+\n| ``\\v`` | ASCII Vertical Tab (VT) | |\n+-------------------+-----------------------------------+---------+\n| ``\\ooo`` | Character with octal value *ooo* | (1,3) |\n+-------------------+-----------------------------------+---------+\n| ``\\xhh`` | Character with hex value *hh* | (2,3) |\n+-------------------+-----------------------------------+---------+\n\nEscape sequences only recognized in string literals are:\n\n+-------------------+-----------------------------------+---------+\n| Escape Sequence | Meaning | Notes |\n+===================+===================================+=========+\n| ``\\N{name}`` | Character named *name* in the | |\n| | Unicode database | |\n+-------------------+-----------------------------------+---------+\n| ``\\uxxxx`` | Character with 16-bit hex value | (4) |\n| | *xxxx* | |\n+-------------------+-----------------------------------+---------+\n| ``\\Uxxxxxxxx`` | Character with 32-bit hex value | (5) |\n| | *xxxxxxxx* | |\n+-------------------+-----------------------------------+---------+\n\nNotes:\n\n1. As in Standard C, up to three octal digits are accepted.\n\n2. Unlike in Standard C, exactly two hex digits are required.\n\n3. In a bytes literal, hexadecimal and octal escapes denote the byte\n with the given value. In a string literal, these escapes denote a\n Unicode character with the given value.\n\n4. Individual code units which form parts of a surrogate pair can be\n encoded using this escape sequence. Exactly four hex digits are\n required.\n\n5. Any Unicode character can be encoded this way, but characters\n outside the Basic Multilingual Plane (BMP) will be encoded using a\n surrogate pair if Python is compiled to use 16-bit code units (the\n default). Exactly eight hex digits are required.\n\nUnlike Standard C, all unrecognized escape sequences are left in the\nstring unchanged, i.e., *the backslash is left in the string*. (This\nbehavior is useful when debugging: if an escape sequence is mistyped,\nthe resulting output is more easily recognized as broken.) It is also\nimportant to note that the escape sequences only recognized in string\nliterals fall into the category of unrecognized escapes for bytes\nliterals.\n\nEven in a raw string, string quotes can be escaped with a backslash,\nbut the backslash remains in the string; for example, ``r"\\""`` is a\nvalid string literal consisting of two characters: a backslash and a\ndouble quote; ``r"\\"`` is not a valid string literal (even a raw\nstring cannot end in an odd number of backslashes). Specifically, *a\nraw string cannot end in a single backslash* (since the backslash\nwould escape the following quote character). Note also that a single\nbackslash followed by a newline is interpreted as those two characters\nas part of the string, *not* as a line continuation.\n', 'subscriptions': '\nSubscriptions\n*************\n\nA subscription selects an item of a sequence (string, tuple or list)\nor mapping (dictionary) object:\n\n subscription ::= primary "[" expression_list "]"\n\nThe primary must evaluate to an object that supports subscription,\ne.g. a list or dictionary. User-defined objects can support\nsubscription by defining a ``__getitem__()`` method.\n\nFor built-in objects, there are two types of objects that support\nsubscription:\n\nIf the primary is a mapping, the expression list must evaluate to an\nobject whose value is one of the keys of the mapping, and the\nsubscription selects the value in the mapping that corresponds to that\nkey. (The expression list is a tuple except if it has exactly one\nitem.)\n\nIf the primary is a sequence, the expression (list) must evaluate to\nan integer or a slice (as discussed in the following section).\n\nThe formal syntax makes no special provision for negative indices in\nsequences; however, built-in sequences all provide a ``__getitem__()``\nmethod that interprets negative indices by adding the length of the\nsequence to the index (so that ``x[-1]`` selects the last item of\n``x``). The resulting value must be a nonnegative integer less than\nthe number of items in the sequence, and the subscription selects the\nitem whose index is that value (counting from zero). Since the support\nfor negative indices and slicing occurs in the object\'s\n``__getitem__()`` method, subclasses overriding this method will need\nto explicitly add that support.\n\nA string\'s items are characters. A character is not a separate data\ntype but a string of exactly one character.\n', @@ -70,7 +70,7 @@ 'typesmapping': '\nMapping Types --- ``dict``\n**************************\n\nA *mapping* object maps *hashable* values to arbitrary objects.\nMappings are mutable objects. There is currently only one standard\nmapping type, the *dictionary*. (For other containers see the built\nin ``list``, ``set``, and ``tuple`` classes, and the ``collections``\nmodule.)\n\nA dictionary\'s keys are *almost* arbitrary values. Values that are\nnot *hashable*, that is, values containing lists, dictionaries or\nother mutable types (that are compared by value rather than by object\nidentity) may not be used as keys. Numeric types used for keys obey\nthe normal rules for numeric comparison: if two numbers compare equal\n(such as ``1`` and ``1.0``) then they can be used interchangeably to\nindex the same dictionary entry. (Note however, that since computers\nstore floating-point numbers as approximations it is usually unwise to\nuse them as dictionary keys.)\n\nDictionaries can be created by placing a comma-separated list of\n``key: value`` pairs within braces, for example: ``{\'jack\': 4098,\n\'sjoerd\': 4127}`` or ``{4098: \'jack\', 4127: \'sjoerd\'}``, or by the\n``dict`` constructor.\n\nclass class dict([arg])\n\n Return a new dictionary initialized from an optional positional\n argument or from a set of keyword arguments. If no arguments are\n given, return a new empty dictionary. If the positional argument\n *arg* is a mapping object, return a dictionary mapping the same\n keys to the same values as does the mapping object. Otherwise the\n positional argument must be a sequence, a container that supports\n iteration, or an iterator object. The elements of the argument\n must each also be of one of those kinds, and each must in turn\n contain exactly two objects. The first is used as a key in the new\n dictionary, and the second as the key\'s value. If a given key is\n seen more than once, the last value associated with it is retained\n in the new dictionary.\n\n If keyword arguments are given, the keywords themselves with their\n associated values are added as items to the dictionary. If a key\n is specified both in the positional argument and as a keyword\n argument, the value associated with the keyword is retained in the\n dictionary. For example, these all return a dictionary equal to\n ``{"one": 1, "two": 2}``:\n\n * ``dict(one=1, two=2)``\n\n * ``dict({\'one\': 1, \'two\': 2})``\n\n * ``dict(zip((\'one\', \'two\'), (1, 2)))``\n\n * ``dict([[\'two\', 2], [\'one\', 1]])``\n\n The first example only works for keys that are valid Python\n identifiers; the others work with any valid keys.\n\n These are the operations that dictionaries support (and therefore,\n custom mapping types should support too):\n\n len(d)\n\n Return the number of items in the dictionary *d*.\n\n d[key]\n\n Return the item of *d* with key *key*. Raises a ``KeyError`` if\n *key* is not in the map.\n\n If a subclass of dict defines a method ``__missing__()``, if the\n key *key* is not present, the ``d[key]`` operation calls that\n method with the key *key* as argument. The ``d[key]`` operation\n then returns or raises whatever is returned or raised by the\n ``__missing__(key)`` call if the key is not present. No other\n operations or methods invoke ``__missing__()``. If\n ``__missing__()`` is not defined, ``KeyError`` is raised.\n ``__missing__()`` must be a method; it cannot be an instance\n variable. For an example, see ``collections.defaultdict``.\n\n d[key] = value\n\n Set ``d[key]`` to *value*.\n\n del d[key]\n\n Remove ``d[key]`` from *d*. Raises a ``KeyError`` if *key* is\n not in the map.\n\n key in d\n\n Return ``True`` if *d* has a key *key*, else ``False``.\n\n key not in d\n\n Equivalent to ``not key in d``.\n\n iter(d)\n\n Return an iterator over the keys of the dictionary. This is a\n shortcut for ``iter(d.keys())``.\n\n clear()\n\n Remove all items from the dictionary.\n\n copy()\n\n Return a shallow copy of the dictionary.\n\n classmethod fromkeys(seq[, value])\n\n Create a new dictionary with keys from *seq* and values set to\n *value*.\n\n ``fromkeys()`` is a class method that returns a new dictionary.\n *value* defaults to ``None``.\n\n get(key[, default])\n\n Return the value for *key* if *key* is in the dictionary, else\n *default*. If *default* is not given, it defaults to ``None``,\n so that this method never raises a ``KeyError``.\n\n items()\n\n Return a new view of the dictionary\'s items (``(key, value)``\n pairs). See below for documentation of view objects.\n\n keys()\n\n Return a new view of the dictionary\'s keys. See below for\n documentation of view objects.\n\n pop(key[, default])\n\n If *key* is in the dictionary, remove it and return its value,\n else return *default*. If *default* is not given and *key* is\n not in the dictionary, a ``KeyError`` is raised.\n\n popitem()\n\n Remove and return an arbitrary ``(key, value)`` pair from the\n dictionary.\n\n ``popitem()`` is useful to destructively iterate over a\n dictionary, as often used in set algorithms. If the dictionary\n is empty, calling ``popitem()`` raises a ``KeyError``.\n\n setdefault(key[, default])\n\n If *key* is in the dictionary, return its value. If not, insert\n *key* with a value of *default* and return *default*. *default*\n defaults to ``None``.\n\n update([other])\n\n Update the dictionary with the key/value pairs from *other*,\n overwriting existing keys. Return ``None``.\n\n ``update()`` accepts either another dictionary object or an\n iterable of key/value pairs (as tuples or other iterables of\n length two). If keyword arguments are specified, the dictionary\n is then updated with those key/value pairs: ``d.update(red=1,\n blue=2)``.\n\n values()\n\n Return a new view of the dictionary\'s values. See below for\n documentation of view objects.\n\n\nDictionary view objects\n=======================\n\nThe objects returned by ``dict.keys()``, ``dict.values()`` and\n``dict.items()`` are *view objects*. They provide a dynamic view on\nthe dictionary\'s entries, which means that when the dictionary\nchanges, the view reflects these changes.\n\nDictionary views can be iterated over to yield their respective data,\nand support membership tests:\n\nlen(dictview)\n\n Return the number of entries in the dictionary.\n\niter(dictview)\n\n Return an iterator over the keys, values or items (represented as\n tuples of ``(key, value)``) in the dictionary.\n\n Keys and values are iterated over in an arbitrary order which is\n non-random, varies across Python implementations, and depends on\n the dictionary\'s history of insertions and deletions. If keys,\n values and items views are iterated over with no intervening\n modifications to the dictionary, the order of items will directly\n correspond. This allows the creation of ``(value, key)`` pairs\n using ``zip()``: ``pairs = zip(d.values(), d.keys())``. Another\n way to create the same list is ``pairs = [(v, k) for (k, v) in\n d.items()]``.\n\n Iterating views while adding or deleting entries in the dictionary\n may raise a ``RuntimeError`` or fail to iterate over all entries.\n\nx in dictview\n\n Return ``True`` if *x* is in the underlying dictionary\'s keys,\n values or items (in the latter case, *x* should be a ``(key,\n value)`` tuple).\n\nKeys views are set-like since their entries are unique and hashable.\nIf all values are hashable, so that ``(key, value)`` pairs are unique\nand hashable, then the items view is also set-like. (Values views are\nnot treated as set-like since the entries are generally not unique.)\nFor set-like views, all of the operations defined for the abstract\nbase class ``collections.Set`` are available (for example, ``==``,\n``<``, or ``^``).\n\nAn example of dictionary view usage:\n\n >>> dishes = {\'eggs\': 2, \'sausage\': 1, \'bacon\': 1, \'spam\': 500}\n >>> keys = dishes.keys()\n >>> values = dishes.values()\n\n >>> # iteration\n >>> n = 0\n >>> for val in values:\n ... n += val\n >>> print(n)\n 504\n\n >>> # keys and values are iterated over in the same order\n >>> list(keys)\n [\'eggs\', \'bacon\', \'sausage\', \'spam\']\n >>> list(values)\n [2, 1, 1, 500]\n\n >>> # view objects are dynamic and reflect dict changes\n >>> del dishes[\'eggs\']\n >>> del dishes[\'sausage\']\n >>> list(keys)\n [\'spam\', \'bacon\']\n\n >>> # set operations\n >>> keys & {\'eggs\', \'bacon\', \'salad\'}\n {\'bacon\'}\n >>> keys ^ {\'sausage\', \'juice\'}\n {\'juice\', \'eggs\', \'bacon\', \'spam\'}\n', 'typesmethods': "\nMethods\n*******\n\nMethods are functions that are called using the attribute notation.\nThere are two flavors: built-in methods (such as ``append()`` on\nlists) and class instance methods. Built-in methods are described\nwith the types that support them.\n\nIf you access a method (a function defined in a class namespace)\nthrough an instance, you get a special object: a *bound method* (also\ncalled *instance method*) object. When called, it will add the\n``self`` argument to the argument list. Bound methods have two\nspecial read-only attributes: ``m.__self__`` is the object on which\nthe method operates, and ``m.__func__`` is the function implementing\nthe method. Calling ``m(arg-1, arg-2, ..., arg-n)`` is completely\nequivalent to calling ``m.__func__(m.__self__, arg-1, arg-2, ...,\narg-n)``.\n\nLike function objects, bound method objects support getting arbitrary\nattributes. However, since method attributes are actually stored on\nthe underlying function object (``meth.__func__``), setting method\nattributes on bound methods is disallowed. Attempting to set a method\nattribute results in a ``TypeError`` being raised. In order to set a\nmethod attribute, you need to explicitly set it on the underlying\nfunction object:\n\n class C:\n def method(self):\n pass\n\n c = C()\n c.method.__func__.whoami = 'my name is c'\n\nSee *The standard type hierarchy* for more information.\n", 'typesmodules': "\nModules\n*******\n\nThe only special operation on a module is attribute access:\n``m.name``, where *m* is a module and *name* accesses a name defined\nin *m*'s symbol table. Module attributes can be assigned to. (Note\nthat the ``import`` statement is not, strictly speaking, an operation\non a module object; ``import foo`` does not require a module object\nnamed *foo* to exist, rather it requires an (external) *definition*\nfor a module named *foo* somewhere.)\n\nA special member of every module is ``__dict__``. This is the\ndictionary containing the module's symbol table. Modifying this\ndictionary will actually change the module's symbol table, but direct\nassignment to the ``__dict__`` attribute is not possible (you can\nwrite ``m.__dict__['a'] = 1``, which defines ``m.a`` to be ``1``, but\nyou can't write ``m.__dict__ = {}``). Modifying ``__dict__`` directly\nis not recommended.\n\nModules built into the interpreter are written like this: ````. If loaded from a file, they are written as\n````.\n", - 'typesseq': '\nSequence Types --- ``str``, ``bytes``, ``bytearray``, ``list``, ``tuple``, ``range``\n************************************************************************************\n\nThere are six sequence types: strings, byte sequences (``bytes``\nobjects), byte arrays (``bytearray`` objects), lists, tuples, and\nrange objects. For other containers see the built in ``dict`` and\n``set`` classes, and the ``collections`` module.\n\nStrings contain Unicode characters. Their literals are written in\nsingle or double quotes: ``\'xyzzy\'``, ``"frobozz"``. See *String and\nBytes literals* for more about string literals. In addition to the\nfunctionality described here, there are also string-specific methods\ndescribed in the *String Methods* section.\n\nBytes and bytearray objects contain single bytes -- the former is\nimmutable while the latter is a mutable sequence. Bytes objects can\nbe constructed the constructor, ``bytes()``, and from literals; use a\n``b`` prefix with normal string syntax: ``b\'xyzzy\'``. To construct\nbyte arrays, use the ``bytearray()`` function.\n\nWhile string objects are sequences of characters (represented by\nstrings of length 1), bytes and bytearray objects are sequences of\n*integers* (between 0 and 255), representing the ASCII value of single\nbytes. That means that for a bytes or bytearray object *b*, ``b[0]``\nwill be an integer, while ``b[0:1]`` will be a bytes or bytearray\nobject of length 1. The representation of bytes objects uses the\nliteral format (``b\'...\'``) since it is generally more useful than\ne.g. ``bytes([50, 19, 100])``. You can always convert a bytes object\ninto a list of integers using ``list(b)``.\n\nAlso, while in previous Python versions, byte strings and Unicode\nstrings could be exchanged for each other rather freely (barring\nencoding issues), strings and bytes are now completely separate\nconcepts. There\'s no implicit en-/decoding if you pass an object of\nthe wrong type. A string always compares unequal to a bytes or\nbytearray object.\n\nLists are constructed with square brackets, separating items with\ncommas: ``[a, b, c]``. Tuples are constructed by the comma operator\n(not within square brackets), with or without enclosing parentheses,\nbut an empty tuple must have the enclosing parentheses, such as ``a,\nb, c`` or ``()``. A single item tuple must have a trailing comma,\nsuch as ``(d,)``.\n\nObjects of type range are created using the ``range()`` function.\nThey don\'t support slicing, concatenation or repetition, and using\n``in``, ``not in``, ``min()`` or ``max()`` on them is inefficient.\n\nMost sequence types support the following operations. The ``in`` and\n``not in`` operations have the same priorities as the comparison\noperations. The ``+`` and ``*`` operations have the same priority as\nthe corresponding numeric operations. [3] Additional methods are\nprovided for *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type; *n*, *i* and *j* are\nintegers:\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+--------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+--------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| ``s * n, n * s`` | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| ``s[i]`` | *i*\'th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+--------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must\ncompare equal and the two sequences must be of the same type and have\nthe same length. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string object, the ``in`` and ``not in`` operations\n act like a substring test.\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. **CPython implementation detail:** If *s* and *t* are both strings,\n some Python implementations such as CPython can usually perform an\n in-place optimization for assignments of the form ``s = s + t`` or\n ``s += t``. When applicable, this optimization makes quadratic\n run-time much less likely. This optimization is both version and\n implementation dependent. For performance sensitive code, it is\n preferable to use the ``str.join()`` method which assures\n consistent linear concatenation performance across versions and\n implementations.\n\n\nString Methods\n==============\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters include digit characters, and all characters that that\n can be used to form decimal-radix numbers, e.g. U+0660, ARABIC-\n INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise.\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n\n\nOld String Formatting Operations\n================================\n\nNote: The formatting operations described here are obsolete and may go\n away in future versions of Python. Use the new *String Formatting*\n in new code.\n\nString objects have one unique built-in operation: the ``%`` operator\n(modulo). This is also known as the string *formatting* or\n*interpolation* operator. Given ``format % values`` (where *format* is\na string), ``%`` conversion specifications in *format* are replaced\nwith zero or more elements of *values*. The effect is similar to the\nusing ``sprintf()`` in the C language.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [4] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The ``\'%\'`` character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence of\n characters (for example, ``(somename)``).\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an ``\'*\'``\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a ``\'.\'`` (dot) followed by the\n precision. If specified as ``\'*\'`` (an asterisk), the actual width\n is read from the next element of the tuple in *values*, and the\n value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the ``\'%\'`` character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print(\'%(language)s has %(number)03d quote types.\' %\n... {\'language\': "Python", "number": 2})\nPython has 002 quote types.\n\nIn this case no ``*`` specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| ``\'#\'`` | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| ``\'0\'`` | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'-\'`` | The converted value is left adjusted (overrides the ``\'0\'`` |\n| | conversion if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| ``\' \'`` | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'+\'`` | A sign character (``\'+\'`` or ``\'-\'``) will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier (``h``, ``l``, or ``L``) may be present, but is\nignored as it is not necessary for Python -- so e.g. ``%ld`` is\nidentical to ``%d``.\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| ``\'d\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'i\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'o\'`` | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'u\'`` | Obsolete type -- it is identical to ``\'d\'``. | (7) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'x\'`` | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'X\'`` | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'e\'`` | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'E\'`` | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'f\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'F\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'g\'`` | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'G\'`` | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'c\'`` | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'r\'`` | String (converts any Python object using ``repr()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'s\'`` | String (converts any Python object using ``str()``). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'%\'`` | No argument is converted, results in a ``\'%\'`` | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero (``\'0\'``) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading ``\'0x\'`` or ``\'0X\'`` (depending\n on whether the ``\'x\'`` or ``\'X\'`` format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. The precision determines the maximal number of characters used.\n\n1. See **PEP 237**.\n\nSince Python strings have an explicit length, ``%s`` conversions do\nnot assume that ``\'\\0\'`` is the end of the string.\n\nChanged in version 3.1: ``%f`` conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by ``%g`` conversions.\n\nAdditional string operations are defined in standard modules\n``string`` and ``re``.\n\n\nRange Type\n==========\n\nThe ``range`` type is an immutable sequence which is commonly used for\nlooping. The advantage of the ``range`` type is that an ``range``\nobject will always take the same amount of memory, no matter the size\nof the range it represents. There are no consistent performance\nadvantages.\n\nRange objects have relatively little behavior: they support indexing,\niteration, the ``len()`` function, and the following methods.\n\nrange.count(x)\n\n Return the number of *i*\'s for which ``s[i] == x``. Normally the\n result will be 0 or 1, but it could be greater if *x* defines an\n unusual equality function.\n\n New in version 3.2.\n\nrange.index(x)\n\n Return the smallest *i* such that ``s[i] == x``. Raises\n ``ValueError`` when *x* is not in the range.\n\n New in version 3.2.\n\n\nMutable Sequence Types\n======================\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n\nBytes and Byte Array Methods\n============================\n\nBytes and bytearray objects, being "strings of bytes", have all\nmethods found on strings, with the exception of ``encode()``,\n``format()`` and ``isidentifier()``, which do not make sense with\nthese types. For converting the objects to strings, they have a\n``decode()`` method.\n\nWherever one of these methods needs to interpret the bytes as\ncharacters (e.g. the ``is...()`` methods), the ASCII character set is\nassumed.\n\nNote: The methods on bytes and bytearray objects don\'t accept strings as\n their arguments, just as the methods on strings don\'t accept bytes\n as their arguments. For example, you have to write\n\n a = "abc"\n b = a.replace("a", "f")\n\n and\n\n a = b"abc"\n b = a.replace(b"a", b"f")\n\nbytes.decode(encoding="utf-8", errors="strict")\nbytearray.decode(encoding="utf-8", errors="strict")\n\n Return a string decoded from the given bytes. Default encoding is\n ``\'utf-8\'``. *errors* may be given to set a different error\n handling scheme. The default for *errors* is ``\'strict\'``, meaning\n that encoding errors raise a ``UnicodeError``. Other possible\n values are ``\'ignore\'``, ``\'replace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Added support for keyword arguments.\n\nThe bytes and bytearray types have an additional class method:\n\nclassmethod bytes.fromhex(string)\nclassmethod bytearray.fromhex(string)\n\n This ``bytes`` class method returns a bytes or bytearray object,\n decoding the given string object. The string must contain two\n hexadecimal digits per byte, spaces are ignored.\n\n >>> bytes.fromhex(\'f0 f1f2 \')\n b\'\\xf0\\xf1\\xf2\'\n\nThe maketrans and translate methods differ in semantics from the\nversions available on strings:\n\nbytes.translate(table[, delete])\nbytearray.translate(table[, delete])\n\n Return a copy of the bytes or bytearray object where all bytes\n occurring in the optional argument *delete* are removed, and the\n remaining bytes have been mapped through the given translation\n table, which must be a bytes object of length 256.\n\n You can use the ``bytes.maketrans()`` method to create a\n translation table.\n\n Set the *table* argument to ``None`` for translations that only\n delete characters:\n\n >>> b\'read this short text\'.translate(None, b\'aeiou\')\n b\'rd ths shrt txt\'\n\nstatic bytes.maketrans(from, to)\nstatic bytearray.maketrans(from, to)\n\n This static method returns a translation table usable for\n ``bytes.translate()`` that will map each character in *from* into\n the character at the same position in *to*; *from* and *to* must be\n bytes objects and have the same length.\n\n New in version 3.1.\n', + 'typesseq': '\nSequence Types --- ``str``, ``bytes``, ``bytearray``, ``list``, ``tuple``, ``range``\n************************************************************************************\n\nThere are six sequence types: strings, byte sequences (``bytes``\nobjects), byte arrays (``bytearray`` objects), lists, tuples, and\nrange objects. For other containers see the built in ``dict`` and\n``set`` classes, and the ``collections`` module.\n\nStrings contain Unicode characters. Their literals are written in\nsingle or double quotes: ``\'xyzzy\'``, ``"frobozz"``. See *String and\nBytes literals* for more about string literals. In addition to the\nfunctionality described here, there are also string-specific methods\ndescribed in the *String Methods* section.\n\nBytes and bytearray objects contain single bytes -- the former is\nimmutable while the latter is a mutable sequence. Bytes objects can\nbe constructed the constructor, ``bytes()``, and from literals; use a\n``b`` prefix with normal string syntax: ``b\'xyzzy\'``. To construct\nbyte arrays, use the ``bytearray()`` function.\n\nWhile string objects are sequences of characters (represented by\nstrings of length 1), bytes and bytearray objects are sequences of\n*integers* (between 0 and 255), representing the ASCII value of single\nbytes. That means that for a bytes or bytearray object *b*, ``b[0]``\nwill be an integer, while ``b[0:1]`` will be a bytes or bytearray\nobject of length 1. The representation of bytes objects uses the\nliteral format (``b\'...\'``) since it is generally more useful than\ne.g. ``bytes([50, 19, 100])``. You can always convert a bytes object\ninto a list of integers using ``list(b)``.\n\nAlso, while in previous Python versions, byte strings and Unicode\nstrings could be exchanged for each other rather freely (barring\nencoding issues), strings and bytes are now completely separate\nconcepts. There\'s no implicit en-/decoding if you pass an object of\nthe wrong type. A string always compares unequal to a bytes or\nbytearray object.\n\nLists are constructed with square brackets, separating items with\ncommas: ``[a, b, c]``. Tuples are constructed by the comma operator\n(not within square brackets), with or without enclosing parentheses,\nbut an empty tuple must have the enclosing parentheses, such as ``a,\nb, c`` or ``()``. A single item tuple must have a trailing comma,\nsuch as ``(d,)``.\n\nObjects of type range are created using the ``range()`` function.\nThey don\'t support concatenation or repetition, and using ``min()`` or\n``max()`` on them is inefficient.\n\nMost sequence types support the following operations. The ``in`` and\n``not in`` operations have the same priorities as the comparison\noperations. The ``+`` and ``*`` operations have the same priority as\nthe corresponding numeric operations. [3] Additional methods are\nprovided for *Mutable Sequence Types*.\n\nThis table lists the sequence operations sorted in ascending priority\n(operations in the same box have the same priority). In the table,\n*s* and *t* are sequences of the same type; *n*, *i*, *j* and *k* are\nintegers.\n\n+--------------------+----------------------------------+------------+\n| Operation | Result | Notes |\n+====================+==================================+============+\n| ``x in s`` | ``True`` if an item of *s* is | (1) |\n| | equal to *x*, else ``False`` | |\n+--------------------+----------------------------------+------------+\n| ``x not in s`` | ``False`` if an item of *s* is | (1) |\n| | equal to *x*, else ``True`` | |\n+--------------------+----------------------------------+------------+\n| ``s + t`` | the concatenation of *s* and *t* | (6) |\n+--------------------+----------------------------------+------------+\n| ``s * n, n * s`` | *n* shallow copies of *s* | (2) |\n| | concatenated | |\n+--------------------+----------------------------------+------------+\n| ``s[i]`` | *i*\'th item of *s*, origin 0 | (3) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j]`` | slice of *s* from *i* to *j* | (3)(4) |\n+--------------------+----------------------------------+------------+\n| ``s[i:j:k]`` | slice of *s* from *i* to *j* | (3)(5) |\n| | with step *k* | |\n+--------------------+----------------------------------+------------+\n| ``len(s)`` | length of *s* | |\n+--------------------+----------------------------------+------------+\n| ``min(s)`` | smallest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``max(s)`` | largest item of *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.index(i)`` | index of the first occurence of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n| ``s.count(i)`` | total number of occurences of | |\n| | *i* in *s* | |\n+--------------------+----------------------------------+------------+\n\nSequence types also support comparisons. In particular, tuples and\nlists are compared lexicographically by comparing corresponding\nelements. This means that to compare equal, every element must\ncompare equal and the two sequences must be of the same type and have\nthe same length. (For full details see *Comparisons* in the language\nreference.)\n\nNotes:\n\n1. When *s* is a string object, the ``in`` and ``not in`` operations\n act like a substring test.\n\n2. Values of *n* less than ``0`` are treated as ``0`` (which yields an\n empty sequence of the same type as *s*). Note also that the copies\n are shallow; nested structures are not copied. This often haunts\n new Python programmers; consider:\n\n >>> lists = [[]] * 3\n >>> lists\n [[], [], []]\n >>> lists[0].append(3)\n >>> lists\n [[3], [3], [3]]\n\n What has happened is that ``[[]]`` is a one-element list containing\n an empty list, so all three elements of ``[[]] * 3`` are (pointers\n to) this single empty list. Modifying any of the elements of\n ``lists`` modifies this single list. You can create a list of\n different lists this way:\n\n >>> lists = [[] for i in range(3)]\n >>> lists[0].append(3)\n >>> lists[1].append(5)\n >>> lists[2].append(7)\n >>> lists\n [[3], [5], [7]]\n\n3. If *i* or *j* is negative, the index is relative to the end of the\n string: ``len(s) + i`` or ``len(s) + j`` is substituted. But note\n that ``-0`` is still ``0``.\n\n4. The slice of *s* from *i* to *j* is defined as the sequence of\n items with index *k* such that ``i <= k < j``. If *i* or *j* is\n greater than ``len(s)``, use ``len(s)``. If *i* is omitted or\n ``None``, use ``0``. If *j* is omitted or ``None``, use\n ``len(s)``. If *i* is greater than or equal to *j*, the slice is\n empty.\n\n5. The slice of *s* from *i* to *j* with step *k* is defined as the\n sequence of items with index ``x = i + n*k`` such that ``0 <= n <\n (j-i)/k``. In other words, the indices are ``i``, ``i+k``,\n ``i+2*k``, ``i+3*k`` and so on, stopping when *j* is reached (but\n never including *j*). If *i* or *j* is greater than ``len(s)``,\n use ``len(s)``. If *i* or *j* are omitted or ``None``, they become\n "end" values (which end depends on the sign of *k*). Note, *k*\n cannot be zero. If *k* is ``None``, it is treated like ``1``.\n\n6. **CPython implementation detail:** If *s* and *t* are both strings,\n some Python implementations such as CPython can usually perform an\n in-place optimization for assignments of the form ``s = s + t`` or\n ``s += t``. When applicable, this optimization makes quadratic\n run-time much less likely. This optimization is both version and\n implementation dependent. For performance sensitive code, it is\n preferable to use the ``str.join()`` method which assures\n consistent linear concatenation performance across versions and\n implementations.\n\n\nString Methods\n==============\n\nString objects support the methods listed below.\n\nIn addition, Python\'s strings support the sequence type methods\ndescribed in the *Sequence Types --- str, bytes, bytearray, list,\ntuple, range* section. To output formatted strings, see the *String\nFormatting* section. Also, see the ``re`` module for string functions\nbased on regular expressions.\n\nstr.capitalize()\n\n Return a copy of the string with its first character capitalized\n and the rest lowercased.\n\nstr.center(width[, fillchar])\n\n Return centered in a string of length *width*. Padding is done\n using the specified *fillchar* (default is a space).\n\nstr.count(sub[, start[, end]])\n\n Return the number of non-overlapping occurrences of substring *sub*\n in the range [*start*, *end*]. Optional arguments *start* and\n *end* are interpreted as in slice notation.\n\nstr.encode(encoding="utf-8", errors="strict")\n\n Return an encoded version of the string as a bytes object. Default\n encoding is ``\'utf-8\'``. *errors* may be given to set a different\n error handling scheme. The default for *errors* is ``\'strict\'``,\n meaning that encoding errors raise a ``UnicodeError``. Other\n possible values are ``\'ignore\'``, ``\'replace\'``,\n ``\'xmlcharrefreplace\'``, ``\'backslashreplace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Support for keyword arguments added.\n\nstr.endswith(suffix[, start[, end]])\n\n Return ``True`` if the string ends with the specified *suffix*,\n otherwise return ``False``. *suffix* can also be a tuple of\n suffixes to look for. With optional *start*, test beginning at\n that position. With optional *end*, stop comparing at that\n position.\n\nstr.expandtabs([tabsize])\n\n Return a copy of the string where all tab characters are replaced\n by one or more spaces, depending on the current column and the\n given tab size. The column number is reset to zero after each\n newline occurring in the string. If *tabsize* is not given, a tab\n size of ``8`` characters is assumed. This doesn\'t understand other\n non-printing characters or escape sequences.\n\nstr.find(sub[, start[, end]])\n\n Return the lowest index in the string where substring *sub* is\n found, such that *sub* is contained in the slice ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` if *sub* is not found.\n\nstr.format(*args, **kwargs)\n\n Perform a string formatting operation. The string on which this\n method is called can contain literal text or replacement fields\n delimited by braces ``{}``. Each replacement field contains either\n the numeric index of a positional argument, or the name of a\n keyword argument. Returns a copy of the string where each\n replacement field is replaced with the string value of the\n corresponding argument.\n\n >>> "The sum of 1 + 2 is {0}".format(1+2)\n \'The sum of 1 + 2 is 3\'\n\n See *Format String Syntax* for a description of the various\n formatting options that can be specified in format strings.\n\nstr.format_map(mapping)\n\n Similar to ``str.format(**mapping)``, except that ``mapping`` is\n used directly and not copied to a ``dict`` . This is useful if for\n example ``mapping`` is a dict subclass:\n\n >>> class Default(dict):\n ... def __missing__(self, key):\n ... return key\n ...\n >>> \'{name} was born in {country}\'.format_map(Default(name=\'Guido\'))\n \'Guido was born in country\'\n\n New in version 3.2.\n\nstr.index(sub[, start[, end]])\n\n Like ``find()``, but raise ``ValueError`` when the substring is not\n found.\n\nstr.isalnum()\n\n Return true if all characters in the string are alphanumeric and\n there is at least one character, false otherwise.\n\nstr.isalpha()\n\n Return true if all characters in the string are alphabetic and\n there is at least one character, false otherwise.\n\nstr.isdecimal()\n\n Return true if all characters in the string are decimal characters\n and there is at least one character, false otherwise. Decimal\n characters include digit characters, and all characters that that\n can be used to form decimal-radix numbers, e.g. U+0660, ARABIC-\n INDIC DIGIT ZERO.\n\nstr.isdigit()\n\n Return true if all characters in the string are digits and there is\n at least one character, false otherwise.\n\nstr.isidentifier()\n\n Return true if the string is a valid identifier according to the\n language definition, section *Identifiers and keywords*.\n\nstr.islower()\n\n Return true if all cased characters in the string are lowercase and\n there is at least one cased character, false otherwise.\n\nstr.isnumeric()\n\n Return true if all characters in the string are numeric characters,\n and there is at least one character, false otherwise. Numeric\n characters include digit characters, and all characters that have\n the Unicode numeric value property, e.g. U+2155, VULGAR FRACTION\n ONE FIFTH.\n\nstr.isprintable()\n\n Return true if all characters in the string are printable or the\n string is empty, false otherwise. Nonprintable characters are\n those characters defined in the Unicode character database as\n "Other" or "Separator", excepting the ASCII space (0x20) which is\n considered printable. (Note that printable characters in this\n context are those which should not be escaped when ``repr()`` is\n invoked on a string. It has no bearing on the handling of strings\n written to ``sys.stdout`` or ``sys.stderr``.)\n\nstr.isspace()\n\n Return true if there are only whitespace characters in the string\n and there is at least one character, false otherwise.\n\nstr.istitle()\n\n Return true if the string is a titlecased string and there is at\n least one character, for example uppercase characters may only\n follow uncased characters and lowercase characters only cased ones.\n Return false otherwise.\n\nstr.isupper()\n\n Return true if all cased characters in the string are uppercase and\n there is at least one cased character, false otherwise.\n\nstr.join(iterable)\n\n Return a string which is the concatenation of the strings in the\n *iterable* *iterable*. A ``TypeError`` will be raised if there are\n any non-string values in *seq*, including ``bytes`` objects. The\n separator between elements is the string providing this method.\n\nstr.ljust(width[, fillchar])\n\n Return the string left justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.lower()\n\n Return a copy of the string converted to lowercase.\n\nstr.lstrip([chars])\n\n Return a copy of the string with leading characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a prefix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.lstrip()\n \'spacious \'\n >>> \'www.example.com\'.lstrip(\'cmowz.\')\n \'example.com\'\n\nstatic str.maketrans(x[, y[, z]])\n\n This static method returns a translation table usable for\n ``str.translate()``.\n\n If there is only one argument, it must be a dictionary mapping\n Unicode ordinals (integers) or characters (strings of length 1) to\n Unicode ordinals, strings (of arbitrary lengths) or None.\n Character keys will then be converted to ordinals.\n\n If there are two arguments, they must be strings of equal length,\n and in the resulting dictionary, each character in x will be mapped\n to the character at the same position in y. If there is a third\n argument, it must be a string, whose characters will be mapped to\n None in the result.\n\nstr.partition(sep)\n\n Split the string at the first occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing the string itself, followed by\n two empty strings.\n\nstr.replace(old, new[, count])\n\n Return a copy of the string with all occurrences of substring *old*\n replaced by *new*. If the optional argument *count* is given, only\n the first *count* occurrences are replaced.\n\nstr.rfind(sub[, start[, end]])\n\n Return the highest index in the string where substring *sub* is\n found, such that *sub* is contained within ``s[start:end]``.\n Optional arguments *start* and *end* are interpreted as in slice\n notation. Return ``-1`` on failure.\n\nstr.rindex(sub[, start[, end]])\n\n Like ``rfind()`` but raises ``ValueError`` when the substring *sub*\n is not found.\n\nstr.rjust(width[, fillchar])\n\n Return the string right justified in a string of length *width*.\n Padding is done using the specified *fillchar* (default is a\n space). The original string is returned if *width* is less than\n ``len(s)``.\n\nstr.rpartition(sep)\n\n Split the string at the last occurrence of *sep*, and return a\n 3-tuple containing the part before the separator, the separator\n itself, and the part after the separator. If the separator is not\n found, return a 3-tuple containing two empty strings, followed by\n the string itself.\n\nstr.rsplit([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit* splits\n are done, the *rightmost* ones. If *sep* is not specified or\n ``None``, any whitespace string is a separator. Except for\n splitting from the right, ``rsplit()`` behaves like ``split()``\n which is described in detail below.\n\nstr.rstrip([chars])\n\n Return a copy of the string with trailing characters removed. The\n *chars* argument is a string specifying the set of characters to be\n removed. If omitted or ``None``, the *chars* argument defaults to\n removing whitespace. The *chars* argument is not a suffix; rather,\n all combinations of its values are stripped:\n\n >>> \' spacious \'.rstrip()\n \' spacious\'\n >>> \'mississippi\'.rstrip(\'ipz\')\n \'mississ\'\n\nstr.split([sep[, maxsplit]])\n\n Return a list of the words in the string, using *sep* as the\n delimiter string. If *maxsplit* is given, at most *maxsplit*\n splits are done (thus, the list will have at most ``maxsplit+1``\n elements). If *maxsplit* is not specified, then there is no limit\n on the number of splits (all possible splits are made).\n\n If *sep* is given, consecutive delimiters are not grouped together\n and are deemed to delimit empty strings (for example,\n ``\'1,,2\'.split(\',\')`` returns ``[\'1\', \'\', \'2\']``). The *sep*\n argument may consist of multiple characters (for example,\n ``\'1<>2<>3\'.split(\'<>\')`` returns ``[\'1\', \'2\', \'3\']``). Splitting\n an empty string with a specified separator returns ``[\'\']``.\n\n If *sep* is not specified or is ``None``, a different splitting\n algorithm is applied: runs of consecutive whitespace are regarded\n as a single separator, and the result will contain no empty strings\n at the start or end if the string has leading or trailing\n whitespace. Consequently, splitting an empty string or a string\n consisting of just whitespace with a ``None`` separator returns\n ``[]``.\n\n For example, ``\' 1 2 3 \'.split()`` returns ``[\'1\', \'2\', \'3\']``,\n and ``\' 1 2 3 \'.split(None, 1)`` returns ``[\'1\', \'2 3 \']``.\n\nstr.splitlines([keepends])\n\n Return a list of the lines in the string, breaking at line\n boundaries. Line breaks are not included in the resulting list\n unless *keepends* is given and true.\n\nstr.startswith(prefix[, start[, end]])\n\n Return ``True`` if string starts with the *prefix*, otherwise\n return ``False``. *prefix* can also be a tuple of prefixes to look\n for. With optional *start*, test string beginning at that\n position. With optional *end*, stop comparing string at that\n position.\n\nstr.strip([chars])\n\n Return a copy of the string with the leading and trailing\n characters removed. The *chars* argument is a string specifying the\n set of characters to be removed. If omitted or ``None``, the\n *chars* argument defaults to removing whitespace. The *chars*\n argument is not a prefix or suffix; rather, all combinations of its\n values are stripped:\n\n >>> \' spacious \'.strip()\n \'spacious\'\n >>> \'www.example.com\'.strip(\'cmowz.\')\n \'example\'\n\nstr.swapcase()\n\n Return a copy of the string with uppercase characters converted to\n lowercase and vice versa.\n\nstr.title()\n\n Return a titlecased version of the string where words start with an\n uppercase character and the remaining characters are lowercase.\n\n The algorithm uses a simple language-independent definition of a\n word as groups of consecutive letters. The definition works in\n many contexts but it means that apostrophes in contractions and\n possessives form word boundaries, which may not be the desired\n result:\n\n >>> "they\'re bill\'s friends from the UK".title()\n "They\'Re Bill\'S Friends From The Uk"\n\n A workaround for apostrophes can be constructed using regular\n expressions:\n\n >>> import re\n >>> def titlecase(s):\n return re.sub(r"[A-Za-z]+(\'[A-Za-z]+)?",\n lambda mo: mo.group(0)[0].upper() +\n mo.group(0)[1:].lower(),\n s)\n\n >>> titlecase("they\'re bill\'s friends.")\n "They\'re Bill\'s Friends."\n\nstr.translate(map)\n\n Return a copy of the *s* where all characters have been mapped\n through the *map* which must be a dictionary of Unicode ordinals\n (integers) to Unicode ordinals, strings or ``None``. Unmapped\n characters are left untouched. Characters mapped to ``None`` are\n deleted.\n\n You can use ``str.maketrans()`` to create a translation map from\n character-to-character mappings in different formats.\n\n Note: An even more flexible approach is to create a custom character\n mapping codec using the ``codecs`` module (see\n ``encodings.cp1251`` for an example).\n\nstr.upper()\n\n Return a copy of the string converted to uppercase.\n\nstr.zfill(width)\n\n Return the numeric string left filled with zeros in a string of\n length *width*. A sign prefix is handled correctly. The original\n string is returned if *width* is less than ``len(s)``.\n\n\nOld String Formatting Operations\n================================\n\nNote: The formatting operations described here are obsolete and may go\n away in future versions of Python. Use the new *String Formatting*\n in new code.\n\nString objects have one unique built-in operation: the ``%`` operator\n(modulo). This is also known as the string *formatting* or\n*interpolation* operator. Given ``format % values`` (where *format* is\na string), ``%`` conversion specifications in *format* are replaced\nwith zero or more elements of *values*. The effect is similar to the\nusing ``sprintf()`` in the C language.\n\nIf *format* requires a single argument, *values* may be a single non-\ntuple object. [4] Otherwise, *values* must be a tuple with exactly\nthe number of items specified by the format string, or a single\nmapping object (for example, a dictionary).\n\nA conversion specifier contains two or more characters and has the\nfollowing components, which must occur in this order:\n\n1. The ``\'%\'`` character, which marks the start of the specifier.\n\n2. Mapping key (optional), consisting of a parenthesised sequence of\n characters (for example, ``(somename)``).\n\n3. Conversion flags (optional), which affect the result of some\n conversion types.\n\n4. Minimum field width (optional). If specified as an ``\'*\'``\n (asterisk), the actual width is read from the next element of the\n tuple in *values*, and the object to convert comes after the\n minimum field width and optional precision.\n\n5. Precision (optional), given as a ``\'.\'`` (dot) followed by the\n precision. If specified as ``\'*\'`` (an asterisk), the actual width\n is read from the next element of the tuple in *values*, and the\n value to convert comes after the precision.\n\n6. Length modifier (optional).\n\n7. Conversion type.\n\nWhen the right argument is a dictionary (or other mapping type), then\nthe formats in the string *must* include a parenthesised mapping key\ninto that dictionary inserted immediately after the ``\'%\'`` character.\nThe mapping key selects the value to be formatted from the mapping.\nFor example:\n\n>>> print(\'%(language)s has %(number)03d quote types.\' %\n... {\'language\': "Python", "number": 2})\nPython has 002 quote types.\n\nIn this case no ``*`` specifiers may occur in a format (since they\nrequire a sequential parameter list).\n\nThe conversion flag characters are:\n\n+-----------+-----------------------------------------------------------------------+\n| Flag | Meaning |\n+===========+=======================================================================+\n| ``\'#\'`` | The value conversion will use the "alternate form" (where defined |\n| | below). |\n+-----------+-----------------------------------------------------------------------+\n| ``\'0\'`` | The conversion will be zero padded for numeric values. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'-\'`` | The converted value is left adjusted (overrides the ``\'0\'`` |\n| | conversion if both are given). |\n+-----------+-----------------------------------------------------------------------+\n| ``\' \'`` | (a space) A blank should be left before a positive number (or empty |\n| | string) produced by a signed conversion. |\n+-----------+-----------------------------------------------------------------------+\n| ``\'+\'`` | A sign character (``\'+\'`` or ``\'-\'``) will precede the conversion |\n| | (overrides a "space" flag). |\n+-----------+-----------------------------------------------------------------------+\n\nA length modifier (``h``, ``l``, or ``L``) may be present, but is\nignored as it is not necessary for Python -- so e.g. ``%ld`` is\nidentical to ``%d``.\n\nThe conversion types are:\n\n+--------------+-------------------------------------------------------+---------+\n| Conversion | Meaning | Notes |\n+==============+=======================================================+=========+\n| ``\'d\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'i\'`` | Signed integer decimal. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'o\'`` | Signed octal value. | (1) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'u\'`` | Obsolete type -- it is identical to ``\'d\'``. | (7) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'x\'`` | Signed hexadecimal (lowercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'X\'`` | Signed hexadecimal (uppercase). | (2) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'e\'`` | Floating point exponential format (lowercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'E\'`` | Floating point exponential format (uppercase). | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'f\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'F\'`` | Floating point decimal format. | (3) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'g\'`` | Floating point format. Uses lowercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'G\'`` | Floating point format. Uses uppercase exponential | (4) |\n| | format if exponent is less than -4 or not less than | |\n| | precision, decimal format otherwise. | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'c\'`` | Single character (accepts integer or single character | |\n| | string). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'r\'`` | String (converts any Python object using ``repr()``). | (5) |\n+--------------+-------------------------------------------------------+---------+\n| ``\'s\'`` | String (converts any Python object using ``str()``). | |\n+--------------+-------------------------------------------------------+---------+\n| ``\'%\'`` | No argument is converted, results in a ``\'%\'`` | |\n| | character in the result. | |\n+--------------+-------------------------------------------------------+---------+\n\nNotes:\n\n1. The alternate form causes a leading zero (``\'0\'``) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n2. The alternate form causes a leading ``\'0x\'`` or ``\'0X\'`` (depending\n on whether the ``\'x\'`` or ``\'X\'`` format was used) to be inserted\n between left-hand padding and the formatting of the number if the\n leading character of the result is not already a zero.\n\n3. The alternate form causes the result to always contain a decimal\n point, even if no digits follow it.\n\n The precision determines the number of digits after the decimal\n point and defaults to 6.\n\n4. The alternate form causes the result to always contain a decimal\n point, and trailing zeroes are not removed as they would otherwise\n be.\n\n The precision determines the number of significant digits before\n and after the decimal point and defaults to 6.\n\n5. The precision determines the maximal number of characters used.\n\n1. See **PEP 237**.\n\nSince Python strings have an explicit length, ``%s`` conversions do\nnot assume that ``\'\\0\'`` is the end of the string.\n\nChanged in version 3.1: ``%f`` conversions for numbers whose absolute\nvalue is over 1e50 are no longer replaced by ``%g`` conversions.\n\nAdditional string operations are defined in standard modules\n``string`` and ``re``.\n\n\nRange Type\n==========\n\nThe ``range`` type is an immutable sequence which is commonly used for\nlooping. The advantage of the ``range`` type is that an ``range``\nobject will always take the same amount of memory, no matter the size\nof the range it represents.\n\nRange objects have relatively little behavior: they support indexing,\ncontains, iteration, the ``len()`` function, and the following\nmethods:\n\nrange.count(x)\n\n Return the number of *i*\'s for which ``s[i] == x``.\n\n New in version 3.2.\n\nrange.index(x)\n\n Return the smallest *i* such that ``s[i] == x``. Raises\n ``ValueError`` when *x* is not in the range.\n\n New in version 3.2.\n\n\nMutable Sequence Types\n======================\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n\n\nBytes and Byte Array Methods\n============================\n\nBytes and bytearray objects, being "strings of bytes", have all\nmethods found on strings, with the exception of ``encode()``,\n``format()`` and ``isidentifier()``, which do not make sense with\nthese types. For converting the objects to strings, they have a\n``decode()`` method.\n\nWherever one of these methods needs to interpret the bytes as\ncharacters (e.g. the ``is...()`` methods), the ASCII character set is\nassumed.\n\nNote: The methods on bytes and bytearray objects don\'t accept strings as\n their arguments, just as the methods on strings don\'t accept bytes\n as their arguments. For example, you have to write\n\n a = "abc"\n b = a.replace("a", "f")\n\n and\n\n a = b"abc"\n b = a.replace(b"a", b"f")\n\nbytes.decode(encoding="utf-8", errors="strict")\nbytearray.decode(encoding="utf-8", errors="strict")\n\n Return a string decoded from the given bytes. Default encoding is\n ``\'utf-8\'``. *errors* may be given to set a different error\n handling scheme. The default for *errors* is ``\'strict\'``, meaning\n that encoding errors raise a ``UnicodeError``. Other possible\n values are ``\'ignore\'``, ``\'replace\'`` and any other name\n registered via ``codecs.register_error()``, see section *Codec Base\n Classes*. For a list of possible encodings, see section *Standard\n Encodings*.\n\n Changed in version 3.1: Added support for keyword arguments.\n\nThe bytes and bytearray types have an additional class method:\n\nclassmethod bytes.fromhex(string)\nclassmethod bytearray.fromhex(string)\n\n This ``bytes`` class method returns a bytes or bytearray object,\n decoding the given string object. The string must contain two\n hexadecimal digits per byte, spaces are ignored.\n\n >>> bytes.fromhex(\'f0 f1f2 \')\n b\'\\xf0\\xf1\\xf2\'\n\nThe maketrans and translate methods differ in semantics from the\nversions available on strings:\n\nbytes.translate(table[, delete])\nbytearray.translate(table[, delete])\n\n Return a copy of the bytes or bytearray object where all bytes\n occurring in the optional argument *delete* are removed, and the\n remaining bytes have been mapped through the given translation\n table, which must be a bytes object of length 256.\n\n You can use the ``bytes.maketrans()`` method to create a\n translation table.\n\n Set the *table* argument to ``None`` for translations that only\n delete characters:\n\n >>> b\'read this short text\'.translate(None, b\'aeiou\')\n b\'rd ths shrt txt\'\n\nstatic bytes.maketrans(from, to)\nstatic bytearray.maketrans(from, to)\n\n This static method returns a translation table usable for\n ``bytes.translate()`` that will map each character in *from* into\n the character at the same position in *to*; *from* and *to* must be\n bytes objects and have the same length.\n\n New in version 3.1.\n', 'typesseq-mutable': '\nMutable Sequence Types\n**********************\n\nList and bytearray objects support additional operations that allow\nin-place modification of the object. Other mutable sequence types\n(when added to the language) should also support these operations.\nStrings and tuples are immutable sequence types: such objects cannot\nbe modified once created. The following operations are defined on\nmutable sequence types (where *x* is an arbitrary object).\n\nNote that while lists allow their items to be of any type, bytearray\nobject "items" are all integers in the range 0 <= x < 256.\n\n+--------------------------------+----------------------------------+-----------------------+\n| Operation | Result | Notes |\n+================================+==================================+=======================+\n| ``s[i] = x`` | item *i* of *s* is replaced by | |\n| | *x* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j] = t`` | slice of *s* from *i* to *j* is | |\n| | replaced by the contents of the | |\n| | iterable *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j]`` | same as ``s[i:j] = []`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s[i:j:k] = t`` | the elements of ``s[i:j:k]`` are | (1) |\n| | replaced by those of *t* | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``del s[i:j:k]`` | removes the elements of | |\n| | ``s[i:j:k]`` from the list | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.append(x)`` | same as ``s[len(s):len(s)] = | |\n| | [x]`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.extend(x)`` | same as ``s[len(s):len(s)] = x`` | (2) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.count(x)`` | return number of *i*\'s for which | |\n| | ``s[i] == x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.index(x[, i[, j]])`` | return smallest *k* such that | (3) |\n| | ``s[k] == x`` and ``i <= k < j`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.insert(i, x)`` | same as ``s[i:i] = [x]`` | (4) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.pop([i])`` | same as ``x = s[i]; del s[i]; | (5) |\n| | return x`` | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.remove(x)`` | same as ``del s[s.index(x)]`` | (3) |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.reverse()`` | reverses the items of *s* in | (6) |\n| | place | |\n+--------------------------------+----------------------------------+-----------------------+\n| ``s.sort([key[, reverse]])`` | sort the items of *s* in place | (6), (7), (8) |\n+--------------------------------+----------------------------------+-----------------------+\n\nNotes:\n\n1. *t* must have the same length as the slice it is replacing.\n\n2. *x* can be any iterable object.\n\n3. Raises ``ValueError`` when *x* is not found in *s*. When a negative\n index is passed as the second or third parameter to the ``index()``\n method, the sequence length is added, as for slice indices. If it\n is still negative, it is truncated to zero, as for slice indices.\n\n4. When a negative index is passed as the first parameter to the\n ``insert()`` method, the sequence length is added, as for slice\n indices. If it is still negative, it is truncated to zero, as for\n slice indices.\n\n5. The optional argument *i* defaults to ``-1``, so that by default\n the last item is removed and returned.\n\n6. The ``sort()`` and ``reverse()`` methods modify the sequence in\n place for economy of space when sorting or reversing a large\n sequence. To remind you that they operate by side effect, they\n don\'t return the sorted or reversed sequence.\n\n7. The ``sort()`` method takes optional arguments for controlling the\n comparisons. Each must be specified as a keyword argument.\n\n *key* specifies a function of one argument that is used to extract\n a comparison key from each list element: ``key=str.lower``. The\n default value is ``None``. Use ``functools.cmp_to_key()`` to\n convert an old-style *cmp* function to a *key* function.\n\n *reverse* is a boolean value. If set to ``True``, then the list\n elements are sorted as if each comparison were reversed.\n\n The ``sort()`` method is guaranteed to be stable. A sort is stable\n if it guarantees not to change the relative order of elements that\n compare equal --- this is helpful for sorting in multiple passes\n (for example, sort by department, then by salary grade).\n\n **CPython implementation detail:** While a list is being sorted,\n the effect of attempting to mutate, or even inspect, the list is\n undefined. The C implementation of Python makes the list appear\n empty for the duration, and raises ``ValueError`` if it can detect\n that the list has been mutated during a sort.\n\n8. ``sort()`` is not supported by ``bytearray`` objects.\n', 'unary': '\nUnary arithmetic and bitwise operations\n***************************************\n\nAll unary arithmetic and bitwise operations have the same priority:\n\n u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr\n\nThe unary ``-`` (minus) operator yields the negation of its numeric\nargument.\n\nThe unary ``+`` (plus) operator yields its numeric argument unchanged.\n\nThe unary ``~`` (invert) operator yields the bitwise inversion of its\ninteger argument. The bitwise inversion of ``x`` is defined as\n``-(x+1)``. It only applies to integral numbers.\n\nIn all three cases, if the argument does not have the proper type, a\n``TypeError`` exception is raised.\n', 'while': '\nThe ``while`` statement\n***********************\n\nThe ``while`` statement is used for repeated execution as long as an\nexpression is true:\n\n while_stmt ::= "while" expression ":" suite\n ["else" ":" suite]\n\nThis repeatedly tests the expression and, if it is true, executes the\nfirst suite; if the expression is false (which may be the first time\nit is tested) the suite of the ``else`` clause, if present, is\nexecuted and the loop terminates.\n\nA ``break`` statement executed in the first suite terminates the loop\nwithout executing the ``else`` clause\'s suite. A ``continue``\nstatement executed in the first suite skips the rest of the suite and\ngoes back to testing the expression.\n', Modified: python/branches/py3k-cdecimal/Lib/random.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/random.py (original) +++ python/branches/py3k-cdecimal/Lib/random.py Sun Jan 2 13:18:37 2011 @@ -43,6 +43,7 @@ from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin from os import urandom as _urandom import collections as _collections +from hashlib import sha512 as _sha512 __all__ = ["Random","seed","random","uniform","randint","choice","sample", "randrange","shuffle","normalvariate","lognormvariate", @@ -110,10 +111,12 @@ import time a = int(time.time() * 256) # use fractional seconds - if version == 2 and isinstance(a, (str, bytes, bytearray)): - if isinstance(a, str): - a = a.encode("utf8") - a = int.from_bytes(a, 'big') + if version == 2: + if isinstance(a, (str, bytes, bytearray)): + if isinstance(a, str): + a = a.encode("utf8") + a += _sha512(a).digest() + a = int.from_bytes(a, 'big') super().seed(a) self.gauss_next = None Modified: python/branches/py3k-cdecimal/Lib/shelve.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/shelve.py (original) +++ python/branches/py3k-cdecimal/Lib/shelve.py Sun Jan 2 13:18:37 2011 @@ -73,6 +73,7 @@ def __repr__(self): return '' + class Shelf(collections.MutableMapping): """Base class for shelf implementations. @@ -88,7 +89,7 @@ self._protocol = protocol self.writeback = writeback self.cache = {} - self.keyencoding = "utf-8" + self.keyencoding = keyencoding def __iter__(self): for k in self.dict.keys(): Modified: python/branches/py3k-cdecimal/Lib/shutil.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/shutil.py (original) +++ python/branches/py3k-cdecimal/Lib/shutil.py Sun Jan 2 13:18:37 2011 @@ -370,7 +370,7 @@ archive that is being built. If not provided, the current owner and group will be used. - The output tar file will be named 'base_dir' + ".tar", possibly plus + The output tar file will be named 'base_name' + ".tar", possibly plus the appropriate compression extension (".gz", or ".bz2"). Returns the output filename. @@ -440,7 +440,7 @@ def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): """Create a zip file from all the files under 'base_dir'. - The output zip file will be named 'base_dir' + ".zip". Uses either the + The output zip file will be named 'base_name' + ".zip". Uses either the "zipfile" Python module (if available) or the InfoZIP "zip" utility (if installed and found on the default search path). If neither tool is available, raises ExecError. Returns the name of the output zip Modified: python/branches/py3k-cdecimal/Lib/site.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/site.py (original) +++ python/branches/py3k-cdecimal/Lib/site.py Sun Jan 2 13:18:37 2011 @@ -55,6 +55,7 @@ import sys import os import builtins +import traceback # Prefixes for site-packages; add additional prefixes like /usr/local here PREFIXES = [sys.prefix, sys.exec_prefix] @@ -141,17 +142,26 @@ except IOError: return with f: - for line in f: + for n, line in enumerate(f): if line.startswith("#"): continue - if line.startswith(("import ", "import\t")): - exec(line) - continue - line = line.rstrip() - dir, dircase = makepath(sitedir, line) - if not dircase in known_paths and os.path.exists(dir): - sys.path.append(dir) - known_paths.add(dircase) + try: + if line.startswith(("import ", "import\t")): + exec(line) + continue + line = line.rstrip() + dir, dircase = makepath(sitedir, line) + if not dircase in known_paths and os.path.exists(dir): + sys.path.append(dir) + known_paths.add(dircase) + except Exception as err: + print("Error processing line {:d} of {}:\n".format(n+1, fullname), + file=sys.stderr) + for record in traceback.format_exception(*sys.exc_info()): + for line in record.splitlines(): + print(' '+line, file=sys.stderr) + print("\nRemainder of file ignored", file=sys.stderr) + break if reset: known_paths = None return known_paths Modified: python/branches/py3k-cdecimal/Lib/smtpd.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/smtpd.py (original) +++ python/branches/py3k-cdecimal/Lib/smtpd.py Sun Jan 2 13:18:37 2011 @@ -109,6 +109,9 @@ COMMAND = 0 DATA = 1 + data_size_limit = 33554432 + command_size_limit = 512 + def __init__(self, server, conn, addr): asynchat.async_chat.__init__(self, conn) self.smtp_server = server @@ -121,6 +124,7 @@ self.rcpttos = [] self.received_data = '' self.fqdn = socket.getfqdn() + self.num_bytes = 0 try: self.peer = conn.getpeername() except socket.error as err: @@ -262,6 +266,15 @@ # Implementation of base class abstract method def collect_incoming_data(self, data): + limit = None + if self.smtp_state == self.COMMAND: + limit = self.command_size_limit + elif self.smtp_state == self.DATA: + limit = self.data_size_limit + if limit and self.num_bytes > limit: + return + elif limit: + self.num_bytes += len(data) self.received_lines.append(str(data, "utf8")) # Implementation of base class abstract method @@ -270,6 +283,11 @@ print('Data:', repr(line), file=DEBUGSTREAM) self.received_lines = [] if self.smtp_state == self.COMMAND: + if self.num_bytes > self.command_size_limit: + self.push('500 Error: line too long') + self.num_bytes = 0 + return + self.num_bytes = 0 if not line: self.push('500 Error: bad syntax') return @@ -290,6 +308,11 @@ else: if self.smtp_state != self.DATA: self.push('451 Internal confusion') + self.num_bytes = 0 + return + if self.num_bytes > self.data_size_limit: + self.push('552 Error: Too much mail data') + self.num_bytes = 0 return # Remove extraneous carriage returns and de-transparency according # to RFC 821, Section 4.5.2. @@ -307,6 +330,7 @@ self.rcpttos = [] self.mailfrom = None self.smtp_state = self.COMMAND + self.num_bytes = 0 self.set_terminator(b'\r\n') if not status: self.push('250 Ok') Modified: python/branches/py3k-cdecimal/Lib/subprocess.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/subprocess.py (original) +++ python/branches/py3k-cdecimal/Lib/subprocess.py Sun Jan 2 13:18:37 2011 @@ -27,10 +27,10 @@ class Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=False, shell=False, + preexec_fn=None, close_fds=True, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, - restore_signals=True, start_new_session=False): + restore_signals=True, start_new_session=False, pass_fds=()): Arguments are: @@ -39,12 +39,12 @@ program to execute is normally the first item in the args sequence or string, but can be explicitly set by using the executable argument. -On UNIX, with shell=False (default): In this case, the Popen class +On POSIX, with shell=False (default): In this case, the Popen class uses os.execvp() to execute the child program. args should normally be a sequence. A string will be treated as a sequence with the string as the only item (the program to execute). -On UNIX, with shell=True: If args is a string, it specifies the +On POSIX, with shell=True: If args is a string, it specifies the command string to execute through the shell. If args is a sequence, the first item specifies the command string, and any additional items will be treated as additional shell arguments. @@ -73,14 +73,19 @@ stderr data from the applications should be captured into the same file handle as for stdout. -On UNIX, if preexec_fn is set to a callable object, this object will be +On POSIX, if preexec_fn is set to a callable object, this object will be called in the child process just before the child is executed. The use of preexec_fn is not thread safe, using it in the presence of threads could lead to a deadlock in the child process before the new executable is executed. If close_fds is true, all file descriptors except 0, 1 and 2 will be -closed before the child process is executed. +closed before the child process is executed. The default for close_fds +varies by platform: Always true on POSIX. True when stdin/stdout/stderr +are None on Windows, false otherwise. + +pass_fds is an optional sequence of file descriptors to keep open between the +parent and child. Providing any pass_fds implicitly sets close_fds to true. if shell is true, the specified command will be executed through the shell. @@ -88,12 +93,12 @@ If cwd is not None, the current directory will be changed to cwd before the child is executed. -On UNIX, if restore_signals is True all signals that Python sets to +On POSIX, if restore_signals is True all signals that Python sets to SIG_IGN are restored to SIG_DFL in the child process before the exec. Currently this includes the SIGPIPE, SIGXFZ and SIGXFSZ signals. This parameter does nothing on Windows. -On UNIX, if start_new_session is True, the setsid() system call will be made +On POSIX, if start_new_session is True, the setsid() system call will be made in the child process prior to executing the command. If env is not None, it defines the environment variables for the new @@ -101,7 +106,7 @@ If universal_newlines is true, the file objects stdout and stderr are opened as a text files, but lines may be terminated by any of '\n', -the Unix end-of-line convention, '\r', the Macintosh convention or +the Unix end-of-line convention, '\r', the old Macintosh convention or '\r\n', the Windows convention. All of these external representations are seen as '\n' by the Python program. Note: This feature is only available if Python is built with universal newline support (the @@ -242,7 +247,7 @@ returncode The child return code. A None value indicates that the process hasn't terminated yet. A negative value -N indicates that the - child was terminated by signal N (UNIX only). + child was terminated by signal N (POSIX only). Replacing older functions with the subprocess module @@ -339,6 +344,7 @@ import gc import signal import builtins +import warnings # Exception classes used by this module. class CalledProcessError(Exception): @@ -378,7 +384,6 @@ import _posixsubprocess except ImportError: _posixsubprocess = None - import warnings warnings.warn("The _posixsubprocess module is not being used. " "Child process reliability may suffer if your " "program uses threads.", RuntimeWarning) @@ -388,6 +393,23 @@ # POSIX defines PIPE_BUF as >= 512. _PIPE_BUF = getattr(select, 'PIPE_BUF', 512) + if _posixsubprocess: + _create_pipe = _posixsubprocess.cloexec_pipe + else: + def _create_pipe(): + try: + cloexec_flag = fcntl.FD_CLOEXEC + except AttributeError: + cloexec_flag = 1 + + fds = os.pipe() + + old = fcntl.fcntl(fds[0], fcntl.F_GETFD) + fcntl.fcntl(fds[0], fcntl.F_SETFD, old | cloexec_flag) + old = fcntl.fcntl(fds[1], fcntl.F_GETFD) + fcntl.fcntl(fds[1], fcntl.F_SETFD, old | cloexec_flag) + + return fds __all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "getstatusoutput", "getoutput", "check_output", "CalledProcessError"] @@ -562,7 +584,7 @@ # Various tools for executing commands and looking at their output and status. # -# NB This only works (and is only relevant) for UNIX. +# NB This only works (and is only relevant) for POSIX. def getstatusoutput(cmd): """Return (status, output) of executing cmd in a shell. @@ -602,13 +624,17 @@ return getstatusoutput(cmd)[1] +_PLATFORM_DEFAULT_CLOSE_FDS = object() + + class Popen(object): def __init__(self, args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, - preexec_fn=None, close_fds=False, shell=False, - cwd=None, env=None, universal_newlines=False, + preexec_fn=None, close_fds=_PLATFORM_DEFAULT_CLOSE_FDS, + shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0, - restore_signals=True, start_new_session=False): + restore_signals=True, start_new_session=False, + pass_fds=()): """Create new Popen instance.""" _cleanup() @@ -622,12 +648,24 @@ if preexec_fn is not None: raise ValueError("preexec_fn is not supported on Windows " "platforms") - if close_fds and (stdin is not None or stdout is not None or - stderr is not None): - raise ValueError("close_fds is not supported on Windows " - "platforms if you redirect stdin/stdout/stderr") + any_stdio_set = (stdin is not None or stdout is not None or + stderr is not None) + if close_fds is _PLATFORM_DEFAULT_CLOSE_FDS: + if any_stdio_set: + close_fds = False + else: + close_fds = True + elif close_fds and any_stdio_set: + raise ValueError( + "close_fds is not supported on Windows platforms" + " if you redirect stdin/stdout/stderr") else: # POSIX + if close_fds is _PLATFORM_DEFAULT_CLOSE_FDS: + close_fds = True + if pass_fds and not close_fds: + warnings.warn("pass_fds overriding close_fds.", RuntimeWarning) + close_fds = True if startupinfo is not None: raise ValueError("startupinfo is only supported on Windows " "platforms") @@ -662,7 +700,7 @@ errread, errwrite) = self._get_handles(stdin, stdout, stderr) self._execute_child(args, executable, preexec_fn, close_fds, - cwd, env, universal_newlines, + pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, @@ -697,6 +735,16 @@ data = data.replace(b"\r\n", b"\n").replace(b"\r", b"\n") return data.decode(encoding) + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + if self.stdout: + self.stdout.close() + if self.stderr: + self.stderr.close() + if self.stdin: + self.stdin.close() def __del__(self, _maxsize=sys.maxsize, _active=_active): if not self._child_created: @@ -829,7 +877,7 @@ def _execute_child(self, args, executable, preexec_fn, close_fds, - cwd, env, universal_newlines, + pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, @@ -837,6 +885,8 @@ unused_restore_signals, unused_start_new_session): """Execute program (MS Windows version)""" + assert not pass_fds, "pass_fds not supported on Windows." + if not isinstance(args, str): args = list2cmdline(args) @@ -935,6 +985,7 @@ def _readerthread(self, fh, buffer): buffer.append(fh.read()) + fh.close() def _communicate(self, input): @@ -1007,7 +1058,7 @@ if stdin is None: pass elif stdin == PIPE: - p2cread, p2cwrite = os.pipe() + p2cread, p2cwrite = _create_pipe() elif isinstance(stdin, int): p2cread = stdin else: @@ -1017,7 +1068,7 @@ if stdout is None: pass elif stdout == PIPE: - c2pread, c2pwrite = os.pipe() + c2pread, c2pwrite = _create_pipe() elif isinstance(stdout, int): c2pwrite = stdout else: @@ -1027,7 +1078,7 @@ if stderr is None: pass elif stderr == PIPE: - errread, errwrite = os.pipe() + errread, errwrite = _create_pipe() elif stderr == STDOUT: errwrite = c2pwrite elif isinstance(stderr, int): @@ -1041,23 +1092,24 @@ errread, errwrite) - def _set_cloexec_flag(self, fd): - try: - cloexec_flag = fcntl.FD_CLOEXEC - except AttributeError: - cloexec_flag = 1 - - old = fcntl.fcntl(fd, fcntl.F_GETFD) - fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) - - def _close_fds(self, but): os.closerange(3, but) os.closerange(but + 1, MAXFD) + def _close_all_but_a_sorted_few_fds(self, fds_to_keep): + # precondition: fds_to_keep must be sorted and unique + start_fd = 3 + for fd in fds_to_keep: + if fd >= start_fd: + os.closerange(start_fd, fd) + start_fd = fd + 1 + if start_fd <= MAXFD: + os.closerange(start_fd, MAXFD) + + def _execute_child(self, args, executable, preexec_fn, close_fds, - cwd, env, universal_newlines, + pass_fds, cwd, env, universal_newlines, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, @@ -1081,10 +1133,9 @@ # For transferring possible exec failure from child to parent. # Data format: "exception name:hex errno:description" # Pickle is not used; it is complex and involves memory allocation. - errpipe_read, errpipe_write = os.pipe() + errpipe_read, errpipe_write = _create_pipe() try: try: - self._set_cloexec_flag(errpipe_write) if _posixsubprocess: # We must avoid complex work that could involve @@ -1105,9 +1156,11 @@ executable_list = tuple( os.path.join(os.fsencode(dir), executable) for dir in os.get_exec_path(env)) + fds_to_keep = set(pass_fds) + fds_to_keep.add(errpipe_write) self.pid = _posixsubprocess.fork_exec( args, executable_list, - close_fds, cwd, env_list, + close_fds, sorted(fds_to_keep), cwd, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, @@ -1161,7 +1214,14 @@ # Close all other fds, if asked for if close_fds: - self._close_fds(but=errpipe_write) + if pass_fds: + fds_to_keep = set(pass_fds) + fds_to_keep.add(errpipe_write) + self._close_all_but_a_sorted_few_fds( + sorted(fds_to_keep)) + else: + self._close_fds(but=errpipe_write) + if cwd is not None: os.chdir(cwd) @@ -1236,7 +1296,11 @@ os.close(errpipe_read) if data: - _eintr_retry_call(os.waitpid, self.pid, 0) + try: + _eintr_retry_call(os.waitpid, self.pid, 0) + except OSError as e: + if e.errno != errno.ECHILD: + raise try: exception_name, hex_errno, err_msg = data.split(b':', 2) except ValueError: @@ -1299,7 +1363,15 @@ """Wait for child process to terminate. Returns returncode attribute.""" if self.returncode is None: - pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0) + try: + pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0) + except OSError as e: + if e.errno != errno.ECHILD: + raise + # This happens if SIGCLD is set to be ignored or waiting + # for child processes has otherwise been disabled for our + # process. This child is dead, we can't get the status. + sts = 0 self._handle_exitstatus(sts) return self.returncode Modified: python/branches/py3k-cdecimal/Lib/sysconfig.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/sysconfig.py (original) +++ python/branches/py3k-cdecimal/Lib/sysconfig.py Sun Jan 2 13:18:37 2011 @@ -25,8 +25,10 @@ 'platstdlib': '{platbase}/lib/python{py_version_short}', 'purelib': '{base}/lib/python{py_version_short}/site-packages', 'platlib': '{platbase}/lib/python{py_version_short}/site-packages', - 'include': '{base}/include/python{py_version_short}', - 'platinclude': '{platbase}/include/python{py_version_short}', + 'include': + '{base}/include/python{py_version_short}{abiflags}', + 'platinclude': + '{platbase}/include/python{py_version_short}{abiflags}', 'scripts': '{base}/bin', 'data': '{base}', }, @@ -317,7 +319,9 @@ """Return the path of the Makefile.""" if _PYTHON_BUILD: return os.path.join(_PROJECT_BASE, "Makefile") - return os.path.join(get_path('stdlib'), "config", "Makefile") + return os.path.join(get_path('stdlib'), + 'config-{}{}'.format(_PY_VERSION_SHORT, sys.abiflags), + 'Makefile') def _init_posix(vars): @@ -471,6 +475,11 @@ _CONFIG_VARS['base'] = _PREFIX _CONFIG_VARS['platbase'] = _EXEC_PREFIX _CONFIG_VARS['projectbase'] = _PROJECT_BASE + try: + _CONFIG_VARS['abiflags'] = sys.abiflags + except AttributeError: + # sys.abiflags may not be defined on all platforms. + _CONFIG_VARS['abiflags'] = '' if os.name in ('nt', 'os2'): _init_non_posix(_CONFIG_VARS) Modified: python/branches/py3k-cdecimal/Lib/tabnanny.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/tabnanny.py (original) +++ python/branches/py3k-cdecimal/Lib/tabnanny.py Sun Jan 2 13:18:37 2011 @@ -264,7 +264,7 @@ return a def format_witnesses(w): - firsts = map(lambda tup: str(tup[0]), w) + firsts = (str(tup[0]) for tup in w) prefix = "at tab size" if len(w) > 1: prefix = prefix + "s" Modified: python/branches/py3k-cdecimal/Lib/telnetlib.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/telnetlib.py (original) +++ python/branches/py3k-cdecimal/Lib/telnetlib.py Sun Jan 2 13:18:37 2011 @@ -236,7 +236,7 @@ """ if self.debuglevel > 0: - print('Telnet(%s,%d):' % (self.host, self.port), end=' ') + print('Telnet(%s,%s):' % (self.host, self.port), end=' ') if args: print(msg % args) else: Modified: python/branches/py3k-cdecimal/Lib/tempfile.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/tempfile.py (original) +++ python/branches/py3k-cdecimal/Lib/tempfile.py Sun Jan 2 13:18:37 2011 @@ -29,6 +29,8 @@ # Imports. +import warnings as _warnings +import sys as _sys import io as _io import os as _os import errno as _errno @@ -617,22 +619,40 @@ """ def __init__(self, suffix="", prefix=template, dir=None): - self.name = mkdtemp(suffix, prefix, dir) self._closed = False + self.name = None # Handle mkdtemp throwing an exception + self.name = mkdtemp(suffix, prefix, dir) + + def __repr__(self): + return "<{} {!r}>".format(self.__class__.__name__, self.name) def __enter__(self): return self.name - def cleanup(self): - if not self._closed: - self._rmtree(self.name) + def cleanup(self, _warn=False): + if self.name and not self._closed: + try: + self._rmtree(self.name) + except (TypeError, AttributeError) as ex: + # Issue #10188: Emit a warning on stderr + # if the directory could not be cleaned + # up due to missing globals + if "None" not in str(ex): + raise + print("ERROR: {!r} while cleaning up {!r}".format(ex, self,), + file=_sys.stderr) + return self._closed = True + if _warn: + self._warn("Implicitly cleaning up {!r}".format(self), + ResourceWarning) def __exit__(self, exc, value, tb): self.cleanup() - __del__ = cleanup - + def __del__(self): + # Issue a ResourceWarning if implicit cleanup needed + self.cleanup(_warn=True) # XXX (ncoghlan): The following code attempts to make # this class tolerant of the module nulling out process @@ -644,6 +664,7 @@ _remove = staticmethod(_os.remove) _rmdir = staticmethod(_os.rmdir) _os_error = _os.error + _warn = _warnings.warn def _rmtree(self, path): # Essentially a stripped down version of shutil.rmtree. We can't Modified: python/branches/py3k-cdecimal/Lib/test/crashers/README ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/crashers/README (original) +++ python/branches/py3k-cdecimal/Lib/test/crashers/README Sun Jan 2 13:18:37 2011 @@ -1,20 +1,16 @@ -This directory only contains tests for outstanding bugs that cause -the interpreter to segfault. Ideally this directory should always -be empty. Sometimes it may not be easy to fix the underlying cause. +This directory only contains tests for outstanding bugs that cause the +interpreter to segfault. Ideally this directory should always be empty, but +sometimes it may not be easy to fix the underlying cause and the bug is deemed +too obscure to invest the effort. Each test should fail when run from the command line: ./python Lib/test/crashers/weakref_in_del.py -Each test should have a link to the bug report: - - # http://python.org/sf/BUG# - -Put as much info into a docstring or comments to help determine -the cause of the failure. Particularly note if the cause is -system or environment dependent and what the variables are. - -Once the crash is fixed, the test case should be moved into an appropriate -test (even if it was originally from the test suite). This ensures the -regression doesn't happen again. And if it does, it should be easier -to track down. +Put as much info into a docstring or comments to help determine the cause of the +failure, as well as a bugs.python.org issue number if it exists. Particularly +note if the cause is system or environment dependent and what the variables are. + +Once the crash is fixed, the test case should be moved into an appropriate test +(even if it was originally from the test suite). This ensures the regression +doesn't happen again. And if it does, it should be easier to track down. Modified: python/branches/py3k-cdecimal/Lib/test/datetimetester.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/datetimetester.py (original) +++ python/branches/py3k-cdecimal/Lib/test/datetimetester.py Sun Jan 2 13:18:37 2011 @@ -38,11 +38,6 @@ INF = float("inf") NAN = float("nan") -# decorator for skipping tests on non-IEEE 754 platforms -requires_IEEE_754 = unittest.skipUnless( - float.__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") - ############################################################################# # module tests @@ -407,7 +402,7 @@ self.assertRaises(ZeroDivisionError, lambda: a / 0.0) self.assertRaises(TypeError, lambda: a / '') - @requires_IEEE_754 + @support.requires_IEEE_754 def test_disallowed_special(self): a = timedelta(42) self.assertRaises(ValueError, a.__mul__, NAN) @@ -589,7 +584,7 @@ self.assertRaises(OverflowError, day.__truediv__, 1e-10) self.assertRaises(OverflowError, day.__truediv__, 9e-10) - @requires_IEEE_754 + @support.requires_IEEE_754 def _test_overflow_special(self): day = timedelta(1) self.assertRaises(OverflowError, day.__mul__, INF) @@ -2513,11 +2508,17 @@ # Check that an invalid tzname result raises an exception. class Badtzname(tzinfo): - def tzname(self, dt): return 42 + tz = 42 + def tzname(self, dt): return self.tz t = time(2, 3, 4, tzinfo=Badtzname()) self.assertEqual(t.strftime("%H:%M:%S"), "02:03:04") self.assertRaises(TypeError, t.strftime, "%Z") + # Issue #6697: + if '_Fast' in str(type(self)): + Badtzname.tz = '\ud800' + self.assertRaises(ValueError, t.strftime, "%Z") + def test_hash_edge_cases(self): # Offsets that overflow a basic time. t1 = self.theclass(0, 1, 2, 3, tzinfo=FixedOffset(1439, "")) Modified: python/branches/py3k-cdecimal/Lib/test/pystone.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/pystone.py (original) +++ python/branches/py3k-cdecimal/Lib/test/pystone.py Sun Jan 2 13:18:37 2011 @@ -72,7 +72,7 @@ Char1Glob = '\0' Char2Glob = '\0' Array1Glob = [0]*51 -Array2Glob = list(map(lambda x: x[:], [Array1Glob]*51)) +Array2Glob = [x[:] for x in [Array1Glob]*51] PtrGlb = None PtrGlbNext = None Modified: python/branches/py3k-cdecimal/Lib/test/regrtest.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/regrtest.py (original) +++ python/branches/py3k-cdecimal/Lib/test/regrtest.py Sun Jan 2 13:18:37 2011 @@ -167,6 +167,7 @@ import tempfile import platform import sysconfig +import logging # Some times __path__ and __file__ are not absolute (e.g. while running from @@ -526,7 +527,7 @@ def tests_and_args(): for test in tests: args_tuple = ( - (test, verbose, quiet, testdir), + (test, verbose, quiet), dict(huntrleaks=huntrleaks, use_resources=use_resources, debug=debug) ) @@ -598,16 +599,15 @@ if trace: # If we're tracing code coverage, then we don't exit with status # if on a false return value from main. - tracer.runctx('runtest(test, verbose, quiet, testdir)', + tracer.runctx('runtest(test, verbose, quiet)', globals=globals(), locals=vars()) else: try: - result = runtest(test, verbose, quiet, - testdir, huntrleaks, debug) + result = runtest(test, verbose, quiet, huntrleaks, debug) accumulate_result(test, result) if verbose3 and result[0] == FAILED: print("Re-running test {} in verbose mode".format(test)) - runtest(test, True, quiet, testdir, huntrleaks, debug) + runtest(test, True, quiet, huntrleaks, debug) except KeyboardInterrupt: interrupted = True break @@ -677,8 +677,7 @@ sys.stdout.flush() try: verbose = True - ok = runtest(test, True, quiet, testdir, - huntrleaks, debug) + ok = runtest(test, True, quiet, huntrleaks, debug) except KeyboardInterrupt: # print a newline separate from the ^C print() @@ -744,14 +743,13 @@ errors="backslashreplace") def runtest(test, verbose, quiet, - testdir=None, huntrleaks=False, debug=False, use_resources=None): + huntrleaks=False, debug=False, use_resources=None): """Run a single test. test -- the name of the test verbose -- if true, print more messages quiet -- if true, don't print 'skipped' messages (probably redundant) test_times -- a list of (time, test_name) pairs - testdir -- test directory huntrleaks -- run multiple times to test for leaks; requires a debug build; a triple corresponding to -R's three arguments @@ -768,8 +766,7 @@ if use_resources is not None: support.use_resources = use_resources try: - return runtest_inner(test, verbose, quiet, - testdir, huntrleaks, debug) + return runtest_inner(test, verbose, quiet, huntrleaks, debug) finally: cleanup_test_droppings(test, verbose) @@ -814,7 +811,8 @@ resources = ('sys.argv', 'cwd', 'sys.stdin', 'sys.stdout', 'sys.stderr', 'os.environ', 'sys.path', 'sys.path_hooks', '__import__', - 'warnings.filters', 'asyncore.socket_map') + 'warnings.filters', 'asyncore.socket_map', + 'logging._handlers', 'logging._handlerList') def get_sys_argv(self): return id(sys.argv), sys.argv, sys.argv[:] @@ -882,6 +880,20 @@ asyncore.close_all(ignore_all=True) asyncore.socket_map.update(saved_map) + def get_logging__handlers(self): + # _handlers is a WeakValueDictionary + return id(logging._handlers), logging._handlers, logging._handlers.copy() + def restore_logging__handlers(self, saved_handlers): + # Can't easily revert the logging state + pass + + def get_logging__handlerList(self): + # _handlerList is a list of weakrefs to handlers + return id(logging._handlerList), logging._handlerList, logging._handlerList[:] + def restore_logging__handlerList(self, saved_handlerList): + # Can't easily revert the logging state + pass + def resource_info(self): for name in self.resources: method_suffix = name.replace('.', '_') @@ -915,10 +927,8 @@ return False -def runtest_inner(test, verbose, quiet, - testdir=None, huntrleaks=False, debug=False): +def runtest_inner(test, verbose, quiet, huntrleaks=False, debug=False): support.unload(test) - testdir = findtestdir(testdir) if verbose: capture_stdout = None else: @@ -1468,16 +1478,7 @@ assert self.isvalid() return self.expected -if __name__ == '__main__': - # findtestdir() gets the dirname out of __file__, so we have to make it - # absolute before changing the working directory. - # For example __file__ may be relative when running trace or profile. - # See issue #9323. - __file__ = os.path.abspath(__file__) - - # sanity check - assert __file__ == os.path.abspath(sys.argv[0]) - +def _make_temp_dir_for_build(TEMPDIR): # When tests are run from the Python build directory, it is best practice # to keep the test files in a subfolder. It eases the cleanup of leftover # files using command "make distclean". @@ -1493,6 +1494,31 @@ TESTCWD = 'test_python_{}'.format(os.getpid()) TESTCWD = os.path.join(TEMPDIR, TESTCWD) + return TEMPDIR, TESTCWD + +if __name__ == '__main__': + # Remove regrtest.py's own directory from the module search path. Despite + # the elimination of implicit relative imports, this is still needed to + # ensure that submodules of the test package do not inappropriately appear + # as top-level modules even when people (or buildbots!) invoke regrtest.py + # directly instead of using the -m switch + mydir = os.path.abspath(os.path.normpath(os.path.dirname(sys.argv[0]))) + i = len(sys.path) + while i >= 0: + i -= 1 + if os.path.abspath(os.path.normpath(sys.path[i])) == mydir: + del sys.path[i] + + # findtestdir() gets the dirname out of __file__, so we have to make it + # absolute before changing the working directory. + # For example __file__ may be relative when running trace or profile. + # See issue #9323. + __file__ = os.path.abspath(__file__) + + # sanity check + assert __file__ == os.path.abspath(sys.argv[0]) + + TEMPDIR, TESTCWD = _make_temp_dir_for_build(TEMPDIR) # Run the tests in a context manager that temporary changes the CWD to a # temporary and writable directory. If it's not possible to create or Modified: python/branches/py3k-cdecimal/Lib/test/script_helper.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/script_helper.py (original) +++ python/branches/py3k-cdecimal/Lib/test/script_helper.py Sun Jan 2 13:18:37 2011 @@ -3,6 +3,7 @@ import sys import os +import re import os.path import tempfile import subprocess @@ -12,7 +13,7 @@ import zipfile from imp import source_from_cache -from test.support import make_legacy_pyc +from test.support import make_legacy_pyc, strip_python_stderr # Executing the interpreter in a subprocess def _assert_python(expected_success, *args, **env_vars): @@ -34,6 +35,7 @@ p.stdout.close() p.stderr.close() rc = p.returncode + err = strip_python_stderr(err) if (rc and expected_success) or (not rc and not expected_success): raise AssertionError( "Process return code is %d, " Modified: python/branches/py3k-cdecimal/Lib/test/support.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/support.py (original) +++ python/branches/py3k-cdecimal/Lib/test/support.py Sun Jan 2 13:18:37 2011 @@ -21,7 +21,7 @@ import imp import time import sysconfig - +import logging.handlers try: import _thread @@ -42,7 +42,8 @@ "set_memlimit", "bigmemtest", "bigaddrspacetest", "BasicTestRunner", "run_unittest", "run_doctest", "threading_setup", "threading_cleanup", "reap_children", "cpython_only", "check_impl_detail", "get_attribute", - "swap_item", "swap_attr", "can_symlink", "skip_unless_symlink"] + "swap_item", "swap_attr", "requires_IEEE_754", + "TestHandler", "Matcher", "can_symlink", "skip_unless_symlink"] class Error(Exception): @@ -366,6 +367,11 @@ return (len(x) > len(y)) - (len(x) < len(y)) return (x > y) - (x < y) +# decorator for skipping tests on non-IEEE 754 platforms +requires_IEEE_754 = unittest.skipUnless( + float.__getformat__("double").startswith("IEEE"), + "test requires IEEE 754 doubles") + is_jython = sys.platform.startswith('java') # Filename used for testing @@ -868,6 +874,9 @@ def captured_stdout(): return captured_output("stdout") +def captured_stderr(): + return captured_output("stderr") + def captured_stdin(): return captured_output("stdin") @@ -1256,27 +1265,6 @@ except: break -try: - from .symlink_support import enable_symlink_privilege -except: - enable_symlink_privilege = lambda: True - -def can_symlink(): - """It's no longer sufficient to test for the presence of symlink in the - os module - on Windows XP and earlier, os.symlink exists but a - NotImplementedError is thrown. - """ - has_symlink = hasattr(os, 'symlink') - is_old_windows = sys.platform == "win32" and sys.getwindowsversion().major < 6 - has_privilege = False if is_old_windows else enable_symlink_privilege() - return has_symlink and (not is_old_windows) and has_privilege - -def skip_unless_symlink(test): - """Skip decorator for tests that require functional symlink""" - selector = can_symlink() - msg = "Requires functional symlink implementation" - return [unittest.skip(msg)(test), test][selector] - @contextlib.contextmanager def swap_attr(obj, attr, new_val): """Temporary swap out an attribute with a new object. @@ -1359,3 +1347,88 @@ if v > 0: args.append('-' + opt * v) return args + +#============================================================ +# Support for assertions about logging. +#============================================================ + +class TestHandler(logging.handlers.BufferingHandler): + def __init__(self, matcher): + # BufferingHandler takes a "capacity" argument + # so as to know when to flush. As we're overriding + # shouldFlush anyway, we can set a capacity of zero. + # You can call flush() manually to clear out the + # buffer. + logging.handlers.BufferingHandler.__init__(self, 0) + self.matcher = matcher + + def shouldFlush(self): + return False + + def emit(self, record): + self.format(record) + self.buffer.append(record.__dict__) + + def matches(self, **kwargs): + """ + Look for a saved dict whose keys/values match the supplied arguments. + """ + result = False + for d in self.buffer: + if self.matcher.matches(d, **kwargs): + result = True + break + return result + +class Matcher(object): + + _partial_matches = ('msg', 'message') + + def matches(self, d, **kwargs): + """ + Try to match a single dict with the supplied arguments. + + Keys whose values are strings and which are in self._partial_matches + will be checked for partial (i.e. substring) matches. You can extend + this scheme to (for example) do regular expression matching, etc. + """ + result = True + for k in kwargs: + v = kwargs[k] + dv = d.get(k) + if not self.match_value(k, dv, v): + result = False + break + return result + + def match_value(self, k, dv, v): + """ + Try to match a single stored value (dv) with a supplied value (v). + """ + if type(v) != type(dv): + result = False + elif type(dv) is not str or k not in self._partial_matches: + result = (v == dv) + else: + result = dv.find(v) >= 0 + return result + + +_can_symlink = None +def can_symlink(): + global _can_symlink + if _can_symlink is not None: + return _can_symlink + try: + os.symlink(TESTFN, TESTFN + "can_symlink") + can = True + except (OSError, NotImplementedError): + can = False + _can_symlink = can + return can + +def skip_unless_symlink(test): + """Skip decorator for tests that require functional symlink""" + ok = can_symlink() + msg = "Requires functional symlink implementation" + return test if ok else unittest.skip(msg)(test) Deleted: python/branches/py3k-cdecimal/Lib/test/symlink_support.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/symlink_support.py Sun Jan 2 13:18:37 2011 +++ (empty file) @@ -1,206 +0,0 @@ -""" -A module built to test if the current process has the privilege to -create symlinks on Windows. -""" - -# allow script to run natively under python 2.6+ -from __future__ import print_function - -import ctypes -from ctypes import wintypes - -GetCurrentProcess = ctypes.windll.kernel32.GetCurrentProcess -GetCurrentProcess.restype = wintypes.HANDLE -OpenProcessToken = ctypes.windll.advapi32.OpenProcessToken -OpenProcessToken.argtypes = (wintypes.HANDLE, wintypes.DWORD, - ctypes.POINTER(wintypes.HANDLE)) -OpenProcessToken.restype = wintypes.BOOL - -class LUID(ctypes.Structure): - _fields_ = [ - ('low_part', wintypes.DWORD), - ('high_part', wintypes.LONG), - ] - - def __eq__(self, other): - return ( - self.high_part == other.high_part and - self.low_part == other.low_part - ) - - def __ne__(self, other): - return not (self==other) - -LookupPrivilegeValue = ctypes.windll.advapi32.LookupPrivilegeValueW -LookupPrivilegeValue.argtypes = ( - wintypes.LPWSTR, # system name - wintypes.LPWSTR, # name - ctypes.POINTER(LUID), - ) -LookupPrivilegeValue.restype = wintypes.BOOL - -class TOKEN_INFORMATION_CLASS: - TokenUser = 1 - TokenGroups = 2 - TokenPrivileges = 3 - # ... see http://msdn.microsoft.com/en-us/library/aa379626%28VS.85%29.aspx - -SE_PRIVILEGE_ENABLED_BY_DEFAULT = (0x00000001) -SE_PRIVILEGE_ENABLED = (0x00000002) -SE_PRIVILEGE_REMOVED = (0x00000004) -SE_PRIVILEGE_USED_FOR_ACCESS = (0x80000000) - -class LUID_AND_ATTRIBUTES(ctypes.Structure): - _fields_ = [ - ('LUID', LUID), - ('attributes', wintypes.DWORD), - ] - - def is_enabled(self): - return bool(self.attributes & SE_PRIVILEGE_ENABLED) - - def enable(self): - self.attributes |= SE_PRIVILEGE_ENABLED - - def get_name(self): - size = wintypes.DWORD(10240) - buf = ctypes.create_unicode_buffer(size.value) - res = LookupPrivilegeName(None, self.LUID, buf, size) - if res == 0: - raise RuntimeError - return buf[:size.value] - - def __str__(self): - name = self.name - fmt = ['{name}', '{name} (enabled)'][self.is_enabled()] - return fmt.format(**vars()) - -LookupPrivilegeName = ctypes.windll.advapi32.LookupPrivilegeNameW -LookupPrivilegeName.argtypes = ( - wintypes.LPWSTR, # lpSystemName - ctypes.POINTER(LUID), # lpLuid - wintypes.LPWSTR, # lpName - ctypes.POINTER(wintypes.DWORD), #cchName - ) -LookupPrivilegeName.restype = wintypes.BOOL - -class TOKEN_PRIVILEGES(ctypes.Structure): - _fields_ = [ - ('count', wintypes.DWORD), - ('privileges', LUID_AND_ATTRIBUTES*0), - ] - - def get_array(self): - array_type = LUID_AND_ATTRIBUTES*self.count - privileges = ctypes.cast(self.privileges, - ctypes.POINTER(array_type)).contents - return privileges - - def __iter__(self): - return iter(self.get_array()) - -PTOKEN_PRIVILEGES = ctypes.POINTER(TOKEN_PRIVILEGES) - -GetTokenInformation = ctypes.windll.advapi32.GetTokenInformation -GetTokenInformation.argtypes = [ - wintypes.HANDLE, # TokenHandle - ctypes.c_uint, # TOKEN_INFORMATION_CLASS value - ctypes.c_void_p, # TokenInformation - wintypes.DWORD, # TokenInformationLength - ctypes.POINTER(wintypes.DWORD), # ReturnLength - ] -GetTokenInformation.restype = wintypes.BOOL - -# http://msdn.microsoft.com/en-us/library/aa375202%28VS.85%29.aspx -AdjustTokenPrivileges = ctypes.windll.advapi32.AdjustTokenPrivileges -AdjustTokenPrivileges.restype = wintypes.BOOL -AdjustTokenPrivileges.argtypes = [ - wintypes.HANDLE, # TokenHandle - wintypes.BOOL, # DisableAllPrivileges - PTOKEN_PRIVILEGES, # NewState (optional) - wintypes.DWORD, # BufferLength of PreviousState - PTOKEN_PRIVILEGES, # PreviousState (out, optional) - ctypes.POINTER(wintypes.DWORD), # ReturnLength - ] - -def get_process_token(): - "Get the current process token" - token = wintypes.HANDLE() - TOKEN_ALL_ACCESS = 0xf01ff - res = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, token) - if not res > 0: - raise RuntimeError("Couldn't get process token") - return token - -def get_symlink_luid(): - "Get the LUID for the SeCreateSymbolicLinkPrivilege" - symlink_luid = LUID() - res = LookupPrivilegeValue(None, "SeCreateSymbolicLinkPrivilege", - symlink_luid) - if not res > 0: - raise RuntimeError("Couldn't lookup privilege value") - return symlink_luid - -def get_privilege_information(): - "Get all privileges associated with the current process." - # first call with zero length to determine what size buffer we need - - return_length = wintypes.DWORD() - params = [ - get_process_token(), - TOKEN_INFORMATION_CLASS.TokenPrivileges, - None, - 0, - return_length, - ] - - res = GetTokenInformation(*params) - - # assume we now have the necessary length in return_length - - buffer = ctypes.create_string_buffer(return_length.value) - params[2] = buffer - params[3] = return_length.value - - res = GetTokenInformation(*params) - assert res > 0, "Error in second GetTokenInformation (%d)" % res - - privileges = ctypes.cast(buffer, ctypes.POINTER(TOKEN_PRIVILEGES)).contents - return privileges - -def report_privilege_information(): - "Report all privilege information assigned to the current process." - privileges = get_privilege_information() - print("found {0} privileges".format(privileges.count)) - tuple(map(print, privileges)) - -def enable_symlink_privilege(): - """ - Try to assign the symlink privilege to the current process token. - Return True if the assignment is successful. - """ - # create a space in memory for a TOKEN_PRIVILEGES structure - # with one element - size = ctypes.sizeof(TOKEN_PRIVILEGES) - size += ctypes.sizeof(LUID_AND_ATTRIBUTES) - buffer = ctypes.create_string_buffer(size) - tp = ctypes.cast(buffer, ctypes.POINTER(TOKEN_PRIVILEGES)).contents - tp.count = 1 - tp.get_array()[0].enable() - tp.get_array()[0].LUID = get_symlink_luid() - token = get_process_token() - res = AdjustTokenPrivileges(token, False, tp, 0, None, None) - if res == 0: - raise RuntimeError("Error in AdjustTokenPrivileges") - - ERROR_NOT_ALL_ASSIGNED = 1300 - return ctypes.windll.kernel32.GetLastError() != ERROR_NOT_ALL_ASSIGNED - -def main(): - assigned = enable_symlink_privilege() - msg = ['failure', 'success'][assigned] - - print("Symlink privilege assignment completed with {0}".format(msg)) - -if __name__ == '__main__': - main() Modified: python/branches/py3k-cdecimal/Lib/test/test_abc.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_abc.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_abc.py Sun Jan 2 13:18:37 2011 @@ -192,8 +192,8 @@ def test_register_non_class(self): class A(metaclass=abc.ABCMeta): pass - self.assertRaisesRegexp(TypeError, "Can only register classes", - A.register, 4) + self.assertRaisesRegex(TypeError, "Can only register classes", + A.register, 4) def test_registration_transitiveness(self): class A(metaclass=abc.ABCMeta): Modified: python/branches/py3k-cdecimal/Lib/test/test_argparse.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_argparse.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_argparse.py Sun Jan 2 13:18:37 2011 @@ -1708,7 +1708,8 @@ def assertArgumentParserError(self, *args, **kwargs): self.assertRaises(ArgumentParserError, *args, **kwargs) - def _get_parser(self, subparser_help=False, prefix_chars=None): + def _get_parser(self, subparser_help=False, prefix_chars=None, + aliases=False): # create a parser with a subparsers argument if prefix_chars: parser = ErrorRaisingArgumentParser( @@ -1724,13 +1725,21 @@ 'bar', type=float, help='bar help') # check that only one subparsers argument can be added - subparsers = parser.add_subparsers(help='command help') + subparsers_kwargs = {} + if aliases: + subparsers_kwargs['metavar'] = 'COMMAND' + subparsers_kwargs['title'] = 'commands' + else: + subparsers_kwargs['help'] = 'command help' + subparsers = parser.add_subparsers(**subparsers_kwargs) self.assertArgumentParserError(parser.add_subparsers) # add first sub-parser parser1_kwargs = dict(description='1 description') if subparser_help: parser1_kwargs['help'] = '1 help' + if aliases: + parser1_kwargs['aliases'] = ['1alias1', '1alias2'] parser1 = subparsers.add_parser('1', **parser1_kwargs) parser1.add_argument('-w', type=int, help='w help') parser1.add_argument('x', choices='abc', help='x help') @@ -1947,6 +1956,44 @@ -y {1,2,3} y help ''')) + def test_alias_invocation(self): + parser = self._get_parser(aliases=True) + self.assertEqual( + parser.parse_known_args('0.5 1alias1 b'.split()), + (NS(foo=False, bar=0.5, w=None, x='b'), []), + ) + self.assertEqual( + parser.parse_known_args('0.5 1alias2 b'.split()), + (NS(foo=False, bar=0.5, w=None, x='b'), []), + ) + + def test_error_alias_invocation(self): + parser = self._get_parser(aliases=True) + self.assertArgumentParserError(parser.parse_args, + '0.5 1alias3 b'.split()) + + def test_alias_help(self): + parser = self._get_parser(aliases=True, subparser_help=True) + self.maxDiff = None + self.assertEqual(parser.format_help(), textwrap.dedent("""\ + usage: PROG [-h] [--foo] bar COMMAND ... + + main description + + positional arguments: + bar bar help + + optional arguments: + -h, --help show this help message and exit + --foo foo help + + commands: + COMMAND + 1 (1alias1, 1alias2) + 1 help + 2 2 help + """)) + # ============ # Groups tests # ============ @@ -4315,7 +4362,7 @@ items = [ name for name, value in vars(argparse).items() - if not name.startswith("_") + if not (name.startswith("_") or name == 'ngettext') if not inspect.ismodule(value) ] self.assertEqual(sorted(items), sorted(argparse.__all__)) Modified: python/branches/py3k-cdecimal/Lib/test/test_array.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_array.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_array.py Sun Jan 2 13:18:37 2011 @@ -22,7 +22,7 @@ class ArraySubclassWithKwargs(array.array): def __init__(self, typecode, newarg=None): - array.array.__init__(typecode) + array.array.__init__(self, typecode) tests = [] # list to accumulate all tests typecodes = "ubBhHiIlLfd" @@ -504,6 +504,12 @@ array.array(self.typecode) ) + a = 5 * array.array(self.typecode, self.example[:1]) + self.assertEqual( + a, + array.array(self.typecode, [a[0]] * 5) + ) + self.assertRaises(TypeError, a.__mul__, "bad") def test_imul(self): Modified: python/branches/py3k-cdecimal/Lib/test/test_asyncore.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_asyncore.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_asyncore.py Sun Jan 2 13:18:37 2011 @@ -312,8 +312,8 @@ d = asyncore.dispatcher(socket.socket()) # make sure the error message no longer refers to the socket # object but the dispatcher instance instead - self.assertRaisesRegexp(AttributeError, 'dispatcher instance', - getattr, d, 'foo') + self.assertRaisesRegex(AttributeError, 'dispatcher instance', + getattr, d, 'foo') # cheap inheritance with the underlying socket is supposed # to still work but a DeprecationWarning is expected with warnings.catch_warnings(record=True) as w: Modified: python/branches/py3k-cdecimal/Lib/test/test_bool.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_bool.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_bool.py Sun Jan 2 13:18:37 2011 @@ -174,8 +174,8 @@ self.assertIs(hasattr([], "wobble"), False) def test_callable(self): - self.assertIs(hasattr(len, '__call__'), True) - self.assertIs(hasattr(1, '__call__'), False) + self.assertIs(callable(len), True) + self.assertIs(callable(1), False) def test_isinstance(self): self.assertIs(isinstance(True, bool), True) Modified: python/branches/py3k-cdecimal/Lib/test/test_builtin.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_builtin.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_builtin.py Sun Jan 2 13:18:37 2011 @@ -6,6 +6,7 @@ import warnings import collections import io +import ast import types import builtins import random @@ -207,22 +208,39 @@ self.assertTrue(isinstance(x, int)) self.assertEqual(-x, sys.maxsize+1) - # XXX(nnorwitz): This test case for callable should probably be removed. def test_callable(self): - self.assertTrue(hasattr(len, '__call__')) + self.assertTrue(callable(len)) + self.assertFalse(callable("a")) + self.assertTrue(callable(callable)) + self.assertTrue(callable(lambda x, y: x + y)) + self.assertFalse(callable(__builtins__)) def f(): pass - self.assertTrue(hasattr(f, '__call__')) - class C: + self.assertTrue(callable(f)) + + class C1: def meth(self): pass - self.assertTrue(hasattr(C, '__call__')) - x = C() - self.assertTrue(hasattr(x.meth, '__call__')) - self.assertTrue(not hasattr(x, '__call__')) - class D(C): + self.assertTrue(callable(C1)) + c = C1() + self.assertTrue(callable(c.meth)) + self.assertFalse(callable(c)) + + # __call__ is looked up on the class, not the instance + c.__call__ = None + self.assertFalse(callable(c)) + c.__call__ = lambda self: 0 + self.assertFalse(callable(c)) + del c.__call__ + self.assertFalse(callable(c)) + + class C2(object): def __call__(self): pass - y = D() - self.assertTrue(hasattr(y, '__call__')) - y() + c2 = C2() + self.assertTrue(callable(c2)) + c2.__call__ = None + self.assertTrue(callable(c2)) + class C3(C2): pass + c3 = C3() + self.assertTrue(callable(c3)) def test_chr(self): self.assertEqual(chr(32), ' ') @@ -268,6 +286,34 @@ self.assertRaises(TypeError, compile, chr(0), 'f', 'exec') self.assertRaises(ValueError, compile, str('a = 1'), 'f', 'bad') + # test the optimize argument + + codestr = '''def f(): + """doc""" + try: + assert False + except AssertionError: + return (True, f.__doc__) + else: + return (False, f.__doc__) + ''' + def f(): """doc""" + values = [(-1, __debug__, f.__doc__), + (0, True, 'doc'), + (1, False, 'doc'), + (2, False, None)] + for optval, debugval, docstring in values: + # test both direct compilation and compilation via AST + codeobjs = [] + codeobjs.append(compile(codestr, "", "exec", optimize=optval)) + tree = ast.parse(codestr) + codeobjs.append(compile(tree, "", "exec", optimize=optval)) + for code in codeobjs: + ns = {} + exec(code, ns) + rv = ns['f']() + self.assertEqual(rv, (debugval, docstring)) + def test_delattr(self): sys.spam = 1 delattr(sys, 'spam') Modified: python/branches/py3k-cdecimal/Lib/test/test_calendar.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_calendar.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_calendar.py Sun Jan 2 13:18:37 2011 @@ -430,6 +430,26 @@ with self.assertRaises(calendar.IllegalMonthError): calendar.monthrange(2004, 13) +class LeapdaysTestCase(unittest.TestCase): + def test_no_range(self): + # test when no range i.e. two identical years as args + self.assertEqual(calendar.leapdays(2010,2010), 0) + + def test_no_leapdays(self): + # test when no leap years in range + self.assertEqual(calendar.leapdays(2010,2011), 0) + + def test_no_leapdays_upper_boundary(self): + # test no leap years in range, when upper boundary is a leap year + self.assertEqual(calendar.leapdays(2010,2012), 0) + + def test_one_leapday_lower_boundary(self): + # test when one leap year in range, lower boundary is leap year + self.assertEqual(calendar.leapdays(2012,2013), 1) + + def test_several_leapyears_in_range(self): + self.assertEqual(calendar.leapdays(1997,2020), 5) + def test_main(): support.run_unittest( @@ -439,6 +459,7 @@ SundayTestCase, TimegmTestCase, MonthRangeTestCase, + LeapdaysTestCase, ) Modified: python/branches/py3k-cdecimal/Lib/test/test_cfgparser.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_cfgparser.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_cfgparser.py Sun Jan 2 13:18:37 2011 @@ -2,8 +2,10 @@ import configparser import io import os -import unittest +import sys import textwrap +import unittest +import warnings from test import support @@ -28,10 +30,12 @@ allow_no_value = False delimiters = ('=', ':') comment_prefixes = (';', '#') + inline_comment_prefixes = (';', '#') empty_lines_in_values = True dict_type = configparser._default_dict strict = False default_section = configparser.DEFAULTSECT + interpolation = configparser._UNSET def newconfig(self, defaults=None): arguments = dict( @@ -39,12 +43,15 @@ allow_no_value=self.allow_no_value, delimiters=self.delimiters, comment_prefixes=self.comment_prefixes, + inline_comment_prefixes=self.inline_comment_prefixes, empty_lines_in_values=self.empty_lines_in_values, dict_type=self.dict_type, strict=self.strict, default_section=self.default_section, + interpolation=self.interpolation, ) - return self.config_class(**arguments) + instance = self.config_class(**arguments) + return instance def fromstring(self, string, defaults=None): cf = self.newconfig(defaults) @@ -68,12 +75,16 @@ if self.allow_no_value: E.append('NoValue') E.sort() + F = [('baz', 'qwe'), ('foo', 'bar3')] # API access L = cf.sections() L.sort() eq = self.assertEqual eq(L, E) + L = cf.items('Spacey Bar From The Beginning') + L.sort() + eq(L, F) # mapping access L = [section for section in cf] @@ -81,6 +92,15 @@ E.append(self.default_section) E.sort() eq(L, E) + L = cf['Spacey Bar From The Beginning'].items() + L = sorted(list(L)) + eq(L, F) + L = cf.items() + L = sorted(list(L)) + self.assertEqual(len(L), len(E)) + for name, section in L: + eq(name, section.name) + eq(cf.defaults(), cf[self.default_section]) # The use of spaces in the section names serves as a # regression test for SourceForge bug #583248: @@ -100,6 +120,7 @@ self.assertAlmostEqual(cf.getfloat('Types', 'float'), 0.44) eq(cf.get('Types', 'float'), "0.44") eq(cf.getboolean('Types', 'boolean'), False) + eq(cf.get('Types', '123'), 'strange but acceptable') if self.allow_no_value: eq(cf.get('NoValue', 'option-without-value'), None) @@ -117,15 +138,21 @@ eq(cf.getint('Types', 'int', fallback=18), 42) eq(cf.getint('Types', 'no-such-int', fallback=18), 18) eq(cf.getint('Types', 'no-such-int', fallback="18"), "18") # sic! + with self.assertRaises(configparser.NoOptionError): + cf.getint('Types', 'no-such-int') self.assertAlmostEqual(cf.getfloat('Types', 'float', fallback=0.0), 0.44) self.assertAlmostEqual(cf.getfloat('Types', 'no-such-float', fallback=0.0), 0.0) eq(cf.getfloat('Types', 'no-such-float', fallback="0.0"), "0.0") # sic! + with self.assertRaises(configparser.NoOptionError): + cf.getfloat('Types', 'no-such-float') eq(cf.getboolean('Types', 'boolean', fallback=True), False) eq(cf.getboolean('Types', 'no-such-boolean', fallback="yes"), "yes") # sic! eq(cf.getboolean('Types', 'no-such-boolean', fallback=True), True) + with self.assertRaises(configparser.NoOptionError): + cf.getboolean('Types', 'no-such-boolean') eq(cf.getboolean('No Such Types', 'boolean', fallback=True), True) if self.allow_no_value: eq(cf.get('NoValue', 'option-without-value', fallback=False), None) @@ -152,11 +179,65 @@ 'this line is much, much longer than my editor\nlikes it.') if self.allow_no_value: eq(cf['NoValue']['option-without-value'], None) + # test vars= and fallback= + eq(cf['Foo Bar'].get('foo', 'baz'), 'bar1') + eq(cf['Foo Bar'].get('foo', fallback='baz'), 'bar1') + eq(cf['Foo Bar'].get('foo', vars={'foo': 'baz'}), 'baz') + with self.assertRaises(KeyError): + cf['No Such Foo Bar']['foo'] + with self.assertRaises(KeyError): + cf['Foo Bar']['no-such-foo'] + with self.assertRaises(KeyError): + cf['No Such Foo Bar'].get('foo', fallback='baz') + eq(cf['Foo Bar'].get('no-such-foo', 'baz'), 'baz') + eq(cf['Foo Bar'].get('no-such-foo', fallback='baz'), 'baz') + eq(cf['Foo Bar'].get('no-such-foo'), None) + eq(cf['Spacey Bar'].get('foo', None), 'bar2') + eq(cf['Spacey Bar'].get('foo', fallback=None), 'bar2') + with self.assertRaises(KeyError): + cf['No Such Spacey Bar'].get('foo', None) + eq(cf['Types'].getint('int', 18), 42) + eq(cf['Types'].getint('int', fallback=18), 42) + eq(cf['Types'].getint('no-such-int', 18), 18) + eq(cf['Types'].getint('no-such-int', fallback=18), 18) + eq(cf['Types'].getint('no-such-int', "18"), "18") # sic! + eq(cf['Types'].getint('no-such-int', fallback="18"), "18") # sic! + eq(cf['Types'].getint('no-such-int'), None) + self.assertAlmostEqual(cf['Types'].getfloat('float', 0.0), 0.44) + self.assertAlmostEqual(cf['Types'].getfloat('float', + fallback=0.0), 0.44) + self.assertAlmostEqual(cf['Types'].getfloat('no-such-float', 0.0), 0.0) + self.assertAlmostEqual(cf['Types'].getfloat('no-such-float', + fallback=0.0), 0.0) + eq(cf['Types'].getfloat('no-such-float', "0.0"), "0.0") # sic! + eq(cf['Types'].getfloat('no-such-float', fallback="0.0"), "0.0") # sic! + eq(cf['Types'].getfloat('no-such-float'), None) + eq(cf['Types'].getboolean('boolean', True), False) + eq(cf['Types'].getboolean('boolean', fallback=True), False) + eq(cf['Types'].getboolean('no-such-boolean', "yes"), "yes") # sic! + eq(cf['Types'].getboolean('no-such-boolean', fallback="yes"), + "yes") # sic! + eq(cf['Types'].getboolean('no-such-boolean', True), True) + eq(cf['Types'].getboolean('no-such-boolean', fallback=True), True) + eq(cf['Types'].getboolean('no-such-boolean'), None) + if self.allow_no_value: + eq(cf['NoValue'].get('option-without-value', False), None) + eq(cf['NoValue'].get('option-without-value', fallback=False), None) + eq(cf['NoValue'].get('no-such-option-without-value', False), False) + eq(cf['NoValue'].get('no-such-option-without-value', + fallback=False), False) + + # Make sure the right things happen for remove_section() and + # remove_option(); added to include check for SourceForge bug #123324. - # Make sure the right things happen for remove_option(); - # added to include check for SourceForge bug #123324: + cf[self.default_section]['this_value'] = '1' + cf[self.default_section]['that_value'] = '2' - # API acceess + # API access + self.assertTrue(cf.remove_section('Spaces')) + self.assertFalse(cf.has_option('Spaces', 'key with spaces')) + self.assertFalse(cf.remove_section('Spaces')) + self.assertFalse(cf.remove_section(self.default_section)) self.assertTrue(cf.remove_option('Foo Bar', 'foo'), "remove_option() failed to report existence of option") self.assertFalse(cf.has_option('Foo Bar', 'foo'), @@ -164,6 +245,11 @@ self.assertFalse(cf.remove_option('Foo Bar', 'foo'), "remove_option() failed to report non-existence of option" " that was removed") + self.assertTrue(cf.has_option('Foo Bar', 'this_value')) + self.assertFalse(cf.remove_option('Foo Bar', 'this_value')) + self.assertTrue(cf.remove_option(self.default_section, 'this_value')) + self.assertFalse(cf.has_option('Foo Bar', 'this_value')) + self.assertFalse(cf.remove_option(self.default_section, 'this_value')) with self.assertRaises(configparser.NoSectionError) as cm: cf.remove_option('No Such Section', 'foo') @@ -173,13 +259,29 @@ 'this line is much, much longer than my editor\nlikes it.') # mapping access + del cf['Types'] + self.assertFalse('Types' in cf) + with self.assertRaises(KeyError): + del cf['Types'] + with self.assertRaises(ValueError): + del cf[self.default_section] del cf['Spacey Bar']['foo'] self.assertFalse('foo' in cf['Spacey Bar']) with self.assertRaises(KeyError): del cf['Spacey Bar']['foo'] + self.assertTrue('that_value' in cf['Spacey Bar']) + with self.assertRaises(KeyError): + del cf['Spacey Bar']['that_value'] + del cf[self.default_section]['that_value'] + self.assertFalse('that_value' in cf['Spacey Bar']) + with self.assertRaises(KeyError): + del cf[self.default_section]['that_value'] with self.assertRaises(KeyError): del cf['No Such Section']['foo'] + # Don't add new asserts below in this method as most of the options + # and sections are now removed. + def test_basic(self): config_string = """\ [Foo Bar] @@ -208,6 +310,7 @@ int {0[1]} 42 float {0[0]} 0.44 boolean {0[0]} NO +123 {0[1]} strange but acceptable """.format(self.delimiters, self.comment_prefixes) if self.allow_no_value: config_string += ( @@ -280,6 +383,7 @@ "int": 42, "float": 0.44, "boolean": False, + 123: "strange but acceptable", }, } if self.allow_no_value: @@ -292,6 +396,11 @@ cf.read_dict(config) self.basic_test(cf) if self.strict: + with self.assertRaises(configparser.DuplicateSectionError): + cf.read_dict({ + '1': {'key': 'value'}, + 1: {'key2': 'value2'}, + }) with self.assertRaises(configparser.DuplicateOptionError): cf.read_dict({ "Duplicate Options Here": { @@ -301,13 +410,16 @@ }) else: cf.read_dict({ + 'section': {'key': 'value'}, + 'SECTION': {'key2': 'value2'}, + }) + cf.read_dict({ "Duplicate Options Here": { 'option': 'with a value', 'OPTION': 'with another value', }, }) - def test_case_sensitivity(self): cf = self.newconfig() cf.add_section("A") @@ -325,6 +437,7 @@ # section names are case-sensitive cf.set("b", "A", "value") self.assertTrue(cf.has_option("a", "b")) + self.assertFalse(cf.has_option("b", "b")) cf.set("A", "A-B", "A-B value") for opt in ("a-b", "A-b", "a-B", "A-B"): self.assertTrue( @@ -357,7 +470,7 @@ L = [section for section in cf] L.sort() eq = self.assertEqual - elem_eq = self.assertItemsEqual + elem_eq = self.assertCountEqual eq(L, sorted(["A", "B", self.default_section, "a"])) eq(cf["a"].keys(), {"b"}) eq(cf["a"]["b"], "value", @@ -541,32 +654,36 @@ ) cf = self.fromstring(config_string) - output = io.StringIO() - cf.write(output) - expect_string = ( - "[{default_section}]\n" - "foo {equals} another very\n" - "\tlong line\n" - "\n" - "[Long Line]\n" - "foo {equals} this line is much, much longer than my editor\n" - "\tlikes it.\n" - "\n" - "[Long Line - With Comments!]\n" - "test {equals} we\n" - "\talso\n" - "\tcomments\n" - "\tmultiline\n" - "\n".format(equals=self.delimiters[0], - default_section=self.default_section) - ) - if self.allow_no_value: - expect_string += ( - "[Valueless]\n" - "option-without-value\n" + for space_around_delimiters in (True, False): + output = io.StringIO() + cf.write(output, space_around_delimiters=space_around_delimiters) + delimiter = self.delimiters[0] + if space_around_delimiters: + delimiter = " {} ".format(delimiter) + expect_string = ( + "[{default_section}]\n" + "foo{equals}another very\n" + "\tlong line\n" + "\n" + "[Long Line]\n" + "foo{equals}this line is much, much longer than my editor\n" + "\tlikes it.\n" "\n" + "[Long Line - With Comments!]\n" + "test{equals}we\n" + "\talso\n" + "\tcomments\n" + "\tmultiline\n" + "\n".format(equals=delimiter, + default_section=self.default_section) ) - self.assertEqual(output.getvalue(), expect_string) + if self.allow_no_value: + expect_string += ( + "[Valueless]\n" + "option-without-value\n" + "\n" + ) + self.assertEqual(output.getvalue(), expect_string) def test_set_string_types(self): cf = self.fromstring("[sect]\n" @@ -635,15 +752,17 @@ "name{equals}%(reference)s\n".format(equals=self.delimiters[0])) def check_items_config(self, expected): - cf = self.fromstring( - "[section]\n" - "name {0[0]} value\n" - "key{0[1]} |%(name)s| \n" - "getdefault{0[1]} |%(default)s|\n".format(self.delimiters), - defaults={"default": ""}) - L = list(cf.items("section")) + cf = self.fromstring(""" + [section] + name {0[0]} %(value)s + key{0[1]} |%(name)s| + getdefault{0[1]} |%(default)s| + """.format(self.delimiters), defaults={"default": ""}) + L = list(cf.items("section", vars={'value': 'value'})) L.sort() self.assertEqual(L, expected) + with self.assertRaises(configparser.NoSectionError): + cf.items("no such section") class StrictTestCase(BasicTestCase): @@ -655,11 +774,6 @@ config_class = configparser.ConfigParser def test_interpolation(self): - rawval = { - configparser.ConfigParser: ("something %(with11)s " - "lots of interpolation (11 steps)"), - configparser.SafeConfigParser: "%(with1)s", - } cf = self.get_interpolation_config() eq = self.assertEqual eq(cf.get("Foo", "bar"), "something with interpolation (1 step)") @@ -668,52 +782,107 @@ eq(cf.get("Foo", "bar10"), "something with lots of interpolation (10 steps)") e = self.get_error(cf, configparser.InterpolationDepthError, "Foo", "bar11") - self.assertEqual(e.args, ("bar11", "Foo", rawval[self.config_class])) + if self.interpolation == configparser._UNSET: + self.assertEqual(e.args, ("bar11", "Foo", "%(with1)s")) + elif isinstance(self.interpolation, configparser.LegacyInterpolation): + self.assertEqual(e.args, ("bar11", "Foo", + "something %(with11)s lots of interpolation (11 steps)")) def test_interpolation_missing_value(self): - rawval = { - configparser.ConfigParser: '%(reference)s', - configparser.SafeConfigParser: '', - } cf = self.get_interpolation_config() e = self.get_error(cf, configparser.InterpolationMissingOptionError, "Interpolation Error", "name") self.assertEqual(e.reference, "reference") self.assertEqual(e.section, "Interpolation Error") self.assertEqual(e.option, "name") - self.assertEqual(e.args, ('name', 'Interpolation Error', - rawval[self.config_class], 'reference')) + if self.interpolation == configparser._UNSET: + self.assertEqual(e.args, ('name', 'Interpolation Error', + '', 'reference')) + elif isinstance(self.interpolation, configparser.LegacyInterpolation): + self.assertEqual(e.args, ('name', 'Interpolation Error', + '%(reference)s', 'reference')) def test_items(self): self.check_items_config([('default', ''), ('getdefault', '||'), ('key', '|value|'), - ('name', 'value')]) + ('name', 'value'), + ('value', 'value')]) + + def test_safe_interpolation(self): + # See http://www.python.org/sf/511737 + cf = self.fromstring("[section]\n" + "option1{eq}xxx\n" + "option2{eq}%(option1)s/xxx\n" + "ok{eq}%(option1)s/%%s\n" + "not_ok{eq}%(option2)s/%%s".format( + eq=self.delimiters[0])) + self.assertEqual(cf.get("section", "ok"), "xxx/%s") + if self.interpolation == configparser._UNSET: + self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s") + elif isinstance(self.interpolation, configparser.LegacyInterpolation): + with self.assertRaises(TypeError): + cf.get("section", "not_ok") + + def test_set_malformatted_interpolation(self): + cf = self.fromstring("[sect]\n" + "option1{eq}foo\n".format(eq=self.delimiters[0])) + + self.assertEqual(cf.get('sect', "option1"), "foo") + + self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo") + self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%") + self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo") + + self.assertEqual(cf.get('sect', "option1"), "foo") + + # bug #5741: double percents are *not* malformed + cf.set("sect", "option2", "foo%%bar") + self.assertEqual(cf.get("sect", "option2"), "foo%bar") def test_set_nonstring_types(self): + cf = self.fromstring("[sect]\n" + "option1{eq}foo\n".format(eq=self.delimiters[0])) + # Check that we get a TypeError when setting non-string values + # in an existing section: + self.assertRaises(TypeError, cf.set, "sect", "option1", 1) + self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0) + self.assertRaises(TypeError, cf.set, "sect", "option1", object()) + self.assertRaises(TypeError, cf.set, "sect", "option2", 1) + self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0) + self.assertRaises(TypeError, cf.set, "sect", "option2", object()) + self.assertRaises(TypeError, cf.set, "sect", 123, "invalid opt name!") + self.assertRaises(TypeError, cf.add_section, 123) + + def test_add_section_default(self): cf = self.newconfig() - cf.add_section('non-string') - cf.set('non-string', 'int', 1) - cf.set('non-string', 'list', [0, 1, 1, 2, 3, 5, 8, 13, '%(']) - cf.set('non-string', 'dict', {'pi': 3.14159, '%(': 1, - '%(list)': '%(list)'}) - cf.set('non-string', 'string_with_interpolation', '%(list)s') - self.assertEqual(cf.get('non-string', 'int', raw=True), 1) - self.assertRaises(TypeError, cf.get, 'non-string', 'int') - self.assertEqual(cf.get('non-string', 'list', raw=True), - [0, 1, 1, 2, 3, 5, 8, 13, '%(']) - self.assertRaises(TypeError, cf.get, 'non-string', 'list') - self.assertEqual(cf.get('non-string', 'dict', raw=True), - {'pi': 3.14159, '%(': 1, '%(list)': '%(list)'}) - self.assertRaises(TypeError, cf.get, 'non-string', 'dict') - self.assertEqual(cf.get('non-string', 'string_with_interpolation', - raw=True), '%(list)s') - self.assertRaises(ValueError, cf.get, 'non-string', - 'string_with_interpolation', raw=False) + self.assertRaises(ValueError, cf.add_section, self.default_section) + +class ConfigParserTestCaseLegacyInterpolation(ConfigParserTestCase): + config_class = configparser.ConfigParser + interpolation = configparser.LegacyInterpolation() + + def test_set_malformatted_interpolation(self): + cf = self.fromstring("[sect]\n" + "option1{eq}foo\n".format(eq=self.delimiters[0])) + + self.assertEqual(cf.get('sect', "option1"), "foo") + + cf.set("sect", "option1", "%foo") + self.assertEqual(cf.get('sect', "option1"), "%foo") + cf.set("sect", "option1", "foo%") + self.assertEqual(cf.get('sect', "option1"), "foo%") + cf.set("sect", "option1", "f%oo") + self.assertEqual(cf.get('sect', "option1"), "f%oo") + + # bug #5741: double percents are *not* malformed + cf.set("sect", "option2", "foo%%bar") + self.assertEqual(cf.get("sect", "option2"), "foo%%bar") class ConfigParserTestCaseNonStandardDelimiters(ConfigParserTestCase): delimiters = (':=', '$') comment_prefixes = ('//', '"') + inline_comment_prefixes = ('//', '"') class ConfigParserTestCaseNonStandardDefaultSection(ConfigParserTestCase): default_section = 'general' @@ -765,7 +934,8 @@ self.check_items_config([('default', ''), ('getdefault', '|%(default)s|'), ('key', '|%(name)s|'), - ('name', 'value')]) + ('name', '%(value)s'), + ('value', 'value')]) def test_set_nonstring_types(self): cf = self.newconfig() @@ -777,14 +947,25 @@ self.assertEqual(cf.get('non-string', 'list'), [0, 1, 1, 2, 3, 5, 8, 13]) self.assertEqual(cf.get('non-string', 'dict'), {'pi': 3.14159}) + cf.add_section(123) + cf.set(123, 'this is sick', True) + self.assertEqual(cf.get(123, 'this is sick'), True) + if cf._dict.__class__ is configparser._default_dict: + # would not work for SortedDict; only checking for the most common + # default dictionary (OrderedDict) + cf.optionxform = lambda x: x + cf.set('non-string', 1, 1) + self.assertEqual(cf.get('non-string', 1), 1) class RawConfigParserTestCaseNonStandardDelimiters(RawConfigParserTestCase): delimiters = (':=', '$') comment_prefixes = ('//', '"') + inline_comment_prefixes = ('//', '"') -class RawConfigParserTestSambaConf(BasicTestCase): +class RawConfigParserTestSambaConf(CfgParserTestCaseClass): config_class = configparser.RawConfigParser - comment_prefixes = ('#', ';', '//', '----') + comment_prefixes = ('#', ';', '----') + inline_comment_prefixes = ('//',) empty_lines_in_values = False def test_reading(self): @@ -801,61 +982,124 @@ self.assertEqual(cf.get("global", "hosts allow"), "127.") self.assertEqual(cf.get("tmp", "echo command"), "cat %s; rm %s") -class SafeConfigParserTestCase(ConfigParserTestCase): - config_class = configparser.SafeConfigParser - - def test_safe_interpolation(self): - # See http://www.python.org/sf/511737 - cf = self.fromstring("[section]\n" - "option1{eq}xxx\n" - "option2{eq}%(option1)s/xxx\n" - "ok{eq}%(option1)s/%%s\n" - "not_ok{eq}%(option2)s/%%s".format( - eq=self.delimiters[0])) - self.assertEqual(cf.get("section", "ok"), "xxx/%s") - self.assertEqual(cf.get("section", "not_ok"), "xxx/xxx/%s") - - def test_set_malformatted_interpolation(self): - cf = self.fromstring("[sect]\n" - "option1{eq}foo\n".format(eq=self.delimiters[0])) - - self.assertEqual(cf.get('sect', "option1"), "foo") - - self.assertRaises(ValueError, cf.set, "sect", "option1", "%foo") - self.assertRaises(ValueError, cf.set, "sect", "option1", "foo%") - self.assertRaises(ValueError, cf.set, "sect", "option1", "f%oo") +class ConfigParserTestCaseExtendedInterpolation(BasicTestCase): + config_class = configparser.ConfigParser + interpolation = configparser.ExtendedInterpolation() + default_section = 'common' - self.assertEqual(cf.get('sect', "option1"), "foo") + def test_extended_interpolation(self): + cf = self.fromstring(textwrap.dedent(""" + [common] + favourite Beatle = Paul + favourite color = green + + [tom] + favourite band = ${favourite color} day + favourite pope = John ${favourite Beatle} II + sequel = ${favourite pope}I + + [ambv] + favourite Beatle = George + son of Edward VII = ${favourite Beatle} V + son of George V = ${son of Edward VII}I + + [stanley] + favourite Beatle = ${ambv:favourite Beatle} + favourite pope = ${tom:favourite pope} + favourite color = black + favourite state of mind = paranoid + favourite movie = soylent ${common:favourite color} + favourite song = ${favourite color} sabbath - ${favourite state of mind} + """).strip()) - # bug #5741: double percents are *not* malformed - cf.set("sect", "option2", "foo%%bar") - self.assertEqual(cf.get("sect", "option2"), "foo%bar") + eq = self.assertEqual + eq(cf['common']['favourite Beatle'], 'Paul') + eq(cf['common']['favourite color'], 'green') + eq(cf['tom']['favourite Beatle'], 'Paul') + eq(cf['tom']['favourite color'], 'green') + eq(cf['tom']['favourite band'], 'green day') + eq(cf['tom']['favourite pope'], 'John Paul II') + eq(cf['tom']['sequel'], 'John Paul III') + eq(cf['ambv']['favourite Beatle'], 'George') + eq(cf['ambv']['favourite color'], 'green') + eq(cf['ambv']['son of Edward VII'], 'George V') + eq(cf['ambv']['son of George V'], 'George VI') + eq(cf['stanley']['favourite Beatle'], 'George') + eq(cf['stanley']['favourite color'], 'black') + eq(cf['stanley']['favourite state of mind'], 'paranoid') + eq(cf['stanley']['favourite movie'], 'soylent green') + eq(cf['stanley']['favourite pope'], 'John Paul II') + eq(cf['stanley']['favourite song'], + 'black sabbath - paranoid') + + def test_endless_loop(self): + cf = self.fromstring(textwrap.dedent(""" + [one for you] + ping = ${one for me:pong} + + [one for me] + pong = ${one for you:ping} + + [selfish] + me = ${me} + """).strip()) + + with self.assertRaises(configparser.InterpolationDepthError): + cf['one for you']['ping'] + with self.assertRaises(configparser.InterpolationDepthError): + cf['selfish']['me'] + + def test_strange_options(self): + cf = self.fromstring(""" + [dollars] + $var = $$value + $var2 = ${$var} + ${sick} = cannot interpolate me + + [interpolated] + $other = ${dollars:$var} + $trying = ${dollars:${sick}} + """) - def test_set_nonstring_types(self): - cf = self.fromstring("[sect]\n" - "option1{eq}foo\n".format(eq=self.delimiters[0])) - # Check that we get a TypeError when setting non-string values - # in an existing section: - self.assertRaises(TypeError, cf.set, "sect", "option1", 1) - self.assertRaises(TypeError, cf.set, "sect", "option1", 1.0) - self.assertRaises(TypeError, cf.set, "sect", "option1", object()) - self.assertRaises(TypeError, cf.set, "sect", "option2", 1) - self.assertRaises(TypeError, cf.set, "sect", "option2", 1.0) - self.assertRaises(TypeError, cf.set, "sect", "option2", object()) + self.assertEqual(cf['dollars']['$var'], '$value') + self.assertEqual(cf['interpolated']['$other'], '$value') + self.assertEqual(cf['dollars']['${sick}'], 'cannot interpolate me') + exception_class = configparser.InterpolationMissingOptionError + with self.assertRaises(exception_class) as cm: + cf['interpolated']['$trying'] + self.assertEqual(cm.exception.reference, 'dollars:${sick') + self.assertEqual(cm.exception.args[2], '}') #rawval + + + def test_other_errors(self): + cf = self.fromstring(""" + [interpolation fail] + case1 = ${where's the brace + case2 = ${does_not_exist} + case3 = ${wrong_section:wrong_value} + case4 = ${i:like:colon:characters} + case5 = $100 for Fail No 5! + """) - def test_add_section_default(self): - cf = self.newconfig() - self.assertRaises(ValueError, cf.add_section, self.default_section) + with self.assertRaises(configparser.InterpolationSyntaxError): + cf['interpolation fail']['case1'] + with self.assertRaises(configparser.InterpolationMissingOptionError): + cf['interpolation fail']['case2'] + with self.assertRaises(configparser.InterpolationMissingOptionError): + cf['interpolation fail']['case3'] + with self.assertRaises(configparser.InterpolationSyntaxError): + cf['interpolation fail']['case4'] + with self.assertRaises(configparser.InterpolationSyntaxError): + cf['interpolation fail']['case5'] + with self.assertRaises(ValueError): + cf['interpolation fail']['case6'] = "BLACK $ABBATH" -class SafeConfigParserTestCaseNonStandardDelimiters(SafeConfigParserTestCase): - delimiters = (':=', '$') - comment_prefixes = ('//', '"') -class SafeConfigParserTestCaseNoValue(SafeConfigParserTestCase): +class ConfigParserTestCaseNoValue(ConfigParserTestCase): allow_no_value = True -class SafeConfigParserTestCaseTrickyFile(CfgParserTestCaseClass): - config_class = configparser.SafeConfigParser +class ConfigParserTestCaseTrickyFile(CfgParserTestCaseClass): + config_class = configparser.ConfigParser delimiters = {'='} comment_prefixes = {'#'} allow_no_value = True @@ -918,8 +1162,10 @@ return sio.getvalue() def test_none_as_value_stringified(self): - output = self.prepare(configparser.ConfigParser) - self.assertEqual(output, self.expected_output) + cp = configparser.ConfigParser(allow_no_value=False) + cp.add_section("section") + with self.assertRaises(TypeError): + cp.set("section", "option", None) def test_none_as_value_stringified_raw(self): output = self.prepare(configparser.RawConfigParser) @@ -951,7 +1197,8 @@ class CompatibleTestCase(CfgParserTestCaseClass): config_class = configparser.RawConfigParser - comment_prefixes = configparser._COMPATIBLE + comment_prefixes = '#;' + inline_comment_prefixes = ';' def test_comment_handling(self): config_string = textwrap.dedent("""\ @@ -964,30 +1211,132 @@ ; a space must precede an inline comment """) cf = self.fromstring(config_string) - self.assertEqual(cf.get('Commented Bar', 'foo'), 'bar # not a comment!') + self.assertEqual(cf.get('Commented Bar', 'foo'), + 'bar # not a comment!') self.assertEqual(cf.get('Commented Bar', 'baz'), 'qwe') - self.assertEqual(cf.get('Commented Bar', 'quirk'), 'this;is not a comment') + self.assertEqual(cf.get('Commented Bar', 'quirk'), + 'this;is not a comment') +class CopyTestCase(BasicTestCase): + config_class = configparser.ConfigParser + + def fromstring(self, string, defaults=None): + cf = self.newconfig(defaults) + cf.read_string(string) + cf_copy = self.newconfig() + cf_copy.read_dict(cf) + # we have to clean up option duplicates that appeared because of + # the magic DEFAULTSECT behaviour. + for section in cf_copy.values(): + if section.name == self.default_section: + continue + for default, value in cf[self.default_section].items(): + if section[default] == value: + del section[default] + return cf_copy + +class CoverageOneHundredTestCase(unittest.TestCase): + """Covers edge cases in the codebase.""" + + def test_duplicate_option_error(self): + error = configparser.DuplicateOptionError('section', 'option') + self.assertEqual(error.section, 'section') + self.assertEqual(error.option, 'option') + self.assertEqual(error.source, None) + self.assertEqual(error.lineno, None) + self.assertEqual(error.args, ('section', 'option', None, None)) + self.assertEqual(str(error), "Option 'option' in section 'section' " + "already exists") + + def test_interpolation_depth_error(self): + error = configparser.InterpolationDepthError('option', 'section', + 'rawval') + self.assertEqual(error.args, ('option', 'section', 'rawval')) + self.assertEqual(error.option, 'option') + self.assertEqual(error.section, 'section') + + def test_parsing_error(self): + with self.assertRaises(ValueError) as cm: + configparser.ParsingError() + self.assertEqual(str(cm.exception), "Required argument `source' not " + "given.") + with self.assertRaises(ValueError) as cm: + configparser.ParsingError(source='source', filename='filename') + self.assertEqual(str(cm.exception), "Cannot specify both `filename' " + "and `source'. Use `source'.") + error = configparser.ParsingError(filename='source') + self.assertEqual(error.source, 'source') + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always", DeprecationWarning) + self.assertEqual(error.filename, 'source') + error.filename = 'filename' + self.assertEqual(error.source, 'filename') + for warning in w: + self.assertTrue(warning.category is DeprecationWarning) + + def test_interpolation_validation(self): + parser = configparser.ConfigParser() + parser.read_string(""" + [section] + invalid_percent = % + invalid_reference = %(() + invalid_variable = %(does_not_exist)s + """) + with self.assertRaises(configparser.InterpolationSyntaxError) as cm: + parser['section']['invalid_percent'] + self.assertEqual(str(cm.exception), "'%' must be followed by '%' or " + "'(', found: '%'") + with self.assertRaises(configparser.InterpolationSyntaxError) as cm: + parser['section']['invalid_reference'] + self.assertEqual(str(cm.exception), "bad interpolation variable " + "reference '%(()'") + + def test_readfp_deprecation(self): + sio = io.StringIO(""" + [section] + option = value + """) + parser = configparser.ConfigParser() + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always", DeprecationWarning) + parser.readfp(sio, filename='StringIO') + for warning in w: + self.assertTrue(warning.category is DeprecationWarning) + self.assertEqual(len(parser), 2) + self.assertEqual(parser['section']['option'], 'value') + + def test_safeconfigparser_deprecation(self): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always", DeprecationWarning) + parser = configparser.SafeConfigParser() + for warning in w: + self.assertTrue(warning.category is DeprecationWarning) + + def test_sectionproxy_repr(self): + parser = configparser.ConfigParser() + parser.read_string(""" + [section] + key = value + """) + self.assertEqual(repr(parser['section']), '') def test_main(): support.run_unittest( ConfigParserTestCase, ConfigParserTestCaseNonStandardDelimiters, + ConfigParserTestCaseNoValue, + ConfigParserTestCaseExtendedInterpolation, + ConfigParserTestCaseLegacyInterpolation, + ConfigParserTestCaseTrickyFile, MultilineValuesTestCase, RawConfigParserTestCase, RawConfigParserTestCaseNonStandardDelimiters, RawConfigParserTestSambaConf, - SafeConfigParserTestCase, - SafeConfigParserTestCaseNonStandardDelimiters, - SafeConfigParserTestCaseNoValue, - SafeConfigParserTestCaseTrickyFile, SortedTestCase, Issue7005TestCase, StrictTestCase, CompatibleTestCase, + CopyTestCase, ConfigParserTestCaseNonStandardDefaultSection, + CoverageOneHundredTestCase, ) - - -if __name__ == "__main__": - test_main() Modified: python/branches/py3k-cdecimal/Lib/test/test_cgi.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_cgi.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_cgi.py Sun Jan 2 13:18:37 2011 @@ -131,7 +131,7 @@ if isinstance(expect, dict): # test dict interface self.assertEqual(len(expect), len(fs)) - self.assertItemsEqual(expect.keys(), fs.keys()) + self.assertCountEqual(expect.keys(), fs.keys()) ##self.assertEqual(norm(expect.values()), norm(fs.values())) ##self.assertEqual(norm(expect.items()), norm(fs.items())) self.assertEqual(fs.getvalue("nonexistent field", "default"), "default") Modified: python/branches/py3k-cdecimal/Lib/test/test_cmath.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_cmath.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_cmath.py Sun Jan 2 13:18:37 2011 @@ -1,5 +1,5 @@ -from test.support import run_unittest -from test.test_math import parse_testfile, test_file, requires_IEEE_754 +from test.support import run_unittest, requires_IEEE_754 +from test.test_math import parse_testfile, test_file import unittest import cmath, math from cmath import phase, polar, rect, pi @@ -312,10 +312,8 @@ self.rAssertAlmostEqual(math.log(v, base), z.real) self.assertEqual(0., z.imag) + @requires_IEEE_754 def test_specific_values(self): - if not float.__getformat__("double").startswith("IEEE"): - return - def rect_complex(z): """Wrapped version of rect that accepts a complex number instead of two float arguments.""" @@ -460,9 +458,11 @@ self.assertEqual(abs(complex(INF, NAN)), INF) self.assertTrue(math.isnan(abs(complex(NAN, NAN)))) + + @requires_IEEE_754 + def test_abs_overflows(self): # result overflows - if float.__getformat__("double").startswith("IEEE"): - self.assertRaises(OverflowError, abs, complex(1.4e308, 1.4e308)) + self.assertRaises(OverflowError, abs, complex(1.4e308, 1.4e308)) def assertCEqual(self, a, b): eps = 1E-7 Modified: python/branches/py3k-cdecimal/Lib/test/test_cmd_line.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_cmd_line.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_cmd_line.py Sun Jan 2 13:18:37 2011 @@ -221,6 +221,24 @@ self.assertIn(path1.encode('ascii'), out) self.assertIn(path2.encode('ascii'), out) + def test_displayhook_unencodable(self): + for encoding in ('ascii', 'latin1', 'utf8'): + env = os.environ.copy() + env['PYTHONIOENCODING'] = encoding + p = subprocess.Popen( + [sys.executable, '-i'], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + env=env) + # non-ascii, surrogate, non-BMP printable, non-BMP unprintable + text = "a=\xe9 b=\uDC80 c=\U00010000 d=\U0010FFFF" + p.stdin.write(ascii(text).encode('ascii') + b"\n") + p.stdin.write(b'exit()\n') + data = kill_python(p) + escaped = repr(text).encode(encoding, 'backslashreplace') + self.assertIn(escaped, data) + def test_main(): test.support.run_unittest(CmdLineTest) Modified: python/branches/py3k-cdecimal/Lib/test/test_codecs.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_codecs.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_codecs.py Sun Jan 2 13:18:37 2011 @@ -544,6 +544,12 @@ self.assertRaises(UnicodeDecodeError, codecs.utf_16_le_decode, b"\xff", "strict", True) + def test_nonbmp(self): + self.assertEqual("\U00010203".encode(self.encoding), + b'\x00\xd8\x03\xde') + self.assertEqual(b'\x00\xd8\x03\xde'.decode(self.encoding), + "\U00010203") + class UTF16BETest(ReadTest): encoding = "utf-16-be" @@ -566,6 +572,12 @@ self.assertRaises(UnicodeDecodeError, codecs.utf_16_be_decode, b"\xff", "strict", True) + def test_nonbmp(self): + self.assertEqual("\U00010203".encode(self.encoding), + b'\xd8\x00\xde\x03') + self.assertEqual(b'\xd8\x00\xde\x03'.decode(self.encoding), + "\U00010203") + class UTF8Test(ReadTest): encoding = "utf-8" @@ -1659,6 +1671,54 @@ self.assertEqual(f.read(), data * 2) +bytes_transform_encodings = [ + "base64_codec", + "uu_codec", + "quopri_codec", + "hex_codec", +] +try: + import zlib +except ImportError: + pass +else: + bytes_transform_encodings.append("zlib_codec") +try: + import bz2 +except ImportError: + pass +else: + bytes_transform_encodings.append("bz2_codec") + +class TransformCodecTest(unittest.TestCase): + + def test_basics(self): + binput = bytes(range(256)) + for encoding in bytes_transform_encodings: + # generic codecs interface + (o, size) = codecs.getencoder(encoding)(binput) + self.assertEqual(size, len(binput)) + (i, size) = codecs.getdecoder(encoding)(o) + self.assertEqual(size, len(o)) + self.assertEqual(i, binput) + + def test_read(self): + for encoding in bytes_transform_encodings: + sin = codecs.encode(b"\x80", encoding) + reader = codecs.getreader(encoding)(io.BytesIO(sin)) + sout = reader.read() + self.assertEqual(sout, b"\x80") + + def test_readline(self): + for encoding in bytes_transform_encodings: + if encoding in ['uu_codec', 'zlib_codec']: + continue + sin = codecs.encode(b"\x80", encoding) + reader = codecs.getreader(encoding)(io.BytesIO(sin)) + sout = reader.readline() + self.assertEqual(sout, b"\x80") + + def test_main(): support.run_unittest( UTF32Test, @@ -1686,6 +1746,7 @@ TypesTest, SurrogateEscapeTest, BomTest, + TransformCodecTest, ) Modified: python/branches/py3k-cdecimal/Lib/test/test_collections.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_collections.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_collections.py Sun Jan 2 13:18:37 2011 @@ -356,8 +356,14 @@ for x in samples: self.assertIsInstance(x, Iterator) self.assertTrue(issubclass(type(x), Iterator), repr(type(x))) - self.validate_abstract_methods(Iterator, '__next__') - self.validate_isinstance(Iterator, '__next__') + self.validate_abstract_methods(Iterator, '__next__', '__iter__') + + # Issue 10565 + class NextOnly: + def __next__(self): + yield 1 + raise StopIteration + self.assertNotIsInstance(NextOnly(), Iterator) def test_Sized(self): non_samples = [None, 42, 3.14, 1j, @@ -828,6 +834,10 @@ self.assertEqual(list(d.items()), [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)]) + def test_abc(self): + self.assertIsInstance(OrderedDict(), MutableMapping) + self.assertTrue(issubclass(OrderedDict, MutableMapping)) + def test_clear(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) @@ -886,6 +896,17 @@ self.assertEqual(len(od), 0) self.assertEqual(od.pop(k, 12345), 12345) + # make sure pop still works when __missing__ is defined + class Missing(OrderedDict): + def __missing__(self, key): + return 0 + m = Missing(a=1) + self.assertEqual(m.pop('b', 5), 5) + self.assertEqual(m.pop('a', 6), 1) + self.assertEqual(m.pop('a', 6), 6) + with self.assertRaises(KeyError): + m.pop('a') + def test_equality(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) @@ -970,6 +991,12 @@ # make sure 'x' is added to the end self.assertEqual(list(od.items())[-1], ('x', 10)) + # make sure setdefault still works when __missing__ is defined + class Missing(OrderedDict): + def __missing__(self, key): + return 0 + self.assertEqual(Missing().setdefault(5, 9), 9) + def test_reinsert(self): # Given insert a, insert b, delete a, re-insert a, # verify that a is now later than b. @@ -1000,6 +1027,14 @@ od = OrderedDict(**d) self.assertGreater(sys.getsizeof(od), sys.getsizeof(d)) + def test_override_update(self): + # Verify that subclasses can override update() without breaking __init__() + class MyOD(OrderedDict): + def update(self, *args, **kwds): + raise Exception() + items = [('a', 1), ('c', 3), ('b', 2)] + self.assertEqual(list(MyOD(items).items()), items) + class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): type2test = OrderedDict Modified: python/branches/py3k-cdecimal/Lib/test/test_compileall.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_compileall.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_compileall.py Sun Jan 2 13:18:37 2011 @@ -11,7 +11,7 @@ import unittest import io -from test import support +from test import support, script_helper class CompileallTests(unittest.TestCase): @@ -88,6 +88,15 @@ compileall.compile_file(data_file) self.assertFalse(os.path.exists(os.path.join(data_dir, '__pycache__'))) + def test_optimize(self): + # make sure compiling with different optimization settings than the + # interpreter's creates the correct file names + optimize = 1 if __debug__ else 0 + compileall.compile_dir(self.directory, quiet=True, optimize=optimize) + cached = imp.cache_from_source(self.source_path, + debug_override=not optimize) + self.assertTrue(os.path.isfile(cached)) + class EncodingTest(unittest.TestCase): """Issue 6716: compileall should escape source code when printing errors @@ -115,126 +124,218 @@ class CommandLineTests(unittest.TestCase): """Test compileall's CLI.""" + def assertRunOK(self, *args, **env_vars): + rc, out, err = script_helper.assert_python_ok( + '-S', '-m', 'compileall', *args, **env_vars) + self.assertEqual(b'', err) + return out + + def assertRunNotOK(self, *args, **env_vars): + rc, out, err = script_helper.assert_python_failure( + '-S', '-m', 'compileall', *args, **env_vars) + return rc, out, err + + def assertCompiled(self, fn): + self.assertTrue(os.path.exists(imp.cache_from_source(fn))) + + def assertNotCompiled(self, fn): + self.assertFalse(os.path.exists(imp.cache_from_source(fn))) + def setUp(self): self.addCleanup(self._cleanup) self.directory = tempfile.mkdtemp() self.pkgdir = os.path.join(self.directory, 'foo') os.mkdir(self.pkgdir) - # Touch the __init__.py and a package module. - with open(os.path.join(self.pkgdir, '__init__.py'), 'w'): - pass - with open(os.path.join(self.pkgdir, 'bar.py'), 'w'): - pass - sys.path.insert(0, self.directory) + self.pkgdir_cachedir = os.path.join(self.pkgdir, '__pycache__') + # Create the __init__.py and a package module. + self.initfn = script_helper.make_script(self.pkgdir, '__init__', '') + self.barfn = script_helper.make_script(self.pkgdir, 'bar', '') def _cleanup(self): support.rmtree(self.directory) - assert sys.path[0] == self.directory, 'Missing path' - del sys.path[0] + + def test_no_args_compiles_path(self): + # Note that -l is implied for the no args case. + bazfn = script_helper.make_script(self.directory, 'baz', '') + self.assertRunOK(PYTHONPATH=self.directory) + self.assertCompiled(bazfn) + self.assertNotCompiled(self.initfn) + self.assertNotCompiled(self.barfn) # Ensure that the default behavior of compileall's CLI is to create # PEP 3147 pyc/pyo files. for name, ext, switch in [ ('normal', 'pyc', []), ('optimize', 'pyo', ['-O']), - ('doubleoptimize', 'pyo', ['-OO']) + ('doubleoptimize', 'pyo', ['-OO']), ]: def f(self, ext=ext, switch=switch): - retcode = subprocess.call( - [sys.executable] + switch + - ['-m', 'compileall', '-q', self.pkgdir]) - self.assertEqual(retcode, 0) + script_helper.assert_python_ok(*(switch + + ['-m', 'compileall', '-q', self.pkgdir])) # Verify the __pycache__ directory contents. - cachedir = os.path.join(self.pkgdir, '__pycache__') - self.assertTrue(os.path.exists(cachedir)) + self.assertTrue(os.path.exists(self.pkgdir_cachedir)) expected = sorted(base.format(imp.get_tag(), ext) for base in ('__init__.{}.{}', 'bar.{}.{}')) - self.assertEqual(sorted(os.listdir(cachedir)), expected) + self.assertEqual(sorted(os.listdir(self.pkgdir_cachedir)), expected) # Make sure there are no .pyc files in the source directory. - self.assertFalse([pyc_file for pyc_file in os.listdir(self.pkgdir) - if pyc_file.endswith(ext)]) + self.assertFalse([fn for fn in os.listdir(self.pkgdir) + if fn.endswith(ext)]) locals()['test_pep3147_paths_' + name] = f def test_legacy_paths(self): # Ensure that with the proper switch, compileall leaves legacy # pyc/pyo files, and no __pycache__ directory. - retcode = subprocess.call( - (sys.executable, '-m', 'compileall', '-b', '-q', self.pkgdir)) - self.assertEqual(retcode, 0) + self.assertRunOK('-b', '-q', self.pkgdir) # Verify the __pycache__ directory contents. - cachedir = os.path.join(self.pkgdir, '__pycache__') - self.assertFalse(os.path.exists(cachedir)) + self.assertFalse(os.path.exists(self.pkgdir_cachedir)) expected = sorted(['__init__.py', '__init__.pyc', 'bar.py', 'bar.pyc']) self.assertEqual(sorted(os.listdir(self.pkgdir)), expected) def test_multiple_runs(self): # Bug 8527 reported that multiple calls produced empty # __pycache__/__pycache__ directories. - retcode = subprocess.call( - (sys.executable, '-m', 'compileall', '-q', self.pkgdir)) - self.assertEqual(retcode, 0) + self.assertRunOK('-q', self.pkgdir) # Verify the __pycache__ directory contents. - cachedir = os.path.join(self.pkgdir, '__pycache__') - self.assertTrue(os.path.exists(cachedir)) - cachecachedir = os.path.join(cachedir, '__pycache__') + self.assertTrue(os.path.exists(self.pkgdir_cachedir)) + cachecachedir = os.path.join(self.pkgdir_cachedir, '__pycache__') self.assertFalse(os.path.exists(cachecachedir)) # Call compileall again. - retcode = subprocess.call( - (sys.executable, '-m', 'compileall', '-q', self.pkgdir)) - self.assertEqual(retcode, 0) - self.assertTrue(os.path.exists(cachedir)) + self.assertRunOK('-q', self.pkgdir) + self.assertTrue(os.path.exists(self.pkgdir_cachedir)) self.assertFalse(os.path.exists(cachecachedir)) def test_force(self): - retcode = subprocess.call( - (sys.executable, '-m', 'compileall', '-q', self.pkgdir)) - self.assertEqual(retcode, 0) - pycpath = imp.cache_from_source(os.path.join(self.pkgdir, 'bar.py')) + self.assertRunOK('-q', self.pkgdir) + pycpath = imp.cache_from_source(self.barfn) # set atime/mtime backward to avoid file timestamp resolution issues os.utime(pycpath, (time.time()-60,)*2) - access = os.stat(pycpath).st_mtime - retcode = subprocess.call( - (sys.executable, '-m', 'compileall', '-q', '-f', self.pkgdir)) - self.assertEqual(retcode, 0) - access2 = os.stat(pycpath).st_mtime - self.assertNotEqual(access, access2) - - def test_legacy(self): - # create a new module - newpackage = os.path.join(self.pkgdir, 'spam') - os.mkdir(newpackage) - with open(os.path.join(newpackage, '__init__.py'), 'w'): - pass - with open(os.path.join(newpackage, 'ham.py'), 'w'): - pass - sourcefile = os.path.join(newpackage, 'ham.py') - - retcode = subprocess.call( - (sys.executable, '-m', 'compileall', '-q', '-l', self.pkgdir)) - self.assertEqual(retcode, 0) - self.assertFalse(os.path.exists(imp.cache_from_source(sourcefile))) - - retcode = subprocess.call( - (sys.executable, '-m', 'compileall', '-q', self.pkgdir)) - self.assertEqual(retcode, 0) - self.assertTrue(os.path.exists(imp.cache_from_source(sourcefile))) + mtime = os.stat(pycpath).st_mtime + # without force, no recompilation + self.assertRunOK('-q', self.pkgdir) + mtime2 = os.stat(pycpath).st_mtime + self.assertEqual(mtime, mtime2) + # now force it. + self.assertRunOK('-q', '-f', self.pkgdir) + mtime2 = os.stat(pycpath).st_mtime + self.assertNotEqual(mtime, mtime2) + + def test_recursion_control(self): + subpackage = os.path.join(self.pkgdir, 'spam') + os.mkdir(subpackage) + subinitfn = script_helper.make_script(subpackage, '__init__', '') + hamfn = script_helper.make_script(subpackage, 'ham', '') + self.assertRunOK('-q', '-l', self.pkgdir) + self.assertNotCompiled(subinitfn) + self.assertFalse(os.path.exists(os.path.join(subpackage, '__pycache__'))) + self.assertRunOK('-q', self.pkgdir) + self.assertCompiled(subinitfn) + self.assertCompiled(hamfn) def test_quiet(self): - noise = subprocess.getoutput('{} -m compileall {}'.format( - sys.executable, self.pkgdir)) - quiet = subprocess.getoutput(('{} -m compileall -f -q {}'.format( - sys.executable, self.pkgdir))) - self.assertGreater(len(noise), len(quiet)) + noisy = self.assertRunOK(self.pkgdir) + quiet = self.assertRunOK('-q', self.pkgdir) + self.assertNotEqual(b'', noisy) + self.assertEqual(b'', quiet) def test_regexp(self): - retcode = subprocess.call( - (sys.executable, '-m', 'compileall', '-q', '-x', 'bar.*', self.pkgdir)) - self.assertEqual(retcode, 0) - - sourcefile = os.path.join(self.pkgdir, 'bar.py') - self.assertFalse(os.path.exists(imp.cache_from_source(sourcefile))) - sourcefile = os.path.join(self.pkgdir, '__init__.py') - self.assertTrue(os.path.exists(imp.cache_from_source(sourcefile))) + self.assertRunOK('-q', '-x', 'ba.*', self.pkgdir) + self.assertNotCompiled(self.barfn) + self.assertCompiled(self.initfn) + + def test_multiple_dirs(self): + pkgdir2 = os.path.join(self.directory, 'foo2') + os.mkdir(pkgdir2) + init2fn = script_helper.make_script(pkgdir2, '__init__', '') + bar2fn = script_helper.make_script(pkgdir2, 'bar2', '') + self.assertRunOK('-q', self.pkgdir, pkgdir2) + self.assertCompiled(self.initfn) + self.assertCompiled(self.barfn) + self.assertCompiled(init2fn) + self.assertCompiled(bar2fn) + + def test_d_takes_exactly_one_dir(self): + rc, out, err = self.assertRunNotOK('-d', 'foo') + self.assertEqual(out, b'') + self.assertRegex(err, b'-d') + rc, out, err = self.assertRunNotOK('-d', 'foo', 'bar') + self.assertEqual(out, b'') + self.assertRegex(err, b'-d') + + def test_d_compile_error(self): + script_helper.make_script(self.pkgdir, 'crunchyfrog', 'bad(syntax') + rc, out, err = self.assertRunNotOK('-q', '-d', 'dinsdale', self.pkgdir) + self.assertRegex(out, b'File "dinsdale') + + def test_d_runtime_error(self): + bazfn = script_helper.make_script(self.pkgdir, 'baz', 'raise Exception') + self.assertRunOK('-q', '-d', 'dinsdale', self.pkgdir) + fn = script_helper.make_script(self.pkgdir, 'bing', 'import baz') + pyc = imp.cache_from_source(bazfn) + os.rename(pyc, os.path.join(self.pkgdir, 'baz.pyc')) + os.remove(bazfn) + rc, out, err = script_helper.assert_python_failure(fn) + self.assertRegex(err, b'File "dinsdale') + + def test_include_bad_file(self): + rc, out, err = self.assertRunNotOK( + '-i', os.path.join(self.directory, 'nosuchfile'), self.pkgdir) + self.assertRegex(out, b'rror.*nosuchfile') + self.assertNotRegex(err, b'Traceback') + self.assertFalse(os.path.exists(imp.cache_from_source( + self.pkgdir_cachedir))) + + def test_include_file_with_arg(self): + f1 = script_helper.make_script(self.pkgdir, 'f1', '') + f2 = script_helper.make_script(self.pkgdir, 'f2', '') + f3 = script_helper.make_script(self.pkgdir, 'f3', '') + f4 = script_helper.make_script(self.pkgdir, 'f4', '') + with open(os.path.join(self.directory, 'l1'), 'w') as l1: + l1.write(os.path.join(self.pkgdir, 'f1.py')+os.linesep) + l1.write(os.path.join(self.pkgdir, 'f2.py')+os.linesep) + self.assertRunOK('-i', os.path.join(self.directory, 'l1'), f4) + self.assertCompiled(f1) + self.assertCompiled(f2) + self.assertNotCompiled(f3) + self.assertCompiled(f4) + + def test_include_file_no_arg(self): + f1 = script_helper.make_script(self.pkgdir, 'f1', '') + f2 = script_helper.make_script(self.pkgdir, 'f2', '') + f3 = script_helper.make_script(self.pkgdir, 'f3', '') + f4 = script_helper.make_script(self.pkgdir, 'f4', '') + with open(os.path.join(self.directory, 'l1'), 'w') as l1: + l1.write(os.path.join(self.pkgdir, 'f2.py')+os.linesep) + self.assertRunOK('-i', os.path.join(self.directory, 'l1')) + self.assertNotCompiled(f1) + self.assertCompiled(f2) + self.assertNotCompiled(f3) + self.assertNotCompiled(f4) + + def test_include_on_stdin(self): + f1 = script_helper.make_script(self.pkgdir, 'f1', '') + f2 = script_helper.make_script(self.pkgdir, 'f2', '') + f3 = script_helper.make_script(self.pkgdir, 'f3', '') + f4 = script_helper.make_script(self.pkgdir, 'f4', '') + p = script_helper.spawn_python('-m', 'compileall', '-i', '-') + p.stdin.write((f3+os.linesep).encode('ascii')) + script_helper.kill_python(p) + self.assertNotCompiled(f1) + self.assertNotCompiled(f2) + self.assertCompiled(f3) + self.assertNotCompiled(f4) + + def test_compiles_as_much_as_possible(self): + bingfn = script_helper.make_script(self.pkgdir, 'bing', 'syntax(error') + rc, out, err = self.assertRunNotOK('nosuchfile', self.initfn, + bingfn, self.barfn) + self.assertRegex(out, b'rror') + self.assertNotCompiled(bingfn) + self.assertCompiled(self.initfn) + self.assertCompiled(self.barfn) + + def test_invalid_arg_produces_message(self): + out = self.assertRunOK('badfilename') + self.assertRegex(out, b"Can't list badfilename") def test_main(): Modified: python/branches/py3k-cdecimal/Lib/test/test_complex.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_complex.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_complex.py Sun Jan 2 13:18:37 2011 @@ -220,6 +220,7 @@ self.assertEqual(complex(NS(1+10j)), 1+10j) self.assertRaises(TypeError, complex, OS(None)) self.assertRaises(TypeError, complex, NS(None)) + self.assertRaises(TypeError, complex, {}) self.assertAlmostEqual(complex("1+10j"), 1+10j) self.assertAlmostEqual(complex(10), 10+0j) @@ -325,6 +326,8 @@ # check that complex accepts long unicode strings self.assertEqual(type(complex("1"*500)), complex) + # check whitespace processing + self.assertEqual(complex('\N{EM SPACE}(\N{EN SPACE}1+1j ) '), 1+1j) class EvilExc(Exception): pass @@ -378,28 +381,48 @@ for num in nums: self.assertAlmostEqual((num.real**2 + num.imag**2) ** 0.5, abs(num)) - def test_repr(self): - self.assertEqual(repr(1+6j), '(1+6j)') - self.assertEqual(repr(1-6j), '(1-6j)') - - self.assertNotEqual(repr(-(1+0j)), '(-1+-0j)') + def test_repr_str(self): + def test(v, expected, test_fn=self.assertEqual): + test_fn(repr(v), expected) + test_fn(str(v), expected) + + test(1+6j, '(1+6j)') + test(1-6j, '(1-6j)') + + test(-(1+0j), '(-1+-0j)', test_fn=self.assertNotEqual) + + test(complex(1., INF), "(1+infj)") + test(complex(1., -INF), "(1-infj)") + test(complex(INF, 1), "(inf+1j)") + test(complex(-INF, INF), "(-inf+infj)") + test(complex(NAN, 1), "(nan+1j)") + test(complex(1, NAN), "(1+nanj)") + test(complex(NAN, NAN), "(nan+nanj)") + + test(complex(0, INF), "infj") + test(complex(0, -INF), "-infj") + test(complex(0, NAN), "nanj") self.assertEqual(1-6j,complex(repr(1-6j))) self.assertEqual(1+6j,complex(repr(1+6j))) self.assertEqual(-6j,complex(repr(-6j))) self.assertEqual(6j,complex(repr(6j))) - self.assertEqual(repr(complex(1., INF)), "(1+infj)") - self.assertEqual(repr(complex(1., -INF)), "(1-infj)") - self.assertEqual(repr(complex(INF, 1)), "(inf+1j)") - self.assertEqual(repr(complex(-INF, INF)), "(-inf+infj)") - self.assertEqual(repr(complex(NAN, 1)), "(nan+1j)") - self.assertEqual(repr(complex(1, NAN)), "(1+nanj)") - self.assertEqual(repr(complex(NAN, NAN)), "(nan+nanj)") - - self.assertEqual(repr(complex(0, INF)), "infj") - self.assertEqual(repr(complex(0, -INF)), "-infj") - self.assertEqual(repr(complex(0, NAN)), "nanj") + @support.requires_IEEE_754 + def test_negative_zero_repr_str(self): + def test(v, expected, test_fn=self.assertEqual): + test_fn(repr(v), expected) + test_fn(str(v), expected) + + test(complex(0., 1.), "1j") + test(complex(-0., 1.), "(-0+1j)") + test(complex(0., -1.), "-1j") + test(complex(-0., -1.), "(-0-1j)") + + test(complex(0., 0.), "0j") + test(complex(0., -0.), "-0j") + test(complex(-0., 0.), "(-0+0j)") + test(complex(-0., -0.), "(-0-0j)") def test_neg(self): self.assertEqual(-(1+6j), -1-6j) @@ -428,15 +451,14 @@ self.assertEqual(complex(0, INF).__getnewargs__(), (0.0, INF)) self.assertEqual(complex(INF, 0).__getnewargs__(), (INF, 0.0)) - if float.__getformat__("double").startswith("IEEE"): - def test_plus_minus_0j(self): - # test that -0j and 0j literals are not identified - z1, z2 = 0j, -0j - self.assertEqual(atan2(z1.imag, -1.), atan2(0., -1.)) - self.assertEqual(atan2(z2.imag, -1.), atan2(-0., -1.)) + @support.requires_IEEE_754 + def test_plus_minus_0j(self): + # test that -0j and 0j literals are not identified + z1, z2 = 0j, -0j + self.assertEqual(atan2(z1.imag, -1.), atan2(0., -1.)) + self.assertEqual(atan2(z2.imag, -1.), atan2(-0., -1.)) - @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") + @support.requires_IEEE_754 def test_negated_imaginary_literal(self): z0 = -0j z1 = -7j @@ -452,15 +474,13 @@ self.assertFloatsAreIdentical(z2.real, -0.0) self.assertFloatsAreIdentical(z2.imag, -INF) - @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") + @support.requires_IEEE_754 def test_overflow(self): self.assertEqual(complex("1e500"), complex(INF, 0.0)) self.assertEqual(complex("-1e500j"), complex(0.0, -INF)) self.assertEqual(complex("-1e500+1.8e308j"), complex(-INF, INF)) - @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") + @support.requires_IEEE_754 def test_repr_roundtrip(self): vals = [0.0, 1e-500, 1e-315, 1e-200, 0.0123, 3.1415, 1e50, INF, NAN] vals += [-v for v in vals] @@ -555,8 +575,28 @@ self.assertEqual(format(1.5e21+3j, '^40,.2f'), ' 1,500,000,000,000,000,000,000.00+3.00j ') self.assertEqual(format(1.5e21+3000j, ',.2f'), '1,500,000,000,000,000,000,000.00+3,000.00j') - # alternate is invalid - self.assertRaises(ValueError, (1.5+0.5j).__format__, '#f') + # Issue 7094: Alternate formatting (specified by #) + self.assertEqual(format(1+1j, '.0e'), '1e+00+1e+00j') + self.assertEqual(format(1+1j, '#.0e'), '1.e+00+1.e+00j') + self.assertEqual(format(1+1j, '.0f'), '1+1j') + self.assertEqual(format(1+1j, '#.0f'), '1.+1.j') + self.assertEqual(format(1.1+1.1j, 'g'), '1.1+1.1j') + self.assertEqual(format(1.1+1.1j, '#g'), '1.10000+1.10000j') + + # Alternate doesn't make a difference for these, they format the same with or without it + self.assertEqual(format(1+1j, '.1e'), '1.0e+00+1.0e+00j') + self.assertEqual(format(1+1j, '#.1e'), '1.0e+00+1.0e+00j') + self.assertEqual(format(1+1j, '.1f'), '1.0+1.0j') + self.assertEqual(format(1+1j, '#.1f'), '1.0+1.0j') + + # Misc. other alternate tests + self.assertEqual(format((-1.5+0.5j), '#f'), '-1.500000+0.500000j') + self.assertEqual(format((-1.5+0.5j), '#.0f'), '-2.+0.j') + self.assertEqual(format((-1.5+0.5j), '#e'), '-1.500000e+00+5.000000e-01j') + self.assertEqual(format((-1.5+0.5j), '#.0e'), '-2.e+00+5.e-01j') + self.assertEqual(format((-1.5+0.5j), '#g'), '-1.50000+0.500000j') + self.assertEqual(format((-1.5+0.5j), '.0g'), '-2+0.5j') + self.assertEqual(format((-1.5+0.5j), '#.0g'), '-2.+0.5j') # zero padding is invalid self.assertRaises(ValueError, (1.5+0.5j).__format__, '010f') Modified: python/branches/py3k-cdecimal/Lib/test/test_concurrent_futures.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_concurrent_futures.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_concurrent_futures.py Sun Jan 2 13:18:37 2011 @@ -24,7 +24,7 @@ from concurrent import futures from concurrent.futures._base import ( PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED, Future, - LOGGER, STDERR_HANDLER, wait) + LOGGER, wait) import concurrent.futures.process def create_future(state=PENDING, exception=None, result=None): @@ -75,15 +75,27 @@ def _wait_on_event(self, handle): if sys.platform.startswith('win'): + # WaitForSingleObject returns 0 if handle is signaled. r = ctypes.windll.kernel32.WaitForSingleObject(handle, 60 * 1000) - assert r == 0 + if r != 0: + message = ( + 'WaitForSingleObject({}, ...) failed with {}, ' + 'GetLastError() = {}'.format( + handle, r, ctypes.GetLastError())) + logging.critical(message) + assert False, message else: self.CALL_LOCKS[handle].wait() def _signal_event(self, handle): if sys.platform.startswith('win'): - r = ctypes.windll.kernel32.SetEvent(handle) - assert r != 0 + r = ctypes.windll.kernel32.SetEvent(handle) # Returns 0 on failure. + if r == 0: + message = ( + 'SetEvent({}) failed with {}, GetLastError() = {}'.format( + handle, r, ctypes.GetLastError())) + logging.critical(message) + assert False, message else: self.CALL_LOCKS[handle].set() @@ -113,6 +125,8 @@ if sys.platform.startswith('win'): ctypes.windll.kernel32.CloseHandle(self._called_event) ctypes.windll.kernel32.CloseHandle(self._can_finish) + self._called_event = None + self._can_finish = None else: del self.CALL_LOCKS[self._called_event] del self.CALL_LOCKS[self._can_finish] @@ -363,8 +377,6 @@ self.assertEqual(set([future1, future2]), finished) self.assertEqual(set(), pending) - - finally: call1.close() call2.close() @@ -620,11 +632,7 @@ self.assertTrue(was_cancelled) def test_done_callback_raises(self): - LOGGER.removeHandler(STDERR_HANDLER) - logging_stream = io.StringIO() - handler = logging.StreamHandler(logging_stream) - LOGGER.addHandler(handler) - try: + with test.support.captured_stderr() as stderr: raising_was_called = False fn_was_called = False @@ -643,10 +651,7 @@ f.set_result(5) self.assertTrue(raising_was_called) self.assertTrue(fn_was_called) - self.assertIn('Exception: doh!', logging_stream.getvalue()) - finally: - LOGGER.removeHandler(handler) - LOGGER.addHandler(STDERR_HANDLER) + self.assertIn('Exception: doh!', stderr.getvalue()) def test_done_callback_already_successful(self): callback_result = None @@ -682,18 +687,18 @@ self.assertTrue(was_cancelled) def test_repr(self): - self.assertRegexpMatches(repr(PENDING_FUTURE), - '') - self.assertRegexpMatches(repr(RUNNING_FUTURE), - '') - self.assertRegexpMatches(repr(CANCELLED_FUTURE), - '') - self.assertRegexpMatches(repr(CANCELLED_AND_NOTIFIED_FUTURE), - '') - self.assertRegexpMatches( + self.assertRegex(repr(PENDING_FUTURE), + '') + self.assertRegex(repr(RUNNING_FUTURE), + '') + self.assertRegex(repr(CANCELLED_FUTURE), + '') + self.assertRegex(repr(CANCELLED_AND_NOTIFIED_FUTURE), + '') + self.assertRegex( repr(EXCEPTION_FUTURE), '') - self.assertRegexpMatches( + self.assertRegex( repr(SUCCESSFUL_FUTURE), '') Modified: python/branches/py3k-cdecimal/Lib/test/test_contextlib.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_contextlib.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_contextlib.py Sun Jan 2 13:18:37 2011 @@ -231,7 +231,7 @@ def test_contextdecorator_with_exception(self): context = mycontext() - with self.assertRaisesRegexp(NameError, 'foo'): + with self.assertRaisesRegex(NameError, 'foo'): with context: raise NameError('foo') self.assertIsNotNone(context.exc) @@ -265,7 +265,7 @@ self.assertTrue(context.started) raise NameError('foo') - with self.assertRaisesRegexp(NameError, 'foo'): + with self.assertRaisesRegex(NameError, 'foo'): test() self.assertIsNotNone(context.exc) self.assertIs(context.exc[0], NameError) Modified: python/branches/py3k-cdecimal/Lib/test/test_csv.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_csv.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_csv.py Sun Jan 2 13:18:37 2011 @@ -313,22 +313,17 @@ expected_dialects = csv.list_dialects() + [name] expected_dialects.sort() csv.register_dialect(name, myexceltsv) - try: - self.assertTrue(csv.get_dialect(name).delimiter, '\t') - got_dialects = csv.list_dialects() - got_dialects.sort() - self.assertEqual(expected_dialects, got_dialects) - finally: - csv.unregister_dialect(name) + self.addCleanup(csv.unregister_dialect, name) + self.assertEqual(csv.get_dialect(name).delimiter, '\t') + got_dialects = sorted(csv.list_dialects()) + self.assertEqual(expected_dialects, got_dialects) def test_register_kwargs(self): name = 'fedcba' csv.register_dialect(name, delimiter=';') - try: - self.assertTrue(csv.get_dialect(name).delimiter, '\t') - self.assertTrue(list(csv.reader('X;Y;Z', name)), ['X', 'Y', 'Z']) - finally: - csv.unregister_dialect(name) + self.addCleanup(csv.unregister_dialect, name) + self.assertEqual(csv.get_dialect(name).delimiter, ';') + self.assertEqual([['X', 'Y', 'Z']], list(csv.reader(['X;Y;Z'], name))) def test_incomplete_dialect(self): class myexceltsv(csv.Dialect): Modified: python/branches/py3k-cdecimal/Lib/test/test_dbm_gnu.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_dbm_gnu.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_dbm_gnu.py Sun Jan 2 13:18:37 2011 @@ -32,6 +32,10 @@ key_set.remove(key) key = self.g.nextkey(key) self.assertRaises(KeyError, lambda: self.g['xxx']) + # get() and setdefault() work as in the dict interface + self.assertEqual(self.g.get(b'xxx', b'foo'), b'foo') + self.assertEqual(self.g.setdefault(b'xxx', b'foo'), b'foo') + self.assertEqual(self.g[b'xxx'], b'foo') def test_error_conditions(self): # Try to open a non-existent database. Modified: python/branches/py3k-cdecimal/Lib/test/test_decimal.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_decimal.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_decimal.py Sun Jan 2 13:18:37 2011 @@ -32,7 +32,8 @@ import unittest from decimal import * import numbers -from test.support import run_unittest, run_doctest, is_resource_enabled +from test.support import (run_unittest, run_doctest, is_resource_enabled, + requires_IEEE_754) from test.support import check_warnings import random try: @@ -61,11 +62,6 @@ ) setcontext(DefaultTestContext) -# decorator for skipping tests on non-IEEE 754 platforms -requires_IEEE_754 = unittest.skipUnless( - float.__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") - TESTDATADIR = 'decimaltestdata' if __name__ == '__main__': file = sys.argv[0] @@ -818,6 +814,18 @@ # issue 6850 ('a=-7.0', '0.12345', 'aaaa0.1'), + + # Issue 7094: Alternate formatting (specified by #) + ('.0e', '1.0', '1e+0'), + ('#.0e', '1.0', '1.e+0'), + ('.0f', '1.0', '1'), + ('#.0f', '1.0', '1.'), + ('g', '1.1', '1.1'), + ('#g', '1.1', '1.1'), + ('.0g', '1', '1'), + ('#.0g', '1', '1.'), + ('.0%', '1.0', '100%'), + ('#.0%', '1.0', '100.%'), ] for fmt, d, result in test_values: self.assertEqual(format(Decimal(d), fmt), result) Modified: python/branches/py3k-cdecimal/Lib/test/test_descr.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_descr.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_descr.py Sun Jan 2 13:18:37 2011 @@ -4233,20 +4233,26 @@ self.C = C def test_iter_keys(self): - # Testing dict-proxy iterkeys... - keys = [ key for key in self.C.__dict__.keys() ] + # Testing dict-proxy keys... + it = self.C.__dict__.keys() + self.assertNotIsInstance(it, list) + keys = list(it) keys.sort() self.assertEqual(keys, ['__dict__', '__doc__', '__module__', '__weakref__', 'meth']) def test_iter_values(self): - # Testing dict-proxy itervalues... - values = [ values for values in self.C.__dict__.values() ] + # Testing dict-proxy values... + it = self.C.__dict__.values() + self.assertNotIsInstance(it, list) + values = list(it) self.assertEqual(len(values), 5) def test_iter_items(self): # Testing dict-proxy iteritems... - keys = [ key for (key, value) in self.C.__dict__.items() ] + it = self.C.__dict__.items() + self.assertNotIsInstance(it, list) + keys = [item[0] for item in it] keys.sort() self.assertEqual(keys, ['__dict__', '__doc__', '__module__', '__weakref__', 'meth']) @@ -4262,6 +4268,11 @@ pass self.assertEqual(type(C.__dict__), type(B.__dict__)) + def test_repr(self): + # Testing dict_proxy.__repr__ + dict_ = {k: v for k, v in self.C.__dict__.items()} + self.assertEqual(repr(self.C.__dict__), 'dict_proxy({!r})'.format(dict_)) + class PTypesLongInitTest(unittest.TestCase): # This is in its own TestCase so that it can be run before any other tests. Modified: python/branches/py3k-cdecimal/Lib/test/test_difflib.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_difflib.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_difflib.py Sun Jan 2 13:18:37 2011 @@ -4,8 +4,64 @@ import doctest import sys -class TestSFbugs(unittest.TestCase): +class TestWithAscii(unittest.TestCase): + def test_one_insert(self): + sm = difflib.SequenceMatcher(None, 'b' * 100, 'a' + 'b' * 100) + self.assertAlmostEqual(sm.ratio(), 0.995, places=3) + self.assertEqual(list(sm.get_opcodes()), + [ ('insert', 0, 0, 0, 1), + ('equal', 0, 100, 1, 101)]) + self.assertEqual(sm.bpopular, set()) + sm = difflib.SequenceMatcher(None, 'b' * 100, 'b' * 50 + 'a' + 'b' * 50) + self.assertAlmostEqual(sm.ratio(), 0.995, places=3) + self.assertEqual(list(sm.get_opcodes()), + [ ('equal', 0, 50, 0, 50), + ('insert', 50, 50, 50, 51), + ('equal', 50, 100, 51, 101)]) + self.assertEqual(sm.bpopular, set()) + + def test_one_delete(self): + sm = difflib.SequenceMatcher(None, 'a' * 40 + 'c' + 'b' * 40, 'a' * 40 + 'b' * 40) + self.assertAlmostEqual(sm.ratio(), 0.994, places=3) + self.assertEqual(list(sm.get_opcodes()), + [ ('equal', 0, 40, 0, 40), + ('delete', 40, 41, 40, 40), + ('equal', 41, 81, 40, 80)]) + + def test_bjunk(self): + sm = difflib.SequenceMatcher(isjunk=lambda x: x == ' ', + a='a' * 40 + 'b' * 40, b='a' * 44 + 'b' * 40) + self.assertEqual(sm.bjunk, set()) + + sm = difflib.SequenceMatcher(isjunk=lambda x: x == ' ', + a='a' * 40 + 'b' * 40, b='a' * 44 + 'b' * 40 + ' ' * 20) + self.assertEqual(sm.bjunk, {' '}) + + sm = difflib.SequenceMatcher(isjunk=lambda x: x in [' ', 'b'], + a='a' * 40 + 'b' * 40, b='a' * 44 + 'b' * 40 + ' ' * 20) + self.assertEqual(sm.bjunk, {' ', 'b'}) + + +class TestAutojunk(unittest.TestCase): + """Tests for the autojunk parameter added in 2.7""" + def test_one_insert_homogenous_sequence(self): + # By default autojunk=True and the heuristic kicks in for a sequence + # of length 200+ + seq1 = 'b' * 200 + seq2 = 'a' + 'b' * 200 + + sm = difflib.SequenceMatcher(None, seq1, seq2) + self.assertAlmostEqual(sm.ratio(), 0, places=3) + self.assertEqual(sm.bpopular, {'b'}) + + # Now turn the heuristic off + sm = difflib.SequenceMatcher(None, seq1, seq2, autojunk=False) + self.assertAlmostEqual(sm.ratio(), 0.9975, places=3) + self.assertEqual(sm.bpopular, set()) + + +class TestSFbugs(unittest.TestCase): def test_ratio_for_null_seqn(self): # Check clearing of SF bug 763023 s = difflib.SequenceMatcher(None, [], []) @@ -184,7 +240,9 @@ def test_main(): difflib.HtmlDiff._default_prefix = 0 Doctests = doctest.DocTestSuite(difflib) - run_unittest(TestSFpatches, TestSFbugs, TestOutputFormat, Doctests) + run_unittest( + TestWithAscii, TestAutojunk, TestSFpatches, TestSFbugs, + TestOutputFormat, Doctests) if __name__ == '__main__': test_main() Modified: python/branches/py3k-cdecimal/Lib/test/test_dis.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_dis.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_dis.py Sun Jan 2 13:18:37 2011 @@ -354,14 +354,14 @@ def test_code_info(self): self.maxDiff = 1000 for x, expected in self.test_pairs: - self.assertRegexpMatches(dis.code_info(x), expected) + self.assertRegex(dis.code_info(x), expected) def test_show_code(self): self.maxDiff = 1000 for x, expected in self.test_pairs: with captured_stdout() as output: dis.show_code(x) - self.assertRegexpMatches(output.getvalue(), expected+"\n") + self.assertRegex(output.getvalue(), expected+"\n") def test_main(): run_unittest(DisTests, CodeInfoTests) Modified: python/branches/py3k-cdecimal/Lib/test/test_float.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_float.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_float.py Sun Jan 2 13:18:37 2011 @@ -16,10 +16,6 @@ "requires __getformat__") requires_setformat = unittest.skipUnless(hasattr(float, "__setformat__"), "requires __setformat__") -# decorator for skipping tests on non-IEEE 754 platforms -requires_IEEE_754 = unittest.skipUnless(have_getformat and - float.__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") #locate file with float format test values test_dir = os.path.dirname(__file__) or os.curdir @@ -43,14 +39,30 @@ self.assertRaises(ValueError, float, "+.inf") self.assertRaises(ValueError, float, ".") self.assertRaises(ValueError, float, "-.") + self.assertRaises(ValueError, float, b"-") + self.assertRaises(TypeError, float, {}) + # Lone surrogate + self.assertRaises(UnicodeEncodeError, float, '\uD8F0') # check that we don't accept alternate exponent markers self.assertRaises(ValueError, float, "-1.7d29") self.assertRaises(ValueError, float, "3D-14") - self.assertEqual(float(b" \u0663.\u0661\u0664 ".decode('raw-unicode-escape')), 3.14) + self.assertEqual(float(" \u0663.\u0661\u0664 "), 3.14) + self.assertEqual(float("\N{EM SPACE}3.14\N{EN SPACE}"), 3.14) # extra long strings should not be a problem float(b'.' + b'1'*1000) float('.' + '1'*1000) + def test_error_message(self): + testlist = ('\xbd', '123\xbd', ' 123 456 ') + for s in testlist: + try: + float(s) + except ValueError as e: + self.assertIn(s.strip(), e.args[0]) + else: + self.fail("Expected int(%r) to raise a ValueError", s) + + @support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE') def test_float_with_comma(self): # set locale to something that doesn't use '.' for the decimal point @@ -180,7 +192,27 @@ # distingishes -0.0 and 0.0. self.assertEqual((a, copysign(1.0, a)), (b, copysign(1.0, b))) - @requires_IEEE_754 + @support.requires_IEEE_754 + def test_float_mod(self): + # Check behaviour of % operator for IEEE 754 special cases. + # In particular, check signs of zeros. + mod = operator.mod + + self.assertEqualAndEqualSign(mod(-1.0, 1.0), 0.0) + self.assertEqualAndEqualSign(mod(-1e-100, 1.0), 1.0) + self.assertEqualAndEqualSign(mod(-0.0, 1.0), 0.0) + self.assertEqualAndEqualSign(mod(0.0, 1.0), 0.0) + self.assertEqualAndEqualSign(mod(1e-100, 1.0), 1e-100) + self.assertEqualAndEqualSign(mod(1.0, 1.0), 0.0) + + self.assertEqualAndEqualSign(mod(-1.0, -1.0), -0.0) + self.assertEqualAndEqualSign(mod(-1e-100, -1.0), -1e-100) + self.assertEqualAndEqualSign(mod(-0.0, -1.0), -0.0) + self.assertEqualAndEqualSign(mod(0.0, -1.0), -0.0) + self.assertEqualAndEqualSign(mod(1e-100, -1.0), -1.0) + self.assertEqualAndEqualSign(mod(1.0, -1.0), -0.0) + + @support.requires_IEEE_754 def test_float_pow(self): # test builtin pow and ** operator for IEEE 754 special cases. # Special cases taken from section F.9.4.4 of the C99 specification @@ -467,7 +499,7 @@ class IEEEFormatTestCase(unittest.TestCase): - @requires_IEEE_754 + @support.requires_IEEE_754 def test_double_specials_do_unpack(self): for fmt, data in [('>d', BE_DOUBLE_INF), ('>d', BE_DOUBLE_NAN), @@ -475,7 +507,7 @@ ('f', BE_FLOAT_INF), ('>f', BE_FLOAT_NAN), @@ -538,7 +570,7 @@ self.assertEqual(format(INF, 'f'), 'inf') self.assertEqual(format(INF, 'F'), 'INF') - @requires_IEEE_754 + @support.requires_IEEE_754 def test_format_testfile(self): with open(format_testfile) as testfile: for line in testfile: @@ -622,7 +654,7 @@ self.assertEqual(repr(float(s)), str(float(s))) self.assertEqual(repr(float(negs)), str(float(negs))) - at requires_IEEE_754 + at support.requires_IEEE_754 class RoundTestCase(unittest.TestCase): def test_inf_nan(self): @@ -706,11 +738,8 @@ def test(fmt, value, expected): # Test with both % and format(). self.assertEqual(fmt % value, expected, fmt) - if not '#' in fmt: - # Until issue 7094 is implemented, format() for floats doesn't - # support '#' formatting - fmt = fmt[1:] # strip off the % - self.assertEqual(format(value, fmt), expected, fmt) + fmt = fmt[1:] # strip off the % + self.assertEqual(format(value, fmt), expected, fmt) for fmt in ['%e', '%f', '%g', '%.0e', '%.6f', '%.20g', '%#e', '%#f', '%#g', '%#.20e', '%#.15f', '%#.3g']: Modified: python/branches/py3k-cdecimal/Lib/test/test_fork1.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_fork1.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_fork1.py Sun Jan 2 13:18:37 2011 @@ -8,13 +8,14 @@ import time from test.fork_wait import ForkWait -from test.support import run_unittest, reap_children, get_attribute, import_module +from test.support import (run_unittest, reap_children, get_attribute, + import_module, verbose) + threading = import_module('threading') # Skip test if fork does not exist. get_attribute(os, 'fork') - class ForkTest(ForkWait): def wait_impl(self, cpid): for i in range(10): @@ -28,7 +29,8 @@ self.assertEqual(spid, cpid) self.assertEqual(status, 0, "cause = %d, exit = %d" % (status&0xff, status>>8)) - def test_import_lock_fork(self): + def test_threaded_import_lock_fork(self): + """Check fork() in main thread works while a subthread is doing an import""" import_started = threading.Event() fake_module_name = "fake test module" partial_module = "partial" @@ -45,11 +47,16 @@ import_started.wait() pid = os.fork() try: + # PyOS_BeforeFork should have waited for the import to complete + # before forking, so the child can recreate the import lock + # correctly, but also won't see a partially initialised module if not pid: m = __import__(fake_module_name) if m == complete_module: os._exit(0) else: + if verbose > 1: + print("Child encountered partial module") os._exit(1) else: t.join() @@ -63,6 +70,39 @@ except OSError: pass + + def test_nested_import_lock_fork(self): + """Check fork() in main thread works while the main thread is doing an import""" + # Issue 9573: this used to trigger RuntimeError in the child process + def fork_with_import_lock(level): + release = 0 + in_child = False + try: + try: + for i in range(level): + imp.acquire_lock() + release += 1 + pid = os.fork() + in_child = not pid + finally: + for i in range(release): + imp.release_lock() + except RuntimeError: + if in_child: + if verbose > 1: + print("RuntimeError in child") + os._exit(1) + raise + if in_child: + os._exit(0) + self.wait_impl(pid) + + # Check this works with various levels of nested + # import in the main thread + for level in range(5): + fork_with_import_lock(level) + + def test_main(): run_unittest(ForkTest) reap_children() Modified: python/branches/py3k-cdecimal/Lib/test/test_fractions.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_fractions.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_fractions.py Sun Jan 2 13:18:37 2011 @@ -1,7 +1,7 @@ """Tests for Lib/fractions.py.""" from decimal import Decimal -from test.support import run_unittest +from test.support import run_unittest, requires_IEEE_754 import math import numbers import operator @@ -12,11 +12,6 @@ F = fractions.Fraction gcd = fractions.gcd -# decorator for skipping tests on non-IEEE 754 platforms -requires_IEEE_754 = unittest.skipUnless( - float.__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") - class DummyFloat(object): """Dummy float class for testing comparisons with Fractions""" Modified: python/branches/py3k-cdecimal/Lib/test/test_functools.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_functools.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_functools.py Sun Jan 2 13:18:37 2011 @@ -146,6 +146,32 @@ join = self.thetype(''.join) self.assertEqual(join(data), '0123456789') + def test_repr(self): + args = (object(), object()) + args_repr = ', '.join(repr(a) for a in args) + kwargs = {'a': object(), 'b': object()} + kwargs_repr = ', '.join("%s=%r" % (k, v) for k, v in kwargs.items()) + if self.thetype is functools.partial: + name = 'functools.partial' + else: + name = self.thetype.__name__ + + f = self.thetype(capture) + self.assertEqual('{}({!r})'.format(name, capture), + repr(f)) + + f = self.thetype(capture, *args) + self.assertEqual('{}({!r}, {})'.format(name, capture, args_repr), + repr(f)) + + f = self.thetype(capture, **kwargs) + self.assertEqual('{}({!r}, {})'.format(name, capture, kwargs_repr), + repr(f)) + + f = self.thetype(capture, *args, **kwargs) + self.assertEqual('{}({!r}, {}, {})'.format(name, capture, args_repr, kwargs_repr), + repr(f)) + def test_pickle(self): f = self.thetype(signature, 'asdf', bar=True) f.add_something_to__dict__ = True @@ -163,6 +189,9 @@ thetype = PythonPartial + # the python version hasn't a nice repr + def test_repr(self): pass + # the python version isn't picklable def test_pickle(self): pass @@ -501,6 +530,11 @@ def orig(x, y): return 3*x+y f = functools.lru_cache(maxsize=20)(orig) + hits, misses, maxsize, currsize = f.cache_info() + self.assertEqual(maxsize, 20) + self.assertEqual(currsize, 0) + self.assertEqual(hits, 0) + self.assertEqual(misses, 0) domain = range(5) for i in range(1000): @@ -508,21 +542,29 @@ actual = f(x, y) expected = orig(x, y) self.assertEqual(actual, expected) - self.assertTrue(f.cache_hits > f.cache_misses) - self.assertEqual(f.cache_hits + f.cache_misses, 1000) + hits, misses, maxsize, currsize = f.cache_info() + self.assertTrue(hits > misses) + self.assertEqual(hits + misses, 1000) + self.assertEqual(currsize, 20) f.cache_clear() # test clearing - self.assertEqual(f.cache_hits, 0) - self.assertEqual(f.cache_misses, 0) + hits, misses, maxsize, currsize = f.cache_info() + self.assertEqual(hits, 0) + self.assertEqual(misses, 0) + self.assertEqual(currsize, 0) f(x, y) - self.assertEqual(f.cache_hits, 0) - self.assertEqual(f.cache_misses, 1) + hits, misses, maxsize, currsize = f.cache_info() + self.assertEqual(hits, 0) + self.assertEqual(misses, 1) + self.assertEqual(currsize, 1) # Test bypassing the cache self.assertIs(f.__wrapped__, orig) f.__wrapped__(x, y) - self.assertEqual(f.cache_hits, 0) - self.assertEqual(f.cache_misses, 1) + hits, misses, maxsize, currsize = f.cache_info() + self.assertEqual(hits, 0) + self.assertEqual(misses, 1) + self.assertEqual(currsize, 1) # test size zero (which means "never-cache") @functools.lru_cache(0) @@ -530,10 +572,15 @@ nonlocal f_cnt f_cnt += 1 return 20 + self.assertEqual(f.cache_info().maxsize, 0) f_cnt = 0 for i in range(5): self.assertEqual(f(), 20) self.assertEqual(f_cnt, 5) + hits, misses, maxsize, currsize = f.cache_info() + self.assertEqual(hits, 0) + self.assertEqual(misses, 5) + self.assertEqual(currsize, 0) # test size one @functools.lru_cache(1) @@ -541,10 +588,15 @@ nonlocal f_cnt f_cnt += 1 return 20 + self.assertEqual(f.cache_info().maxsize, 1) f_cnt = 0 for i in range(5): self.assertEqual(f(), 20) self.assertEqual(f_cnt, 1) + hits, misses, maxsize, currsize = f.cache_info() + self.assertEqual(hits, 4) + self.assertEqual(misses, 1) + self.assertEqual(currsize, 1) # test size two @functools.lru_cache(2) @@ -552,11 +604,30 @@ nonlocal f_cnt f_cnt += 1 return x*10 + self.assertEqual(f.cache_info().maxsize, 2) f_cnt = 0 for x in 7, 9, 7, 9, 7, 9, 8, 8, 8, 9, 9, 9, 8, 8, 8, 7: # * * * * self.assertEqual(f(x), x*10) self.assertEqual(f_cnt, 4) + hits, misses, maxsize, currsize = f.cache_info() + self.assertEqual(hits, 12) + self.assertEqual(misses, 4) + self.assertEqual(currsize, 2) + + def test_lru_with_maxsize_none(self): + @functools.lru_cache(maxsize=None) + def fib(n): + if n < 2: + return n + return fib(n-1) + fib(n-2) + self.assertEqual([fib(n) for n in range(16)], + [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]) + self.assertEqual(fib.cache_info(), + functools._CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)) + fib.cache_clear() + self.assertEqual(fib.cache_info(), + functools._CacheInfo(hits=0, misses=0, maxsize=None, currsize=0)) def test_main(verbose=None): test_classes = ( Modified: python/branches/py3k-cdecimal/Lib/test/test_grp.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_grp.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_grp.py Sun Jan 2 13:18:37 2011 @@ -33,12 +33,16 @@ e2 = grp.getgrgid(e.gr_gid) self.check_value(e2) self.assertEqual(e2.gr_gid, e.gr_gid) - e2 = grp.getgrnam(e.gr_name) + name = e.gr_name + if name.startswith('+') or name.startswith('-'): + # NIS-related entry + continue + e2 = grp.getgrnam(name) self.check_value(e2) # There are instances where getgrall() returns group names in # lowercase while getgrgid() returns proper casing. # Discovered on Ubuntu 5.04 (custom). - self.assertEqual(e2.gr_name.lower(), e.gr_name.lower()) + self.assertEqual(e2.gr_name.lower(), name.lower()) def test_errors(self): self.assertRaises(TypeError, grp.getgrgid) Modified: python/branches/py3k-cdecimal/Lib/test/test_htmlparser.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_htmlparser.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_htmlparser.py Sun Jan 2 13:18:37 2011 @@ -8,10 +8,10 @@ class EventCollector(html.parser.HTMLParser): - def __init__(self): + def __init__(self, *args, **kw): self.events = [] self.append = self.events.append - html.parser.HTMLParser.__init__(self) + html.parser.HTMLParser.__init__(self, *args, **kw) def get_events(self): # Normalize the list of events so that buffer artefacts don't @@ -72,8 +72,10 @@ class TestCaseBase(unittest.TestCase): - def _run_check(self, source, expected_events, collector=EventCollector): - parser = collector() + def _run_check(self, source, expected_events, collector=None): + if collector is None: + collector = EventCollector() + parser = collector for s in source: parser.feed(s) parser.close() @@ -84,7 +86,7 @@ "\nReceived:\n" + pprint.pformat(events)) def _run_check_extra(self, source, events): - self._run_check(source, events, EventCollectorExtra) + self._run_check(source, events, EventCollectorExtra()) def _parse_error(self, source): def parse(source=source): @@ -321,8 +323,47 @@ ]) +class HTMLParserTolerantTestCase(TestCaseBase): + + def setUp(self): + self.collector = EventCollector(strict=False) + + def test_tolerant_parsing(self): + self._run_check('te>>xt&a<\n' + '', [ + ('starttag', 'form', + [('action', '/xxx.php?a=1&b=2&'), + ('method', 'post')])], + collector = self.collector) + + def test_weird_chars_in_unquoted_attribute_values(self): + self._run_check('
', [ + ('starttag', 'form', + [('action', 'bogus|&#()value')])], + collector = self.collector) + + def test_unescape_function(self): + p = html.parser.HTMLParser() + self.assertEqual(p.unescape('&#bad;'),'&#bad;') + self.assertEqual(p.unescape('&'),'&') + + def test_main(): - support.run_unittest(HTMLParserTestCase) + support.run_unittest(HTMLParserTestCase, HTMLParserTolerantTestCase) if __name__ == "__main__": Modified: python/branches/py3k-cdecimal/Lib/test/test_http_cookies.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_http_cookies.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_http_cookies.py Sun Jan 2 13:18:37 2011 @@ -69,6 +69,14 @@ """) + def test_extended_encode(self): + # Issue 9824: some browsers don't follow the standard; we now + # encode , and ; to keep them from tripping up. + C = cookies.SimpleCookie() + C['val'] = "some,funky;stuff" + self.assertEqual(C.output(['val']), + 'Set-Cookie: val="some\\054funky\\073stuff"') + def test_special_attrs(self): # 'expires' C = cookies.SimpleCookie('Customer="WILE_E_COYOTE"') Modified: python/branches/py3k-cdecimal/Lib/test/test_httplib.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_httplib.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_httplib.py Sun Jan 2 13:18:37 2011 @@ -230,6 +230,22 @@ conn.send(io.BytesIO(expected)) self.assertEqual(expected, sock.data) + def test_send_iter(self): + expected = b'GET /foo HTTP/1.1\r\nHost: example.com\r\n' \ + b'Accept-Encoding: identity\r\nContent-Length: 11\r\n' \ + b'\r\nonetwothree' + + def body(): + yield b"one" + yield b"two" + yield b"three" + + conn = client.HTTPConnection('example.com') + sock = FakeSocket("") + conn.sock = sock + conn.request('GET', '/foo', body(), {'Content-Length': '11'}) + self.assertEquals(sock.data, expected) + def test_chunked(self): chunked_start = ( 'HTTP/1.1 200 OK\r\n' @@ -317,6 +333,33 @@ self.assertEqual("Basic realm=\"example\"", resp.getheader("www-authenticate")) + # Test lines overflowing the max line size (_MAXLINE in http.client) + + def test_overflowing_status_line(self): + body = "HTTP/1.1 200 Ok" + "k" * 65536 + "\r\n" + resp = client.HTTPResponse(FakeSocket(body)) + self.assertRaises((client.LineTooLong, client.BadStatusLine), resp.begin) + + def test_overflowing_header_line(self): + body = ( + 'HTTP/1.1 200 OK\r\n' + 'X-Foo: bar' + 'r' * 65536 + '\r\n\r\n' + ) + resp = client.HTTPResponse(FakeSocket(body)) + self.assertRaises(client.LineTooLong, resp.begin) + + def test_overflowing_chunked_line(self): + body = ( + 'HTTP/1.1 200 OK\r\n' + 'Transfer-Encoding: chunked\r\n\r\n' + + '0' * 65536 + 'a\r\n' + 'hello world\r\n' + '0\r\n' + ) + resp = client.HTTPResponse(FakeSocket(body)) + resp.begin() + self.assertRaises(client.LineTooLong, resp.read) + class OfflineTest(TestCase): def test_responses(self): self.assertEqual(client.responses[client.NOT_FOUND], "Not Found") Modified: python/branches/py3k-cdecimal/Lib/test/test_httpservers.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_httpservers.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_httpservers.py Sun Jan 2 13:18:37 2011 @@ -566,6 +566,19 @@ self.assertEqual(sum(r == b'Connection: close\r\n' for r in result[1:-1]), 1) self.handler = usual_handler # Restore to avoid breaking any subsequent tests. + def test_request_length(self): + # Issue #10714: huge request lines are discarded, to avoid Denial + # of Service attacks. + result = self.send_typical_request(b'GET ' + b'x' * 65537) + self.assertEqual(result[0], b'HTTP/1.1 414 Request-URI Too Long\r\n') + self.assertFalse(self.handler.get_called) + + def test_header_length(self): + # Issue #6791: same for headers + result = self.send_typical_request( + b'GET / HTTP/1.1\r\nX-Foo: bar' + b'r' * 65537 + b'\r\n\r\n') + self.assertEqual(result[0], b'HTTP/1.1 400 Line too long\r\n') + self.assertFalse(self.handler.get_called) class SimpleHTTPRequestHandlerTestCase(unittest.TestCase): """ Test url parsing """ Modified: python/branches/py3k-cdecimal/Lib/test/test_import.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_import.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_import.py Sun Jan 2 13:18:37 2011 @@ -9,11 +9,13 @@ import stat import sys import unittest +import textwrap from test.support import ( EnvironmentVarGuard, TESTFN, check_warnings, forget, is_jython, make_legacy_pyc, rmtree, run_unittest, swap_attr, swap_item, temp_umask, unlink, unload) +from test import script_helper def remove_files(name): @@ -284,6 +286,17 @@ self.assertEqual("Import by filename is not supported.", c.exception.args[0]) + def test_import_in_del_does_not_crash(self): + # Issue 4236 + testfn = script_helper.make_script('', TESTFN, textwrap.dedent("""\ + import sys + class C: + def __del__(self): + import imp + sys.argv.insert(0, C()) + """)) + script_helper.assert_python_ok(testfn) + class PycRewritingTests(unittest.TestCase): # Test that the `co_filename` attribute on code objects always points Modified: python/branches/py3k-cdecimal/Lib/test/test_inspect.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_inspect.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_inspect.py Sun Jan 2 13:18:37 2011 @@ -6,9 +6,11 @@ import linecache import datetime import collections +import os +import shutil from os.path import normcase -from test.support import run_unittest +from test.support import run_unittest, TESTFN, DirsOnSysPath from test import inspect_fodder as mod from test import inspect_fodder2 as mod2 @@ -194,12 +196,12 @@ class GetSourceBase(unittest.TestCase): # Subclasses must override. - fodderFile = None + fodderModule = None def __init__(self, *args, **kwargs): unittest.TestCase.__init__(self, *args, **kwargs) - with open(inspect.getsourcefile(self.fodderFile)) as fp: + with open(inspect.getsourcefile(self.fodderModule)) as fp: self.source = fp.read() def sourcerange(self, top, bottom): @@ -211,7 +213,7 @@ self.sourcerange(top, bottom)) class TestRetrievingSourceCode(GetSourceBase): - fodderFile = mod + fodderModule = mod def test_getclasses(self): classes = inspect.getmembers(mod, inspect.isclass) @@ -297,7 +299,7 @@ inspect.getmodule(compile('a=10','','single')) class TestDecorators(GetSourceBase): - fodderFile = mod2 + fodderModule = mod2 def test_wrapped_decorator(self): self.assertSourceEqual(mod2.wrapped, 14, 17) @@ -306,7 +308,7 @@ self.assertSourceEqual(mod2.gone, 9, 10) class TestOneliners(GetSourceBase): - fodderFile = mod2 + fodderModule = mod2 def test_oneline_lambda(self): # Test inspect.getsource with a one-line lambda function. self.assertSourceEqual(mod2.oll, 25, 25) @@ -348,7 +350,7 @@ self.assertSourceEqual(mod2.anonymous, 55, 55) class TestBuggyCases(GetSourceBase): - fodderFile = mod2 + fodderModule = mod2 def test_with_comment(self): self.assertSourceEqual(mod2.with_comment, 58, 59) @@ -388,6 +390,24 @@ self.assertEqual(inspect.findsource(co), (lines,0)) self.assertEqual(inspect.getsource(co), lines[0]) +class TestNoEOL(GetSourceBase): + def __init__(self, *args, **kwargs): + self.tempdir = TESTFN + '_dir' + os.mkdir(self.tempdir) + with open(os.path.join(self.tempdir, + 'inspect_fodder3%spy' % os.extsep), 'w') as f: + f.write("class X:\n pass # No EOL") + with DirsOnSysPath(self.tempdir): + import inspect_fodder3 as mod3 + self.fodderModule = mod3 + GetSourceBase.__init__(self, *args, **kwargs) + + def tearDown(self): + shutil.rmtree(self.tempdir) + + def test_class(self): + self.assertSourceEqual(self.fodderModule.X, 1, 2) + # Helper for testing classify_class_attrs. def attrs_wo_objs(cls): return [t[:3] for t in inspect.classify_class_attrs(cls)] @@ -931,13 +951,22 @@ # Running after the first yield next(self.generator) + def test_easy_debugging(self): + # repr() and str() of a generator state should contain the state name + names = 'GEN_CREATED GEN_RUNNING GEN_SUSPENDED GEN_CLOSED'.split() + for name in names: + state = getattr(inspect, name) + self.assertIn(name, repr(state)) + self.assertIn(name, str(state)) + def test_main(): run_unittest( TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases, TestInterpreterStack, TestClassesAndFunctions, TestPredicates, TestGetcallargsFunctions, TestGetcallargsMethods, - TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState + TestGetcallargsUnboundMethods, TestGetattrStatic, TestGetGeneratorState, + TestNoEOL ) if __name__ == "__main__": Modified: python/branches/py3k-cdecimal/Lib/test/test_int.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_int.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_int.py Sun Jan 2 13:18:37 2011 @@ -20,7 +20,8 @@ (' 1\02 ', ValueError), ('', ValueError), (' ', ValueError), - (' \t\t ', ValueError) + (' \t\t ', ValueError), + ("\u0200", ValueError) ] class IntTestCases(unittest.TestCase): @@ -35,6 +36,8 @@ self.assertEqual(int(3.5), 3) self.assertEqual(int(-3.5), -3) self.assertEqual(int("-3"), -3) + self.assertEqual(int(" -3 "), -3) + self.assertEqual(int("\N{EM SPACE}-3\N{EN SPACE}"), -3) # Different base: self.assertEqual(int("10",16), 16) # Test conversion from strings and various anomalies @@ -302,6 +305,16 @@ self.fail("Failed to raise TypeError with %s" % ((base, trunc_result_base),)) + def test_error_message(self): + testlist = ('\xbd', '123\xbd', ' 123 456 ') + for s in testlist: + try: + int(s) + except ValueError as e: + self.assertIn(s.strip(), e.args[0]) + else: + self.fail("Expected int(%r) to raise a ValueError", s) + def test_main(): run_unittest(IntTestCases) Modified: python/branches/py3k-cdecimal/Lib/test/test_io.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_io.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_io.py Sun Jan 2 13:18:37 2011 @@ -730,6 +730,13 @@ self.assertRaises(self.UnsupportedOperation, bufio.tell) self.assertRaises(self.UnsupportedOperation, bufio.seek, 0) + def test_readonly_attributes(self): + raw = self.MockRawIO() + buf = self.tp(raw) + x = self.MockRawIO() + with self.assertRaises(AttributeError): + buf.raw = x + class BufferedReaderTest(unittest.TestCase, CommonBufferedTests): read_mode = "rb" @@ -2245,6 +2252,12 @@ self.assertRaises(self.UnsupportedOperation, txt.tell) self.assertRaises(self.UnsupportedOperation, txt.seek, 0) + def test_readonly_attributes(self): + txt = self.TextIOWrapper(self.BytesIO(self.testdata), encoding="ascii") + buf = self.BytesIO(self.testdata) + with self.assertRaises(AttributeError): + txt.buffer = buf + class CTextIOWrapperTest(TextIOWrapperTest): def test_initialization(self): @@ -2653,12 +2666,50 @@ def test_interrupted_write_text(self): self.check_interrupted_write("xy", b"xy", mode="w", encoding="ascii") + def check_reentrant_write(self, data, **fdopen_kwargs): + def on_alarm(*args): + # Will be called reentrantly from the same thread + wio.write(data) + 1/0 + signal.signal(signal.SIGALRM, on_alarm) + r, w = os.pipe() + wio = self.io.open(w, **fdopen_kwargs) + try: + signal.alarm(1) + # Either the reentrant call to wio.write() fails with RuntimeError, + # or the signal handler raises ZeroDivisionError. + with self.assertRaises((ZeroDivisionError, RuntimeError)) as cm: + while 1: + for i in range(100): + wio.write(data) + wio.flush() + # Make sure the buffer doesn't fill up and block further writes + os.read(r, len(data) * 100) + exc = cm.exception + if isinstance(exc, RuntimeError): + self.assertTrue(str(exc).startswith("reentrant call"), str(exc)) + finally: + wio.close() + os.close(r) + + def test_reentrant_write_buffered(self): + self.check_reentrant_write(b"xy", mode="wb") + + def test_reentrant_write_text(self): + self.check_reentrant_write("xy", mode="w", encoding="ascii") + + class CSignalsTest(SignalsTest): io = io class PySignalsTest(SignalsTest): io = pyio + # Handling reentrancy issues would slow down _pyio even more, so the + # tests are disabled. + test_reentrant_write_buffered = None + test_reentrant_write_text = None + def test_main(): tests = (CIOTest, PyIOTest, Modified: python/branches/py3k-cdecimal/Lib/test/test_itertools.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_itertools.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_itertools.py Sun Jan 2 13:18:37 2011 @@ -56,6 +56,24 @@ return prod(range(1, n+1)) class TestBasicOps(unittest.TestCase): + + def test_accumulate(self): + self.assertEqual(list(accumulate(range(10))), # one positional arg + [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]) + self.assertEqual(list(accumulate(iterable=range(10))), # kw arg + [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]) + for typ in int, complex, Decimal, Fraction: # multiple types + self.assertEqual( + list(accumulate(map(typ, range(10)))), + list(map(typ, [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]))) + self.assertEqual(list(accumulate('abc')), ['a', 'ab', 'abc']) # works with non-numeric + self.assertEqual(list(accumulate([])), []) # empty iterable + self.assertEqual(list(accumulate([7])), [7]) # iterable of length one + self.assertRaises(TypeError, accumulate, range(10), 5) # too many args + self.assertRaises(TypeError, accumulate) # too few args + self.assertRaises(TypeError, accumulate, x=range(10)) # unexpected kwd arg + self.assertRaises(TypeError, list, accumulate([1, []])) # args that don't add + def test_chain(self): def chain2(*iterables): @@ -788,6 +806,11 @@ self.assertRaises(ValueError, islice, range(10), 1, 'a', 1) self.assertEqual(len(list(islice(count(), 1, 10, maxsize))), 1) + # Issue #10323: Less islice in a predictable state + c = count() + self.assertEqual(list(islice(c, 1, 3, 50)), [1]) + self.assertEqual(next(c), 3) + def test_takewhile(self): data = [1, 3, 5, 20, 2, 4, 6, 8] underten = lambda x: x<10 @@ -927,6 +950,9 @@ class TestExamples(unittest.TestCase): + def test_accumlate(self): + self.assertEqual(list(accumulate([1,2,3,4,5])), [1, 3, 6, 10, 15]) + def test_chain(self): self.assertEqual(''.join(chain('ABC', 'DEF')), 'ABCDEF') @@ -1014,6 +1040,10 @@ next(iterator) del container, iterator + def test_accumulate(self): + a = [] + self.makecycle(accumulate([1,2,a,3]), a) + def test_chain(self): a = [] self.makecycle(chain(a), a) @@ -1183,6 +1213,17 @@ class TestVariousIteratorArgs(unittest.TestCase): + def test_accumulate(self): + s = [1,2,3,4,5] + r = [1,3,6,10,15] + n = len(s) + for g in (G, I, Ig, L, R): + self.assertEqual(list(accumulate(g(s))), r) + self.assertEqual(list(accumulate(S(s))), []) + self.assertRaises(TypeError, accumulate, X(s)) + self.assertRaises(TypeError, accumulate, N(s)) + self.assertRaises(ZeroDivisionError, list, accumulate(E(s))) + def test_chain(self): for s in ("123", "", range(1000), ('do', 1.2), range(2000,2200,5)): for g in (G, I, Ig, S, L, R): Modified: python/branches/py3k-cdecimal/Lib/test/test_json.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_json.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_json.py Sun Jan 2 13:18:37 2011 @@ -5,12 +5,12 @@ be run. """ -import json.tests +from test import json_tests import test.support def test_main(): - test.support.run_unittest(json.tests.test_suite()) + test.support.run_unittest(json_tests.test_suite()) if __name__ == "__main__": Modified: python/branches/py3k-cdecimal/Lib/test/test_listcomps.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_listcomps.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_listcomps.py Sun Jan 2 13:18:37 2011 @@ -146,299 +146,3 @@ if __name__ == "__main__": test_main(verbose=True) -doctests = """ -########### Tests borrowed from or inspired by test_genexps.py ############ - -Test simple loop with conditional - - >>> sum([i*i for i in range(100) if i&1 == 1]) - 166650 - -Test simple nesting - - >>> [(i,j) for i in range(3) for j in range(4)] - [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] - -Test nesting with the inner expression dependent on the outer - - >>> [(i,j) for i in range(4) for j in range(i)] - [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)] - -Make sure the induction variable is not exposed - - >>> i = 20 - >>> sum([i*i for i in range(100)]) - 328350 - - >>> i - 20 - -Verify that syntax error's are raised for listcomps used as lvalues - - >>> [y for y in (1,2)] = 10 # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - SyntaxError: ... - - >>> [y for y in (1,2)] += 10 # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - SyntaxError: ... - - -########### Tests borrowed from or inspired by test_generators.py ############ - -Make a nested list comprehension that acts like range() - - >>> def frange(n): - ... return [i for i in range(n)] - >>> frange(10) - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - -Same again, only as a lambda expression instead of a function definition - - >>> lrange = lambda n: [i for i in range(n)] - >>> lrange(10) - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - -Generators can call other generators: - - >>> def grange(n): - ... for x in [i for i in range(n)]: - ... yield x - >>> list(grange(5)) - [0, 1, 2, 3, 4] - - -Make sure that None is a valid return value - - >>> [None for i in range(10)] - [None, None, None, None, None, None, None, None, None, None] - -########### Tests for various scoping corner cases ############ - -Return lambdas that use the iteration variable as a default argument - - >>> items = [(lambda i=i: i) for i in range(5)] - >>> [x() for x in items] - [0, 1, 2, 3, 4] - -Same again, only this time as a closure variable - - >>> items = [(lambda: i) for i in range(5)] - >>> [x() for x in items] - [4, 4, 4, 4, 4] - -Another way to test that the iteration variable is local to the list comp - - >>> items = [(lambda: i) for i in range(5)] - >>> i = 20 - >>> [x() for x in items] - [4, 4, 4, 4, 4] - -And confirm that a closure can jump over the list comp scope - - >>> items = [(lambda: y) for i in range(5)] - >>> y = 2 - >>> [x() for x in items] - [2, 2, 2, 2, 2] - -We also repeat each of the above scoping tests inside a function - - >>> def test_func(): - ... items = [(lambda i=i: i) for i in range(5)] - ... return [x() for x in items] - >>> test_func() - [0, 1, 2, 3, 4] - - >>> def test_func(): - ... items = [(lambda: i) for i in range(5)] - ... return [x() for x in items] - >>> test_func() - [4, 4, 4, 4, 4] - - >>> def test_func(): - ... items = [(lambda: i) for i in range(5)] - ... i = 20 - ... return [x() for x in items] - >>> test_func() - [4, 4, 4, 4, 4] - - >>> def test_func(): - ... items = [(lambda: y) for i in range(5)] - ... y = 2 - ... return [x() for x in items] - >>> test_func() - [2, 2, 2, 2, 2] - -""" - - -__test__ = {'doctests' : doctests} - -def test_main(verbose=None): - import sys - from test import support - from test import test_listcomps - support.run_doctest(test_listcomps, verbose) - - # verify reference counting - if verbose and hasattr(sys, "gettotalrefcount"): - import gc - counts = [None] * 5 - for i in range(len(counts)): - support.run_doctest(test_genexps, verbose) - gc.collect() - counts[i] = sys.gettotalrefcount() - print(counts) - -if __name__ == "__main__": - test_main(verbose=True) -doctests = """ -########### Tests borrowed from or inspired by test_genexps.py ############ - -Test simple loop with conditional - - >>> sum([i*i for i in range(100) if i&1 == 1]) - 166650 - -Test simple nesting - - >>> [(i,j) for i in range(3) for j in range(4)] - [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3)] - -Test nesting with the inner expression dependent on the outer - - >>> [(i,j) for i in range(4) for j in range(i)] - [(1, 0), (2, 0), (2, 1), (3, 0), (3, 1), (3, 2)] - -Make sure the induction variable is not exposed - - >>> i = 20 - >>> sum([i*i for i in range(100)]) - 328350 - - >>> i - 20 - -Verify that syntax error's are raised for listcomps used as lvalues - - >>> [y for y in (1,2)] = 10 # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - SyntaxError: ... - - >>> [y for y in (1,2)] += 10 # doctest: +IGNORE_EXCEPTION_DETAIL - Traceback (most recent call last): - ... - SyntaxError: ... - - -########### Tests borrowed from or inspired by test_generators.py ############ - -Make a nested list comprehension that acts like range() - - >>> def frange(n): - ... return [i for i in range(n)] - >>> frange(10) - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - -Same again, only as a lambda expression instead of a function definition - - >>> lrange = lambda n: [i for i in range(n)] - >>> lrange(10) - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - -Generators can call other generators: - - >>> def grange(n): - ... for x in [i for i in range(n)]: - ... yield x - >>> list(grange(5)) - [0, 1, 2, 3, 4] - - -Make sure that None is a valid return value - - >>> [None for i in range(10)] - [None, None, None, None, None, None, None, None, None, None] - -########### Tests for various scoping corner cases ############ - -Return lambdas that use the iteration variable as a default argument - - >>> items = [(lambda i=i: i) for i in range(5)] - >>> [x() for x in items] - [0, 1, 2, 3, 4] - -Same again, only this time as a closure variable - - >>> items = [(lambda: i) for i in range(5)] - >>> [x() for x in items] - [4, 4, 4, 4, 4] - -Another way to test that the iteration variable is local to the list comp - - >>> items = [(lambda: i) for i in range(5)] - >>> i = 20 - >>> [x() for x in items] - [4, 4, 4, 4, 4] - -And confirm that a closure can jump over the list comp scope - - >>> items = [(lambda: y) for i in range(5)] - >>> y = 2 - >>> [x() for x in items] - [2, 2, 2, 2, 2] - -We also repeat each of the above scoping tests inside a function - - >>> def test_func(): - ... items = [(lambda i=i: i) for i in range(5)] - ... return [x() for x in items] - >>> test_func() - [0, 1, 2, 3, 4] - - >>> def test_func(): - ... items = [(lambda: i) for i in range(5)] - ... return [x() for x in items] - >>> test_func() - [4, 4, 4, 4, 4] - - >>> def test_func(): - ... items = [(lambda: i) for i in range(5)] - ... i = 20 - ... return [x() for x in items] - >>> test_func() - [4, 4, 4, 4, 4] - - >>> def test_func(): - ... items = [(lambda: y) for i in range(5)] - ... y = 2 - ... return [x() for x in items] - >>> test_func() - [2, 2, 2, 2, 2] - -""" - - -__test__ = {'doctests' : doctests} - -def test_main(verbose=None): - import sys - from test import support - from test import test_listcomps - support.run_doctest(test_listcomps, verbose) - - # verify reference counting - if verbose and hasattr(sys, "gettotalrefcount"): - import gc - counts = [None] * 5 - for i in range(len(counts)): - support.run_doctest(test_listcomps, verbose) - gc.collect() - counts[i] = sys.gettotalrefcount() - print(counts) - -if __name__ == "__main__": - test_main(verbose=True) Modified: python/branches/py3k-cdecimal/Lib/test/test_logging.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_logging.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_logging.py Sun Jan 2 13:18:37 2011 @@ -67,8 +67,12 @@ try: self.saved_handlers = logging._handlers.copy() self.saved_handler_list = logging._handlerList[:] - self.saved_loggers = logger_dict.copy() + self.saved_loggers = saved_loggers = logger_dict.copy() self.saved_level_names = logging._levelNames.copy() + self.logger_states = logger_states = {} + for name in saved_loggers: + logger_states[name] = getattr(saved_loggers[name], + 'disabled', None) finally: logging._releaseLock() @@ -86,8 +90,12 @@ self.root_hdlr = logging.StreamHandler(self.stream) self.root_formatter = logging.Formatter(self.log_format) self.root_hdlr.setFormatter(self.root_formatter) - self.assertFalse(self.logger1.hasHandlers()) - self.assertFalse(self.logger2.hasHandlers()) + if self.logger1.hasHandlers(): + hlist = self.logger1.handlers + self.root_logger.handlers + raise AssertionError('Unexpected handlers: %s' % hlist) + if self.logger2.hasHandlers(): + hlist = self.logger2.handlers + self.root_logger.handlers + raise AssertionError('Unexpected handlers: %s' % hlist) self.root_logger.addHandler(self.root_hdlr) self.assertTrue(self.logger1.hasHandlers()) self.assertTrue(self.logger2.hasHandlers()) @@ -112,6 +120,10 @@ loggerDict = logging.getLogger().manager.loggerDict loggerDict.clear() loggerDict.update(self.saved_loggers) + logger_states = self.logger_states + for name in self.logger_states: + if logger_states[name] is not None: + self.saved_loggers[name].disabled = logger_states[name] finally: logging._releaseLock() @@ -907,7 +919,8 @@ def test_encoding_plain_file(self): # In Python 2.x, a plain file object is treated as having no encoding. log = logging.getLogger("test") - fn = tempfile.mktemp(".log", "test_logging-1-") + fd, fn = tempfile.mkstemp(".log", "test_logging-1-") + os.close(fd) # the non-ascii data we write to the log. data = "foo\x80" try: @@ -1799,7 +1812,7 @@ class DerivedLogRecord(logging.LogRecord): pass -class LogRecordClassTest(BaseTest): +class LogRecordFactoryTest(BaseTest): def setUp(self): class CheckingFilter(logging.Filter): @@ -1817,17 +1830,17 @@ BaseTest.setUp(self) self.filter = CheckingFilter(DerivedLogRecord) self.root_logger.addFilter(self.filter) - self.orig_cls = logging.getLogRecordClass() + self.orig_factory = logging.getLogRecordFactory() def tearDown(self): self.root_logger.removeFilter(self.filter) BaseTest.tearDown(self) - logging.setLogRecordClass(self.orig_cls) + logging.setLogRecordFactory(self.orig_factory) def test_logrecord_class(self): self.assertRaises(TypeError, self.root_logger.warning, self.next_message()) - logging.setLogRecordClass(DerivedLogRecord) + logging.setLogRecordFactory(DerivedLogRecord) self.root_logger.error(self.next_message()) self.assert_log_lines([ ('root', 'ERROR', '2'), @@ -1885,7 +1898,7 @@ return logging.makeLogRecord(result) def test_percent(self): - "Test %-formatting" + # Test %-formatting r = self.get_record() f = logging.Formatter('${%(message)s}') self.assertEqual(f.format(r), '${Message with 2 placeholders}') @@ -1898,7 +1911,7 @@ self.assertFalse(f.usesTime()) def test_braces(self): - "Test {}-formatting" + # Test {}-formatting r = self.get_record() f = logging.Formatter('$%{message}%$', style='{') self.assertEqual(f.format(r), '$%Message with 2 placeholders%$') @@ -1911,7 +1924,7 @@ self.assertFalse(f.usesTime()) def test_dollars(self): - "Test $-formatting" + # Test $-formatting r = self.get_record() f = logging.Formatter('$message', style='$') self.assertEqual(f.format(r), 'Message with 2 placeholders') @@ -1927,17 +1940,54 @@ f = logging.Formatter('asctime', style='$') self.assertFalse(f.usesTime()) +class LastResortTest(BaseTest): + def test_last_resort(self): + # Test the last resort handler + root = self.root_logger + root.removeHandler(self.root_hdlr) + old_stderr = sys.stderr + old_lastresort = logging.lastResort + old_raise_exceptions = logging.raiseExceptions + try: + sys.stderr = sio = io.StringIO() + root.warning('This is your final chance!') + self.assertEqual(sio.getvalue(), 'This is your final chance!\n') + #No handlers and no last resort, so 'No handlers' message + logging.lastResort = None + sys.stderr = sio = io.StringIO() + root.warning('This is your final chance!') + self.assertEqual(sio.getvalue(), 'No handlers could be found for logger "root"\n') + # 'No handlers' message only printed once + sys.stderr = sio = io.StringIO() + root.warning('This is your final chance!') + self.assertEqual(sio.getvalue(), '') + root.manager.emittedNoHandlerWarning = False + #If raiseExceptions is False, no message is printed + logging.raiseExceptions = False + sys.stderr = sio = io.StringIO() + root.warning('This is your final chance!') + self.assertEqual(sio.getvalue(), '') + finally: + sys.stderr = old_stderr + root.addHandler(self.root_hdlr) + logging.lastResort = old_lastresort + logging.raiseExceptions = old_raise_exceptions + + class BaseFileTest(BaseTest): "Base class for handler tests that write log files" def setUp(self): BaseTest.setUp(self) - self.fn = tempfile.mktemp(".log", "test_logging-2-") + fd, self.fn = tempfile.mkstemp(".log", "test_logging-2-") + os.close(fd) self.rmfiles = [] def tearDown(self): for fn in self.rmfiles: os.unlink(fn) + if os.path.exists(self.fn): + os.unlink(self.fn) BaseTest.tearDown(self) def assertLogFile(self, filename): @@ -1966,7 +2016,6 @@ def test_file_created(self): # checks that the file is created and assumes it was created # by us - self.assertFalse(os.path.exists(self.fn)) rh = logging.handlers.RotatingFileHandler(self.fn) rh.emit(self.next_rec()) self.assertLogFile(self.fn) @@ -2015,8 +2064,9 @@ ConfigFileTest, SocketHandlerTest, MemoryTest, EncodingTest, WarningsTest, ConfigDictTest, ManagerTest, FormatterTest, - LogRecordClassTest, ChildLoggerTest, QueueHandlerTest, + LogRecordFactoryTest, ChildLoggerTest, QueueHandlerTest, RotatingFileHandlerTest, + LastResortTest, #TimedRotatingFileHandlerTest ) Modified: python/branches/py3k-cdecimal/Lib/test/test_long.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_long.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_long.py Sun Jan 2 13:18:37 2011 @@ -1,5 +1,6 @@ import unittest from test import support + import sys import random @@ -15,11 +16,6 @@ def __str__(self): return self.format % self.args -# decorator for skipping tests on non-IEEE 754 platforms -requires_IEEE_754 = unittest.skipUnless( - float.__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") - # SHIFT should match the value in longintrepr.h for best testing. SHIFT = sys.int_info.bits_per_digit BASE = 2 ** SHIFT @@ -276,7 +272,7 @@ digits = digits or [0] return '-'[:sign] + \ {2: '0b', 8: '0o', 10: '', 16: '0x'}[base] + \ - "".join(map(lambda i: "0123456789abcdef"[i], digits)) + "".join("0123456789abcdef"[i] for i in digits) def check_format_1(self, x): for base, mapper in (8, oct), (10, repr), (16, hex): @@ -371,8 +367,7 @@ return 1729 self.assertEqual(int(LongTrunc()), 1729) - @unittest.skipUnless(float.__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") + @support.requires_IEEE_754 def test_float_conversion(self): exact_values = [0, 1, 2, @@ -703,7 +698,7 @@ self.assertEqual(expected, got, "Incorrectly rounded division {}/{}: " "expected {}, got {}".format(a, b, expected, got)) - @requires_IEEE_754 + @support.requires_IEEE_754 def test_correctly_rounded_true_division(self): # more stringent tests than those above, checking that the # result of true division of ints is always correctly rounded. Modified: python/branches/py3k-cdecimal/Lib/test/test_math.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_math.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_math.py Sun Jan 2 13:18:37 2011 @@ -1,7 +1,7 @@ # Python test set -- math module # XXXX Should not do tests around zero only -from test.support import run_unittest, verbose +from test.support import run_unittest, verbose, requires_IEEE_754 import unittest import math import os @@ -15,11 +15,6 @@ INF = float('inf') NINF = float('-inf') -# decorator for skipping tests on non-IEEE 754 platforms -requires_IEEE_754 = unittest.skipUnless( - float.__getformat__("double").startswith("IEEE"), - "test requires IEEE 754 doubles") - # detect evidence of double-rounding: fsum is not always correctly # rounded on machines that suffer from double rounding. x, y = 1e16, 2.9999 # use temporary values to defeat peephole optimizer Modified: python/branches/py3k-cdecimal/Lib/test/test_memoryview.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_memoryview.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_memoryview.py Sun Jan 2 13:18:37 2011 @@ -226,7 +226,7 @@ self.assertTrue(wr() is None, wr()) def _check_released(self, m, tp): - check = self.assertRaisesRegexp(ValueError, "released") + check = self.assertRaisesRegex(ValueError, "released") with check: bytes(m) with check: m.tobytes() with check: m.tolist() Modified: python/branches/py3k-cdecimal/Lib/test/test_multiprocessing.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_multiprocessing.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_multiprocessing.py Sun Jan 2 13:18:37 2011 @@ -815,8 +815,6 @@ # # - at unittest.skipUnless(HAS_SHAREDCTYPES, - "requires multiprocessing.sharedctypes") class _TestValue(BaseTestCase): ALLOWED_TYPES = ('processes',) @@ -828,6 +826,10 @@ ('c', latin('x'), latin('y')) ] + def setUp(self): + if not HAS_SHAREDCTYPES: + self.skipTest("requires multiprocessing.sharedctypes") + @classmethod def _test(cls, values): for sv, cv in zip(values, cls.codes_values): @@ -1662,12 +1664,14 @@ ('y', c_double) ] - at unittest.skipUnless(HAS_SHAREDCTYPES, - "requires multiprocessing.sharedctypes") class _TestSharedCTypes(BaseTestCase): ALLOWED_TYPES = ('processes',) + def setUp(self): + if not HAS_SHAREDCTYPES: + self.skipTest("requires multiprocessing.sharedctypes") + @classmethod def _double(cls, x, y, foo, arr, string): x.value *= 2 Modified: python/branches/py3k-cdecimal/Lib/test/test_netrc.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_netrc.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_netrc.py Sun Jan 2 13:18:37 2011 @@ -3,7 +3,13 @@ from test import support TEST_NETRC = """ + + #this is a comment +#this is a comment +# this is a comment + machine foo login log1 password pass1 account acct1 +machine bar login log1 password pass# account acct1 macdef macro1 line1 @@ -28,17 +34,21 @@ fp = open(temp_filename, mode) fp.write(TEST_NETRC) fp.close() + self.nrc = netrc.netrc(temp_filename) def tearDown(self): os.unlink(temp_filename) def test_case_1(self): - nrc = netrc.netrc(temp_filename) - self.assertTrue(nrc.macros == {'macro1':['line1\n', 'line2\n'], - 'macro2':['line3\n', 'line4\n']} - ) - self.assertTrue(nrc.hosts['foo'] == ('log1', 'acct1', 'pass1')) - self.assertTrue(nrc.hosts['default'] == ('log2', None, 'pass2')) + self.assertEqual(self.nrc.hosts['foo'], ('log1', 'acct1', 'pass1')) + self.assertEqual(self.nrc.hosts['default'], ('log2', None, 'pass2')) + + def test_macros(self): + self.assertEqual(self.nrc.macros, {'macro1':['line1\n', 'line2\n'], + 'macro2':['line3\n', 'line4\n']}) + + def test_parses_passwords_with_hash_character(self): + self.assertEqual(self.nrc.hosts['bar'], ('log1', 'acct1', 'pass#')) def test_main(): support.run_unittest(NetrcTestCase) Modified: python/branches/py3k-cdecimal/Lib/test/test_normalization.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_normalization.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_normalization.py Sun Jan 2 13:18:37 2011 @@ -45,6 +45,7 @@ check=check_version) except (IOError, HTTPException): self.skipTest("Could not retrieve " + TESTDATAURL) + self.addCleanup(testdata.close) for line in testdata: if '#' in line: line = line.split('#')[0] @@ -54,9 +55,6 @@ if line.startswith("@Part"): part = line.split()[0] continue - if part == "@Part3": - # XXX we don't support PRI #29 yet, so skip these tests for now - continue try: c1,c2,c3,c4,c5 = [unistr(x) for x in line.split(';')[:-1]] except RangeError: Modified: python/branches/py3k-cdecimal/Lib/test/test_ntpath.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_ntpath.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_ntpath.py Sun Jan 2 13:18:37 2011 @@ -248,7 +248,7 @@ self.assertFalse(ntpath.sameopenfile(tf1.fileno(), tf2.fileno())) # Make sure invalid values don't cause issues on win32 if sys.platform == "win32": - with self.assertRaises(ValueError): + with self.assertRaises(OSError): # Invalid file descriptors shouldn't display assert # dialogs (#4804) ntpath.sameopenfile(-1, -1) Modified: python/branches/py3k-cdecimal/Lib/test/test_os.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_os.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_os.py Sun Jan 2 13:18:37 2011 @@ -630,6 +630,28 @@ 'dir5', 'dir6') os.makedirs(path) + def test_exist_ok_existing_directory(self): + path = os.path.join(support.TESTFN, 'dir1') + mode = 0o777 + old_mask = os.umask(0o022) + os.makedirs(path, mode) + self.assertRaises(OSError, os.makedirs, path, mode) + self.assertRaises(OSError, os.makedirs, path, mode, exist_ok=False) + self.assertRaises(OSError, os.makedirs, path, 0o776, exist_ok=True) + os.makedirs(path, mode=mode, exist_ok=True) + os.umask(old_mask) + + def test_exist_ok_existing_regular_file(self): + base = support.TESTFN + path = os.path.join(support.TESTFN, 'dir1') + f = open(path, 'w') + f.write('abc') + f.close() + self.assertRaises(OSError, os.makedirs, path) + self.assertRaises(OSError, os.makedirs, path, exist_ok=False) + self.assertRaises(OSError, os.makedirs, path, exist_ok=True) + os.remove(path) + def tearDown(self): path = os.path.join(support.TESTFN, 'dir1', 'dir2', 'dir3', 'dir4', 'dir5', 'dir6') @@ -860,6 +882,42 @@ if hasattr(os, "write"): self.check(os.write, b" ") + +class LinkTests(unittest.TestCase): + def setUp(self): + self.file1 = support.TESTFN + self.file2 = os.path.join(support.TESTFN + "2") + + def tearDown(self): + for file in (self.file1, self.file2): + if os.path.exists(file): + os.unlink(file) + + def _test_link(self, file1, file2): + with open(file1, "w") as f1: + f1.write("test") + + os.link(file1, file2) + with open(file1, "r") as f1, open(file2, "r") as f2: + self.assertTrue(os.path.sameopenfile(f1.fileno(), f2.fileno())) + + def test_link(self): + self._test_link(self.file1, self.file2) + + def test_link_bytes(self): + self._test_link(bytes(self.file1, sys.getfilesystemencoding()), + bytes(self.file2, sys.getfilesystemencoding())) + + def test_unicode_name(self): + try: + os.fsencode("\xf1") + except UnicodeError: + raise unittest.SkipTest("Unable to encode for this platform.") + + self.file1 += "\xf1" + self.file2 = self.file1 + "2" + self._test_link(self.file1, self.file2) + if sys.platform != 'win32': class Win32ErrorTests(unittest.TestCase): pass @@ -1048,13 +1106,15 @@ "win_console_handler.py"), tagname], creationflags=subprocess.CREATE_NEW_PROCESS_GROUP) # Let the interpreter startup before we send signals. See #3137. - count, max = 0, 20 + count, max = 0, 100 while count < max and proc.poll() is None: if m[0] == 1: break - time.sleep(0.5) + time.sleep(0.1) count += 1 else: + # Forcefully kill the process if we weren't able to signal it. + os.kill(proc.pid, signal.SIGINT) self.fail("Subprocess didn't finish initialization") os.kill(proc.pid, event) # proc.send_signal(event) could also be done here. @@ -1088,12 +1148,6 @@ self._kill_with_event(signal.CTRL_BREAK_EVENT, "CTRL_BREAK_EVENT") -def skipUnlessWindows6(test): - if (hasattr(sys, 'getwindowsversion') - and sys.getwindowsversion().major >= 6): - return test - return unittest.skip("Requires Windows Vista or later")(test) - @unittest.skipUnless(sys.platform == "win32", "Win32 specific tests") @support.skip_unless_symlink class Win32SymlinkTests(unittest.TestCase): @@ -1221,6 +1275,7 @@ FSEncodingTests, PidTests, LoginTests, + LinkTests, ) if __name__ == "__main__": Modified: python/branches/py3k-cdecimal/Lib/test/test_pdb.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_pdb.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_pdb.py Sun Jan 2 13:18:37 2011 @@ -29,7 +29,7 @@ """This tests the custom displayhook for pdb. >>> def test_function(foo, bar): - ... import pdb; pdb.Pdb().set_trace() + ... import pdb; pdb.Pdb(nosigint=True).set_trace() ... pass >>> with PdbTestInput([ @@ -69,7 +69,7 @@ ... return foo.upper() >>> def test_function(): - ... import pdb; pdb.Pdb().set_trace() + ... import pdb; pdb.Pdb(nosigint=True).set_trace() ... ret = test_function_2('baz') ... print(ret) @@ -168,7 +168,7 @@ """Test basic commands related to breakpoints. >>> def test_function(): - ... import pdb; pdb.Pdb().set_trace() + ... import pdb; pdb.Pdb(nosigint=True).set_trace() ... print(1) ... print(2) ... print(3) @@ -192,6 +192,9 @@ ... 'ignore 1 10', ... 'condition 1 1 < 2', ... 'break 4', + ... 'break 4', + ... 'break', + ... 'clear 3', ... 'break', ... 'condition 1', ... 'enable 1', @@ -220,6 +223,17 @@ New condition set for breakpoint 1. (Pdb) break 4 Breakpoint 2 at :4 + (Pdb) break 4 + Breakpoint 3 at :4 + (Pdb) break + Num Type Disp Enb Where + 1 breakpoint keep no at :3 + stop only if 1 < 2 + ignore next 10 hits + 2 breakpoint keep yes at :4 + 3 breakpoint keep yes at :4 + (Pdb) clear 3 + Deleted breakpoint 3 at :4 (Pdb) break Num Type Disp Enb Where 1 breakpoint keep no at :3 @@ -244,10 +258,10 @@ Clear all breaks? y Deleted breakpoint 2 at :4 (Pdb) tbreak 5 - Breakpoint 3 at :5 + Breakpoint 4 at :5 (Pdb) continue 2 - Deleted breakpoint 3 at :5 + Deleted breakpoint 4 at :5 > (5)test_function() -> print(3) (Pdb) break @@ -283,7 +297,7 @@ ... return foo >>> def test_function(): - ... import pdb; pdb.Pdb().set_trace() + ... import pdb; pdb.Pdb(nosigint=True).set_trace() ... ret = test_function_2('baz') >>> with PdbTestInput([ # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE @@ -306,7 +320,7 @@ -> ret = test_function_2('baz') (Pdb) list 1 def test_function(): - 2 import pdb; pdb.Pdb().set_trace() + 2 import pdb; pdb.Pdb(nosigint=True).set_trace() 3 -> ret = test_function_2('baz') [EOF] (Pdb) step @@ -369,7 +383,7 @@ ... print('Exception!') >>> def test_function(): - ... import pdb; pdb.Pdb().set_trace() + ... import pdb; pdb.Pdb(nosigint=True).set_trace() ... test_function_2() ... print('Not reached.') @@ -402,7 +416,7 @@ -> 1/0 (Pdb) list 1 def test_function(): - 2 import pdb; pdb.Pdb().set_trace() + 2 import pdb; pdb.Pdb(nosigint=True).set_trace() 3 -> test_function_2() 4 print('Not reached.') [EOF] @@ -426,7 +440,7 @@ >>> def skip_module(): ... import string - ... import pdb; pdb.Pdb(skip=['stri*']).set_trace() + ... import pdb; pdb.Pdb(skip=['stri*'], nosigint=True).set_trace() ... string.capwords('FOO') >>> with PdbTestInput([ @@ -455,7 +469,7 @@ >>> def skip_module(): ... def callback(): ... return None - ... import pdb; pdb.Pdb(skip=['module_to_skip*']).set_trace() + ... import pdb; pdb.Pdb(skip=['module_to_skip*'], nosigint=True).set_trace() ... mod.foo_pony(callback) >>> with PdbTestInput([ @@ -496,7 +510,7 @@ """Test that "continue" and "next" work properly in bottom frame (issue #5294). >>> def test_function(): - ... import pdb, sys; inst = pdb.Pdb() + ... import pdb, sys; inst = pdb.Pdb(nosigint=True) ... inst.set_trace() ... inst.botframe = sys._getframe() # hackery to get the right botframe ... print(1) @@ -536,7 +550,8 @@ def pdb_invoke(method, arg): """Run pdb.method(arg).""" - import pdb; getattr(pdb, method)(arg) + import pdb + getattr(pdb.Pdb(nosigint=True), method)(arg) def test_pdb_run_with_incorrect_argument(): Modified: python/branches/py3k-cdecimal/Lib/test/test_posixpath.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_posixpath.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_posixpath.py Sun Jan 2 13:18:37 2011 @@ -180,7 +180,8 @@ @unittest.skipIf( sys.platform.startswith('win'), "posixpath.samefile does not work on links in Windows") - @support.skip_unless_symlink + @unittest.skipUnless(hasattr(os, "symlink"), + "Missing symlink implementation") def test_samefile_on_links(self): test_fn1 = support.TESTFN + "1" test_fn2 = support.TESTFN + "2" @@ -204,7 +205,8 @@ @unittest.skipIf( sys.platform.startswith('win'), "posixpath.samestat does not work on links in Windows") - @support.skip_unless_symlink + @unittest.skipUnless(hasattr(os, "symlink"), + "Missing symlink implementation") def test_samestat_on_links(self): test_fn1 = support.TESTFN + "1" test_fn2 = support.TESTFN + "2" @@ -273,7 +275,8 @@ self.assertEqual(posixpath.normpath(b"///..//./foo/.//bar"), b"/foo/bar") - @support.skip_unless_symlink + @unittest.skipUnless(hasattr(os, "symlink"), + "Missing symlink implementation") @skip_if_ABSTFN_contains_backslash def test_realpath_basic(self): # Basic operation. @@ -283,7 +286,8 @@ finally: support.unlink(ABSTFN) - @support.skip_unless_symlink + @unittest.skipUnless(hasattr(os, "symlink"), + "Missing symlink implementation") @skip_if_ABSTFN_contains_backslash def test_realpath_symlink_loops(self): # Bug #930024, return the path unchanged if we get into an infinite @@ -307,7 +311,8 @@ support.unlink(ABSTFN+"1") support.unlink(ABSTFN+"2") - @support.skip_unless_symlink + @unittest.skipUnless(hasattr(os, "symlink"), + "Missing symlink implementation") @skip_if_ABSTFN_contains_backslash def test_realpath_resolve_parents(self): # We also need to resolve any symlinks in the parents of a relative @@ -328,7 +333,8 @@ safe_rmdir(ABSTFN + "/y") safe_rmdir(ABSTFN) - @support.skip_unless_symlink + @unittest.skipUnless(hasattr(os, "symlink"), + "Missing symlink implementation") @skip_if_ABSTFN_contains_backslash def test_realpath_resolve_before_normalizing(self): # Bug #990669: Symbolic links should be resolved before we @@ -358,7 +364,8 @@ safe_rmdir(ABSTFN + "/k") safe_rmdir(ABSTFN) - @support.skip_unless_symlink + @unittest.skipUnless(hasattr(os, "symlink"), + "Missing symlink implementation") @skip_if_ABSTFN_contains_backslash def test_realpath_resolve_first(self): # Bug #1213894: The first component of the path, if not absolute, Modified: python/branches/py3k-cdecimal/Lib/test/test_pydoc.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_pydoc.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_pydoc.py Sun Jan 2 13:18:37 2011 @@ -1,17 +1,20 @@ -import sys import os -import os.path +import sys import difflib -import subprocess -import re -import pydoc import inspect -import unittest +import pydoc +import re +import string +import subprocess import test.support +import time +import unittest import xml.etree +import textwrap +from io import StringIO from contextlib import contextmanager -from test.support import ( - TESTFN, forget, rmtree, EnvironmentVarGuard, reap_children) +from test.support import TESTFN, forget, rmtree, EnvironmentVarGuard, \ + reap_children, captured_output from test import pydoc_mod @@ -219,19 +222,27 @@ output = doc.docmodule(module) - # cleanup the extra text formatting that pydoc preforms + # clean up the extra text formatting that pydoc performs patt = re.compile('\b.') output = patt.sub('', output) return output.strip(), loc def print_diffs(text1, text2): "Prints unified diffs for two texts" + # XXX now obsolete, use unittest built-in support lines1 = text1.splitlines(True) lines2 = text2.splitlines(True) diffs = difflib.unified_diff(lines1, lines2, n=0, fromfile='expected', tofile='got') print('\n' + ''.join(diffs)) +def get_html_title(text): + # Bit of hack, but good enough for test purposes + header, _, _ = text.partition("") + _, _, title = header.partition("") + title, _, _ = title.partition("") + return title + class PyDocDocTest(unittest.TestCase): @@ -327,6 +338,41 @@ self.assertEqual(stripid(""), "") + @unittest.skipIf(sys.flags.optimize >= 2, + 'Docstrings are omitted with -O2 and above') + def test_help_output_redirect(self): + # issue 940286, if output is set in Helper, then all output from + # Helper.help should be redirected + old_pattern = expected_text_pattern + getpager_old = pydoc.getpager + getpager_new = lambda: (lambda x: x) + self.maxDiff = None + + buf = StringIO() + helper = pydoc.Helper(output=buf) + unused, doc_loc = get_pydoc_text(pydoc_mod) + module = "test.pydoc_mod" + help_header = """ + Help on module test.pydoc_mod in test: + + """.lstrip() + help_header = textwrap.dedent(help_header) + expected_help_pattern = help_header + expected_text_pattern + + pydoc.getpager = getpager_new + try: + with captured_output('stdout') as output, \ + captured_output('stderr') as err: + helper.help(module) + result = buf.getvalue().strip() + expected_text = expected_help_pattern % \ + (doc_loc, inspect.getabsfile(pydoc_mod)) + self.assertEqual('', output.getvalue()) + self.assertEqual('', err.getvalue()) + self.assertEqual(expected_text, result) + finally: + pydoc.getpager = getpager_old + class TestDescriptions(unittest.TestCase): @@ -336,16 +382,8 @@ doc = pydoc.render_doc(pydocfodder) self.assertIn("pydocfodder", doc) - def test_classic_class(self): - class C: "Classic class" - c = C() - self.assertEqual(pydoc.describe(C), 'class C') - self.assertEqual(pydoc.describe(c), 'C') - expected = 'C in module %s' % __name__ - self.assertIn(expected, pydoc.render_doc(c)) - def test_class(self): - class C(object): "New-style class" + class C: "New-style class" c = C() self.assertEqual(pydoc.describe(C), 'class C') @@ -354,8 +392,78 @@ self.assertIn(expected, pydoc.render_doc(c)) +class PyDocServerTest(unittest.TestCase): + """Tests for pydoc._start_server""" + + def test_server(self): + + # Minimal test that starts the server, then stops it. + def my_url_handler(url, content_type): + text = 'the URL sent was: (%s, %s)' % (url, content_type) + return text + + serverthread = pydoc._start_server(my_url_handler, port=0) + starttime = time.time() + timeout = 1 #seconds + + while serverthread.serving: + time.sleep(.01) + if serverthread.serving and time.time() - starttime > timeout: + serverthread.stop() + break + + self.assertEqual(serverthread.error, None) + + +class PyDocUrlHandlerTest(unittest.TestCase): + """Tests for pydoc._url_handler""" + + def test_content_type_err(self): + err = 'Error: unknown content type ' + f = pydoc._url_handler + result = f("", "") + self.assertEqual(result, err + "''") + result = f("", "foobar") + self.assertEqual(result, err + "'foobar'") + + def test_url_requests(self): + # Test for the correct title in the html pages returned. + # This tests the different parts of the URL handler without + # getting too picky about the exact html. + requests = [ + ("", "Python: Index of Modules"), + ("get?key=", "Python: Index of Modules"), + ("index", "Python: Index of Modules"), + ("topics", "Python: Topics"), + ("keywords", "Python: Keywords"), + ("pydoc", "Python: module pydoc"), + ("get?key=pydoc", "Python: module pydoc"), + ("search?key=pydoc", "Python: Search Results"), + ("def", "Python: KEYWORD def"), + ("STRINGS", "Python: TOPIC STRINGS"), + ("foobar", "Python: Error"), + ("getfile?key=foobar", "Python: Read Error"), + ] + + for url, title in requests: + text = pydoc._url_handler(url, "text/html") + result = get_html_title(text) + self.assertEqual(result, title) + + path = string.__file__ + title = "Python: getfile " + path + url = "getfile?key=" + path + text = pydoc._url_handler(url, "text/html") + result = get_html_title(text) + self.assertEqual(result, title) + + def test_main(): - test.support.run_unittest(PyDocDocTest, TestDescriptions) + test.support.run_unittest(PyDocDocTest, + TestDescriptions, + PyDocServerTest, + PyDocUrlHandlerTest, + ) if __name__ == "__main__": test_main() Modified: python/branches/py3k-cdecimal/Lib/test/test_pyexpat.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_pyexpat.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_pyexpat.py Sun Jan 2 13:18:37 2011 @@ -203,6 +203,8 @@ operations = out.out self._verify_parse_output(operations) + # Issue #6697. + self.assertRaises(AttributeError, getattr, parser, '\uD800') def test_parse_file(self): # Try parsing a file Modified: python/branches/py3k-cdecimal/Lib/test/test_random.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_random.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_random.py Sun Jan 2 13:18:37 2011 @@ -246,8 +246,8 @@ '0x1.1ebb4352e4c4dp-1', '0x1.1a7422abf9c11p-1']) self.gen.seed("the quick brown fox", version=2) self.assertEqual([self.gen.random().hex() for i in range(4)], - ['0x1.1294009b9eda4p-2', '0x1.2ff96171b0010p-1', - '0x1.459e0989bd8e0p-5', '0x1.8b5f55892ddcbp-1']) + ['0x1.1239ddfb11b7cp-3', '0x1.b3cbb5c51b120p-4', + '0x1.8c4f55116b60fp-1', '0x1.63eb525174a27p-1']) def test_setstate_first_arg(self): self.assertRaises(ValueError, self.gen.setstate, (1, None, None)) Modified: python/branches/py3k-cdecimal/Lib/test/test_range.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_range.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_range.py Sun Jan 2 13:18:37 2011 @@ -136,7 +136,12 @@ self.assertNotIn(-b, seq) self.assertEqual(len(seq), 2) - self.assertRaises(OverflowError, len, range(0, sys.maxsize**10)) + self.assertRaises(OverflowError, len, + range(-sys.maxsize, sys.maxsize)) + self.assertRaises(OverflowError, len, + range(0, 2*sys.maxsize)) + self.assertRaises(OverflowError, len, + range(0, sys.maxsize**10)) def test_invalid_invocation(self): self.assertRaises(TypeError, range) @@ -248,6 +253,8 @@ always_equal = AlwaysEqual() self.assertEqual(range(10).count(always_equal), 10) + self.assertEqual(len(range(sys.maxsize, sys.maxsize+10)), 10) + def test_repr(self): self.assertEqual(repr(range(1)), 'range(0, 1)') self.assertEqual(repr(range(1, 2)), 'range(1, 2)') @@ -349,6 +356,70 @@ test_id = "reversed(range({}, {}, {}))".format(start, end, step) self.assert_iterators_equal(iter1, iter2, test_id, limit=100) + def test_slice(self): + def check(start, stop, step=None): + i = slice(start, stop, step) + self.assertEqual(list(r[i]), list(r)[i]) + self.assertEqual(len(r[i]), len(list(r)[i])) + for r in [range(10), + range(0), + range(1, 9, 3), + range(8, 0, -3), + range(sys.maxsize+1, sys.maxsize+10), + ]: + check(0, 2) + check(0, 20) + check(1, 2) + check(20, 30) + check(-30, -20) + check(-1, 100, 2) + check(0, -1) + check(-1, -3, -1) + + def test_contains(self): + r = range(10) + self.assertIn(0, r) + self.assertIn(1, r) + self.assertIn(5.0, r) + self.assertNotIn(5.1, r) + self.assertNotIn(-1, r) + self.assertNotIn(10, r) + self.assertNotIn("", r) + r = range(9, -1, -1) + self.assertIn(0, r) + self.assertIn(1, r) + self.assertIn(5.0, r) + self.assertNotIn(5.1, r) + self.assertNotIn(-1, r) + self.assertNotIn(10, r) + self.assertNotIn("", r) + r = range(0, 10, 2) + self.assertIn(0, r) + self.assertNotIn(1, r) + self.assertNotIn(5.0, r) + self.assertNotIn(5.1, r) + self.assertNotIn(-1, r) + self.assertNotIn(10, r) + self.assertNotIn("", r) + r = range(9, -1, -2) + self.assertNotIn(0, r) + self.assertIn(1, r) + self.assertIn(5.0, r) + self.assertNotIn(5.1, r) + self.assertNotIn(-1, r) + self.assertNotIn(10, r) + self.assertNotIn("", r) + + def test_reverse_iteration(self): + for r in [range(10), + range(0), + range(1, 9, 3), + range(8, 0, -3), + range(sys.maxsize+1, sys.maxsize+10), + ]: + self.assertEqual(list(reversed(r)), list(r)[::-1]) + + def test_main(): test.support.run_unittest(RangeTest) Modified: python/branches/py3k-cdecimal/Lib/test/test_runpy.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_runpy.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_runpy.py Sun Jan 2 13:18:37 2011 @@ -329,7 +329,7 @@ def _check_import_error(self, script_name, msg): msg = re.escape(msg) - self.assertRaisesRegexp(ImportError, msg, run_path, script_name) + self.assertRaisesRegex(ImportError, msg, run_path, script_name) def test_basic_script(self): with temp_dir() as script_dir: @@ -403,7 +403,7 @@ script_name = self._make_test_script(script_dir, mod_name, source) zip_name, fname = make_zip_script(script_dir, 'test_zip', script_name) msg = "recursion depth exceeded" - self.assertRaisesRegexp(RuntimeError, msg, run_path, zip_name) + self.assertRaisesRegex(RuntimeError, msg, run_path, zip_name) Modified: python/branches/py3k-cdecimal/Lib/test/test_shelve.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_shelve.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_shelve.py Sun Jan 2 13:18:37 2011 @@ -122,6 +122,19 @@ self.assertEqual(len(d1), 1) self.assertEqual(len(d2), 1) + def test_keyencoding(self): + d = {} + key = 'P????p' + # the default keyencoding is utf-8 + shelve.Shelf(d)[key] = [1] + self.assertIn(key.encode('utf-8'), d) + # but a different one can be given + shelve.Shelf(d, keyencoding='latin1')[key] = [1] + self.assertIn(key.encode('latin1'), d) + # with all consequences + s = shelve.Shelf(d, keyencoding='ascii') + self.assertRaises(UnicodeEncodeError, s.__setitem__, key, [1]) + def test_writeback_also_writes_immediately(self): # Issue 5754 d = {} Modified: python/branches/py3k-cdecimal/Lib/test/test_shutil.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_shutil.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_shutil.py Sun Jan 2 13:18:37 2011 @@ -271,24 +271,35 @@ shutil.rmtree(src_dir) shutil.rmtree(os.path.dirname(dst_dir)) - @support.skip_unless_symlink + @unittest.skipUnless(hasattr(os, 'link'), 'requires os.link') def test_dont_copy_file_onto_link_to_itself(self): + # Temporarily disable test on Windows. + if os.name == 'nt': + return # bug 851123. os.mkdir(TESTFN) src = os.path.join(TESTFN, 'cheese') dst = os.path.join(TESTFN, 'shop') try: - f = open(src, 'w') - f.write('cheddar') - f.close() - - if hasattr(os, "link"): - os.link(src, dst) - self.assertRaises(shutil.Error, shutil.copyfile, src, dst) - with open(src, 'r') as f: - self.assertEqual(f.read(), 'cheddar') - os.remove(dst) + with open(src, 'w') as f: + f.write('cheddar') + os.link(src, dst) + self.assertRaises(shutil.Error, shutil.copyfile, src, dst) + with open(src, 'r') as f: + self.assertEqual(f.read(), 'cheddar') + os.remove(dst) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + @support.skip_unless_symlink + def test_dont_copy_file_onto_symlink_to_itself(self): + # bug 851123. + os.mkdir(TESTFN) + src = os.path.join(TESTFN, 'cheese') + dst = os.path.join(TESTFN, 'shop') + try: + with open(src, 'w') as f: + f.write('cheddar') # Using `src` here would mean we end up with a symlink pointing # to TESTFN/TESTFN/cheese, while it should point at # TESTFN/cheese. @@ -298,10 +309,7 @@ self.assertEqual(f.read(), 'cheddar') os.remove(dst) finally: - try: - shutil.rmtree(TESTFN) - except OSError: - pass + shutil.rmtree(TESTFN, ignore_errors=True) @support.skip_unless_symlink def test_rmtree_on_symlink(self): @@ -328,26 +336,26 @@ finally: os.remove(TESTFN) - @unittest.skipUnless(hasattr(os, 'mkfifo'), 'requires os.mkfifo') - def test_copytree_named_pipe(self): - os.mkdir(TESTFN) - try: - subdir = os.path.join(TESTFN, "subdir") - os.mkdir(subdir) - pipe = os.path.join(subdir, "mypipe") - os.mkfifo(pipe) + @support.skip_unless_symlink + def test_copytree_named_pipe(self): + os.mkdir(TESTFN) try: - shutil.copytree(TESTFN, TESTFN2) - except shutil.Error as e: - errors = e.args[0] - self.assertEqual(len(errors), 1) - src, dst, error_msg = errors[0] - self.assertEqual("`%s` is a named pipe" % pipe, error_msg) - else: - self.fail("shutil.Error should have been raised") - finally: - shutil.rmtree(TESTFN, ignore_errors=True) - shutil.rmtree(TESTFN2, ignore_errors=True) + subdir = os.path.join(TESTFN, "subdir") + os.mkdir(subdir) + pipe = os.path.join(subdir, "mypipe") + os.mkfifo(pipe) + try: + shutil.copytree(TESTFN, TESTFN2) + except shutil.Error as e: + errors = e.args[0] + self.assertEqual(len(errors), 1) + src, dst, error_msg = errors[0] + self.assertEqual("`%s` is a named pipe" % pipe, error_msg) + else: + self.fail("shutil.Error should have been raised") + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + shutil.rmtree(TESTFN2, ignore_errors=True) def test_copytree_special_func(self): Modified: python/branches/py3k-cdecimal/Lib/test/test_site.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_site.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_site.py Sun Jan 2 13:18:37 2011 @@ -6,9 +6,11 @@ """ import unittest from test.support import run_unittest, TESTFN, EnvironmentVarGuard +from test.support import captured_stderr import builtins import os import sys +import re import encodings import subprocess import sysconfig @@ -90,6 +92,58 @@ finally: pth_file.cleanup() + def make_pth(self, contents, pth_dir='.', pth_name=TESTFN): + # Create a .pth file and return its (abspath, basename). + pth_dir = os.path.abspath(pth_dir) + pth_basename = pth_name + '.pth' + pth_fn = os.path.join(pth_dir, pth_basename) + pth_file = open(pth_fn, 'w', encoding='utf-8') + self.addCleanup(lambda: os.remove(pth_fn)) + pth_file.write(contents) + pth_file.close() + return pth_dir, pth_basename + + def test_addpackage_import_bad_syntax(self): + # Issue 10642 + pth_dir, pth_fn = self.make_pth("import bad)syntax\n") + with captured_stderr() as err_out: + site.addpackage(pth_dir, pth_fn, set()) + self.assertRegex(err_out.getvalue(), "line 1") + self.assertRegex(err_out.getvalue(), + re.escape(os.path.join(pth_dir, pth_fn))) + # XXX: the previous two should be independent checks so that the + # order doesn't matter. The next three could be a single check + # but my regex foo isn't good enough to write it. + self.assertRegex(err_out.getvalue(), 'Traceback') + self.assertRegex(err_out.getvalue(), r'import bad\)syntax') + self.assertRegex(err_out.getvalue(), 'SyntaxError') + + def test_addpackage_import_bad_exec(self): + # Issue 10642 + pth_dir, pth_fn = self.make_pth("randompath\nimport nosuchmodule\n") + with captured_stderr() as err_out: + site.addpackage(pth_dir, pth_fn, set()) + self.assertRegex(err_out.getvalue(), "line 2") + self.assertRegex(err_out.getvalue(), + re.escape(os.path.join(pth_dir, pth_fn))) + # XXX: ditto previous XXX comment. + self.assertRegex(err_out.getvalue(), 'Traceback') + self.assertRegex(err_out.getvalue(), 'ImportError') + + @unittest.skipIf(sys.platform == "win32", "Windows does not raise an " + "error for file paths containing null characters") + def test_addpackage_import_bad_pth_file(self): + # Issue 5258 + pth_dir, pth_fn = self.make_pth("abc\x00def\n") + with captured_stderr() as err_out: + site.addpackage(pth_dir, pth_fn, set()) + self.assertRegex(err_out.getvalue(), "line 1") + self.assertRegex(err_out.getvalue(), + re.escape(os.path.join(pth_dir, pth_fn))) + # XXX: ditto previous XXX comment. + self.assertRegex(err_out.getvalue(), 'Traceback') + self.assertRegex(err_out.getvalue(), 'TypeError') + def test_addsitedir(self): # Same tests for test_addpackage since addsitedir() essentially just # calls addpackage() for every .pth file in the directory Modified: python/branches/py3k-cdecimal/Lib/test/test_smtpd.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_smtpd.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_smtpd.py Sun Jan 2 13:18:37 2011 @@ -121,6 +121,24 @@ self.assertEqual(self.channel.socket.last, b'451 Internal confusion\r\n') + def test_command_too_long(self): + self.write_line(b'MAIL from ' + + b'a' * self.channel.command_size_limit + + b'@example') + self.assertEqual(self.channel.socket.last, + b'500 Error: line too long\r\n') + + def test_data_too_long(self): + # Small hack. Setting limit to 2K octets here will save us some time. + self.channel.data_size_limit = 2048 + self.write_line(b'MAIL From:eggs at example') + self.write_line(b'RCPT To:spam at example') + self.write_line(b'DATA') + self.write_line(b'A' * self.channel.data_size_limit + + b'A\r\n.') + self.assertEqual(self.channel.socket.last, + b'552 Error: Too much mail data\r\n') + def test_need_MAIL(self): self.write_line(b'RCPT to:spam at example') self.assertEqual(self.channel.socket.last, Modified: python/branches/py3k-cdecimal/Lib/test/test_smtplib.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_smtplib.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_smtplib.py Sun Jan 2 13:18:37 2011 @@ -319,12 +319,12 @@ self.assertEqual(self.output.getvalue(), mexpect) debugout = smtpd.DEBUGSTREAM.getvalue() sender = re.compile("^sender: foo at bar.com$", re.MULTILINE) - self.assertRegexpMatches(debugout, sender) + self.assertRegex(debugout, sender) for addr in ('John', 'Sally', 'Fred', 'root at localhost', 'warped at silly.walks.com'): to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), re.MULTILINE) - self.assertRegexpMatches(debugout, to_addr) + self.assertRegex(debugout, to_addr) def testSendMessageWithSomeAddresses(self): # Make sure nothing breaks if not all of the three 'to' headers exist @@ -347,11 +347,11 @@ self.assertEqual(self.output.getvalue(), mexpect) debugout = smtpd.DEBUGSTREAM.getvalue() sender = re.compile("^sender: foo at bar.com$", re.MULTILINE) - self.assertRegexpMatches(debugout, sender) + self.assertRegex(debugout, sender) for addr in ('John', 'Dinsdale'): to_addr = re.compile(r"^recips: .*'{}'.*$".format(addr), re.MULTILINE) - self.assertRegexpMatches(debugout, to_addr) + self.assertRegex(debugout, to_addr) class NonConnectingTests(unittest.TestCase): Modified: python/branches/py3k-cdecimal/Lib/test/test_socket.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_socket.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_socket.py Sun Jan 2 13:18:37 2011 @@ -667,6 +667,8 @@ type=socket.SOCK_STREAM, proto=0, flags=socket.AI_PASSIVE) self.assertEqual(a, b) + # Issue #6697. + self.assertRaises(UnicodeEncodeError, socket.getaddrinfo, 'localhost', '\uD800') def test_getnameinfo(self): # only IP addresses are allowed Modified: python/branches/py3k-cdecimal/Lib/test/test_ssl.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_ssl.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_ssl.py Sun Jan 2 13:18:37 2011 @@ -185,17 +185,17 @@ def test_errors(self): sock = socket.socket() - self.assertRaisesRegexp(ValueError, + self.assertRaisesRegex(ValueError, "certfile must be specified", ssl.wrap_socket, sock, keyfile=CERTFILE) - self.assertRaisesRegexp(ValueError, + self.assertRaisesRegex(ValueError, "certfile must be specified for server-side operations", ssl.wrap_socket, sock, server_side=True) - self.assertRaisesRegexp(ValueError, + self.assertRaisesRegex(ValueError, "certfile must be specified for server-side operations", ssl.wrap_socket, sock, server_side=True, certfile="") s = ssl.wrap_socket(sock, server_side=True, certfile=CERTFILE) - self.assertRaisesRegexp(ValueError, "can't connect in server-side mode", + self.assertRaisesRegex(ValueError, "can't connect in server-side mode", s.connect, (HOST, 8080)) with self.assertRaises(IOError) as cm: with socket.socket() as sock: @@ -310,7 +310,7 @@ ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ctx.set_ciphers("ALL") ctx.set_ciphers("DEFAULT") - with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"): + with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"): ctx.set_ciphers("^$:,;?*'dorothyx") @skip_if_broken_ubuntu_ssl @@ -358,24 +358,24 @@ with self.assertRaises(IOError) as cm: ctx.load_cert_chain(WRONGCERT) self.assertEqual(cm.exception.errno, errno.ENOENT) - with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): + with self.assertRaisesRegex(ssl.SSLError, "PEM lib"): ctx.load_cert_chain(BADCERT) - with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): + with self.assertRaisesRegex(ssl.SSLError, "PEM lib"): ctx.load_cert_chain(EMPTYCERT) # Separate key and cert ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) ctx.load_cert_chain(ONLYCERT, ONLYKEY) ctx.load_cert_chain(certfile=ONLYCERT, keyfile=ONLYKEY) ctx.load_cert_chain(certfile=BYTES_ONLYCERT, keyfile=BYTES_ONLYKEY) - with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): + with self.assertRaisesRegex(ssl.SSLError, "PEM lib"): ctx.load_cert_chain(ONLYCERT) - with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): + with self.assertRaisesRegex(ssl.SSLError, "PEM lib"): ctx.load_cert_chain(ONLYKEY) - with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): + with self.assertRaisesRegex(ssl.SSLError, "PEM lib"): ctx.load_cert_chain(certfile=ONLYKEY, keyfile=ONLYCERT) # Mismatching key and cert ctx = ssl.SSLContext(ssl.PROTOCOL_TLSv1) - with self.assertRaisesRegexp(ssl.SSLError, "key values mismatch"): + with self.assertRaisesRegex(ssl.SSLError, "key values mismatch"): ctx.load_cert_chain(SVN_PYTHON_ORG_ROOT_CERT, ONLYKEY) def test_load_verify_locations(self): @@ -389,7 +389,7 @@ with self.assertRaises(IOError) as cm: ctx.load_verify_locations(WRONGCERT) self.assertEqual(cm.exception.errno, errno.ENOENT) - with self.assertRaisesRegexp(ssl.SSLError, "PEM lib"): + with self.assertRaisesRegex(ssl.SSLError, "PEM lib"): ctx.load_verify_locations(BADCERT) ctx.load_verify_locations(CERTFILE, CAPATH) ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH) @@ -434,8 +434,8 @@ # this should fail because we have no verification certs s = ssl.wrap_socket(socket.socket(socket.AF_INET), cert_reqs=ssl.CERT_REQUIRED) - self.assertRaisesRegexp(ssl.SSLError, "certificate verify failed", - s.connect, ("svn.python.org", 443)) + self.assertRaisesRegex(ssl.SSLError, "certificate verify failed", + s.connect, ("svn.python.org", 443)) s.close() # this should succeed because we specify the root cert @@ -469,7 +469,7 @@ # This should fail because we have no verification certs ctx.verify_mode = ssl.CERT_REQUIRED s = ctx.wrap_socket(socket.socket(socket.AF_INET)) - self.assertRaisesRegexp(ssl.SSLError, "certificate verify failed", + self.assertRaisesRegex(ssl.SSLError, "certificate verify failed", s.connect, ("svn.python.org", 443)) s.close() # This should succeed because we specify the root cert @@ -587,7 +587,7 @@ cert_reqs=ssl.CERT_NONE, ciphers="DEFAULT") s.connect(remote) # Error checking can happen at instantiation or when connecting - with self.assertRaisesRegexp(ssl.SSLError, "No cipher can be selected"): + with self.assertRaisesRegex(ssl.SSLError, "No cipher can be selected"): with socket.socket(socket.AF_INET) as sock: s = ssl.wrap_socket(sock, cert_reqs=ssl.CERT_NONE, ciphers="^$:,;?*'dorothyx") @@ -1499,8 +1499,8 @@ c.settimeout(0.2) c.connect((host, port)) # Will attempt handshake and time out - self.assertRaisesRegexp(ssl.SSLError, "timed out", - ssl.wrap_socket, c) + self.assertRaisesRegex(socket.timeout, "timed out", + ssl.wrap_socket, c) finally: c.close() try: @@ -1508,8 +1508,8 @@ c = ssl.wrap_socket(c) c.settimeout(0.2) # Will attempt handshake and time out - self.assertRaisesRegexp(ssl.SSLError, "timed out", - c.connect, (host, port)) + self.assertRaisesRegex(socket.timeout, "timed out", + c.connect, (host, port)) finally: c.close() finally: Modified: python/branches/py3k-cdecimal/Lib/test/test_struct.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_struct.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_struct.py Sun Jan 2 13:18:37 2011 @@ -82,58 +82,52 @@ # Test some of the new features in detail # (format, argument, big-endian result, little-endian result, asymmetric) tests = [ - ('c', 'a', 'a', 'a', 0), - ('xc', 'a', '\0a', '\0a', 0), - ('cx', 'a', 'a\0', 'a\0', 0), - ('s', 'a', 'a', 'a', 0), - ('0s', 'helloworld', '', '', 1), - ('1s', 'helloworld', 'h', 'h', 1), - ('9s', 'helloworld', 'helloworl', 'helloworl', 1), - ('10s', 'helloworld', 'helloworld', 'helloworld', 0), - ('11s', 'helloworld', 'helloworld\0', 'helloworld\0', 1), - ('20s', 'helloworld', 'helloworld'+10*'\0', 'helloworld'+10*'\0', 1), - ('b', 7, '\7', '\7', 0), - ('b', -7, '\371', '\371', 0), - ('B', 7, '\7', '\7', 0), - ('B', 249, '\371', '\371', 0), - ('h', 700, '\002\274', '\274\002', 0), - ('h', -700, '\375D', 'D\375', 0), - ('H', 700, '\002\274', '\274\002', 0), - ('H', 0x10000-700, '\375D', 'D\375', 0), - ('i', 70000000, '\004,\035\200', '\200\035,\004', 0), - ('i', -70000000, '\373\323\342\200', '\200\342\323\373', 0), - ('I', 70000000, '\004,\035\200', '\200\035,\004', 0), - ('I', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0), - ('l', 70000000, '\004,\035\200', '\200\035,\004', 0), - ('l', -70000000, '\373\323\342\200', '\200\342\323\373', 0), - ('L', 70000000, '\004,\035\200', '\200\035,\004', 0), - ('L', 0x100000000-70000000, '\373\323\342\200', '\200\342\323\373', 0), - ('f', 2.0, '@\000\000\000', '\000\000\000@', 0), - ('d', 2.0, '@\000\000\000\000\000\000\000', - '\000\000\000\000\000\000\000@', 0), - ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0), - ('d', -2.0, '\300\000\000\000\000\000\000\000', - '\000\000\000\000\000\000\000\300', 0), - ('?', 0, '\0', '\0', 0), - ('?', 3, '\1', '\1', 1), - ('?', True, '\1', '\1', 0), - ('?', [], '\0', '\0', 1), - ('?', (1,), '\1', '\1', 1), + ('c', b'a', b'a', b'a', 0), + ('xc', b'a', b'\0a', b'\0a', 0), + ('cx', b'a', b'a\0', b'a\0', 0), + ('s', b'a', b'a', b'a', 0), + ('0s', b'helloworld', b'', b'', 1), + ('1s', b'helloworld', b'h', b'h', 1), + ('9s', b'helloworld', b'helloworl', b'helloworl', 1), + ('10s', b'helloworld', b'helloworld', b'helloworld', 0), + ('11s', b'helloworld', b'helloworld\0', b'helloworld\0', 1), + ('20s', b'helloworld', b'helloworld'+10*b'\0', b'helloworld'+10*b'\0', 1), + ('b', 7, b'\7', b'\7', 0), + ('b', -7, b'\371', b'\371', 0), + ('B', 7, b'\7', b'\7', 0), + ('B', 249, b'\371', b'\371', 0), + ('h', 700, b'\002\274', b'\274\002', 0), + ('h', -700, b'\375D', b'D\375', 0), + ('H', 700, b'\002\274', b'\274\002', 0), + ('H', 0x10000-700, b'\375D', b'D\375', 0), + ('i', 70000000, b'\004,\035\200', b'\200\035,\004', 0), + ('i', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0), + ('I', 70000000, b'\004,\035\200', b'\200\035,\004', 0), + ('I', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0), + ('l', 70000000, b'\004,\035\200', b'\200\035,\004', 0), + ('l', -70000000, b'\373\323\342\200', b'\200\342\323\373', 0), + ('L', 70000000, b'\004,\035\200', b'\200\035,\004', 0), + ('L', 0x100000000-70000000, b'\373\323\342\200', b'\200\342\323\373', 0), + ('f', 2.0, b'@\000\000\000', b'\000\000\000@', 0), + ('d', 2.0, b'@\000\000\000\000\000\000\000', + b'\000\000\000\000\000\000\000@', 0), + ('f', -2.0, b'\300\000\000\000', b'\000\000\000\300', 0), + ('d', -2.0, b'\300\000\000\000\000\000\000\000', + b'\000\000\000\000\000\000\000\300', 0), + ('?', 0, b'\0', b'\0', 0), + ('?', 3, b'\1', b'\1', 1), + ('?', True, b'\1', b'\1', 0), + ('?', [], b'\0', b'\0', 1), + ('?', (1,), b'\1', b'\1', 1), ] for fmt, arg, big, lil, asy in tests: - big = bytes(big, "latin-1") - lil = bytes(lil, "latin-1") for (xfmt, exp) in [('>'+fmt, big), ('!'+fmt, big), ('<'+fmt, lil), ('='+fmt, ISBIGENDIAN and big or lil)]: res = struct.pack(xfmt, arg) self.assertEqual(res, exp) self.assertEqual(struct.calcsize(xfmt), len(res)) rev = struct.unpack(xfmt, res)[0] - if isinstance(arg, str): - # Strings are returned as bytes since you can't know the - # encoding of the string when packed. - arg = bytes(arg, 'latin1') if rev != arg: self.assertTrue(asy) @@ -334,15 +328,14 @@ def test_p_code(self): # Test p ("Pascal string") code. for code, input, expected, expectedback in [ - ('p','abc', '\x00', b''), - ('1p', 'abc', '\x00', b''), - ('2p', 'abc', '\x01a', b'a'), - ('3p', 'abc', '\x02ab', b'ab'), - ('4p', 'abc', '\x03abc', b'abc'), - ('5p', 'abc', '\x03abc\x00', b'abc'), - ('6p', 'abc', '\x03abc\x00\x00', b'abc'), - ('1000p', 'x'*1000, '\xff' + 'x'*999, b'x'*255)]: - expected = bytes(expected, "latin-1") + ('p', b'abc', b'\x00', b''), + ('1p', b'abc', b'\x00', b''), + ('2p', b'abc', b'\x01a', b'a'), + ('3p', b'abc', b'\x02ab', b'ab'), + ('4p', b'abc', b'\x03abc', b'abc'), + ('5p', b'abc', b'\x03abc\x00', b'abc'), + ('6p', b'abc', b'\x03abc\x00\x00', b'abc'), + ('1000p', b'x'*1000, b'\xff' + b'x'*999, b'x'*255)]: got = struct.pack(code, input) self.assertEqual(got, expected) (got,) = struct.unpack(code, got) @@ -401,15 +394,11 @@ s = struct.Struct(fmt) for cls in (bytes, bytearray): data = cls(test_string) - if not isinstance(data, (bytes, bytearray)): - bytes_data = bytes(data, 'latin1') - else: - bytes_data = data self.assertEqual(s.unpack_from(data), (b'abcd',)) self.assertEqual(s.unpack_from(data, 2), (b'cd01',)) self.assertEqual(s.unpack_from(data, 4), (b'0123',)) for i in range(6): - self.assertEqual(s.unpack_from(data, i), (bytes_data[i:i+4],)) + self.assertEqual(s.unpack_from(data, i), (data[i:i+4],)) for i in range(6, len(test_string) + 1): self.assertRaises(struct.error, s.unpack_from, data, i) for cls in (bytes, bytearray): Modified: python/branches/py3k-cdecimal/Lib/test/test_subprocess.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_subprocess.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_subprocess.py Sun Jan 2 13:18:37 2011 @@ -9,6 +9,8 @@ import time import re import sysconfig +import warnings +import select try: import gc except ImportError: @@ -364,22 +366,28 @@ self.assertEqual(stdout, b"banana") self.assertStderrEqual(stderr, b"pineapple") - # This test is Linux specific for simplicity to at least have - # some coverage. It is not a platform specific bug. - @unittest.skipUnless(os.path.isdir('/proc/%d/fd' % os.getpid()), - "Linux specific") # Test for the fd leak reported in http://bugs.python.org/issue2791. def test_communicate_pipe_fd_leak(self): - fd_directory = '/proc/%d/fd' % os.getpid() - num_fds_before_popen = len(os.listdir(fd_directory)) - p = subprocess.Popen([sys.executable, "-c", "print()"], - stdout=subprocess.PIPE) - p.communicate() - num_fds_after_communicate = len(os.listdir(fd_directory)) - del p - num_fds_after_destruction = len(os.listdir(fd_directory)) - self.assertEqual(num_fds_before_popen, num_fds_after_destruction) - self.assertEqual(num_fds_before_popen, num_fds_after_communicate) + for stdin_pipe in (False, True): + for stdout_pipe in (False, True): + for stderr_pipe in (False, True): + options = {} + if stdin_pipe: + options['stdin'] = subprocess.PIPE + if stdout_pipe: + options['stdout'] = subprocess.PIPE + if stderr_pipe: + options['stderr'] = subprocess.PIPE + if not options: + continue + p = subprocess.Popen((sys.executable, "-c", "pass"), **options) + p.communicate() + if p.stdin is not None: + self.assertTrue(p.stdin.closed) + if p.stdout is not None: + self.assertTrue(p.stdout.closed) + if p.stderr is not None: + self.assertTrue(p.stderr.closed) def test_communicate_returns(self): # communicate() should return None if no redirection is active @@ -963,6 +971,125 @@ exitcode = subprocess.call([program, "-c", "pass"], env=envb) self.assertEqual(exitcode, 0) + def test_pipe_cloexec(self): + sleeper = support.findfile("input_reader.py", subdir="subprocessdata") + fd_status = support.findfile("fd_status.py", subdir="subprocessdata") + + p1 = subprocess.Popen([sys.executable, sleeper], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE, close_fds=False) + + self.addCleanup(p1.communicate, b'') + + p2 = subprocess.Popen([sys.executable, fd_status], + stdout=subprocess.PIPE, close_fds=False) + + output, error = p2.communicate() + result_fds = set(map(int, output.split(b','))) + unwanted_fds = set([p1.stdin.fileno(), p1.stdout.fileno(), + p1.stderr.fileno()]) + + self.assertFalse(result_fds & unwanted_fds, + "Expected no fds from %r to be open in child, " + "found %r" % + (unwanted_fds, result_fds & unwanted_fds)) + + def test_pipe_cloexec_real_tools(self): + qcat = support.findfile("qcat.py", subdir="subprocessdata") + qgrep = support.findfile("qgrep.py", subdir="subprocessdata") + + subdata = b'zxcvbn' + data = subdata * 4 + b'\n' + + p1 = subprocess.Popen([sys.executable, qcat], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, + close_fds=False) + + p2 = subprocess.Popen([sys.executable, qgrep, subdata], + stdin=p1.stdout, stdout=subprocess.PIPE, + close_fds=False) + + self.addCleanup(p1.wait) + self.addCleanup(p2.wait) + self.addCleanup(p1.terminate) + self.addCleanup(p2.terminate) + + p1.stdin.write(data) + p1.stdin.close() + + readfiles, ignored1, ignored2 = select.select([p2.stdout], [], [], 10) + + self.assertTrue(readfiles, "The child hung") + self.assertEqual(p2.stdout.read(), data) + + def test_close_fds(self): + fd_status = support.findfile("fd_status.py", subdir="subprocessdata") + + fds = os.pipe() + self.addCleanup(os.close, fds[0]) + self.addCleanup(os.close, fds[1]) + + open_fds = set(fds) + + p = subprocess.Popen([sys.executable, fd_status], + stdout=subprocess.PIPE, close_fds=False) + output, ignored = p.communicate() + remaining_fds = set(map(int, output.split(b','))) + + self.assertEqual(remaining_fds & open_fds, open_fds, + "Some fds were closed") + + p = subprocess.Popen([sys.executable, fd_status], + stdout=subprocess.PIPE, close_fds=True) + output, ignored = p.communicate() + remaining_fds = set(map(int, output.split(b','))) + + self.assertFalse(remaining_fds & open_fds, + "Some fds were left open") + self.assertIn(1, remaining_fds, "Subprocess failed") + + def test_pass_fds(self): + fd_status = support.findfile("fd_status.py", subdir="subprocessdata") + + open_fds = set() + + for x in range(5): + fds = os.pipe() + self.addCleanup(os.close, fds[0]) + self.addCleanup(os.close, fds[1]) + open_fds.update(fds) + + for fd in open_fds: + p = subprocess.Popen([sys.executable, fd_status], + stdout=subprocess.PIPE, close_fds=True, + pass_fds=(fd, )) + output, ignored = p.communicate() + + remaining_fds = set(map(int, output.split(b','))) + to_be_closed = open_fds - {fd} + + self.assertIn(fd, remaining_fds, "fd to be passed not passed") + self.assertFalse(remaining_fds & to_be_closed, + "fd to be closed passed") + + # pass_fds overrides close_fds with a warning. + with self.assertWarns(RuntimeWarning) as context: + self.assertFalse(subprocess.call( + [sys.executable, "-c", "import sys; sys.exit(0)"], + close_fds=False, pass_fds=(fd, ))) + self.assertIn('overriding close_fds', str(context.warning)) + + def test_wait_when_sigchild_ignored(self): + # NOTE: sigchild_ignore.py may not be an effective test on all OSes. + sigchild_ignore = support.findfile("sigchild_ignore.py", + subdir="subprocessdata") + p = subprocess.Popen([sys.executable, sigchild_ignore], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + stdout, stderr = p.communicate() + self.assertEqual(0, p.returncode, "sigchild_ignore.py exited" + " non-zero with this error:\n%s" % + stderr.decode('utf8')) + @unittest.skipUnless(mswindows, "Windows specific tests") class Win32ProcessTestCase(BaseTestCase): @@ -1183,6 +1310,47 @@ # call() function with sequence argument with spaces on Windows self.with_spaces([sys.executable, self.fname, "ab cd"]) + +class ContextManagerTests(ProcessTestCase): + + def test_pipe(self): + with subprocess.Popen([sys.executable, "-c", + "import sys;" + "sys.stdout.write('stdout');" + "sys.stderr.write('stderr');"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) as proc: + self.assertEqual(proc.stdout.read(), b"stdout") + self.assertStderrEqual(proc.stderr.read(), b"stderr") + + self.assertTrue(proc.stdout.closed) + self.assertTrue(proc.stderr.closed) + + def test_returncode(self): + with subprocess.Popen([sys.executable, "-c", + "import sys; sys.exit(100)"]) as proc: + proc.wait() + self.assertEqual(proc.returncode, 100) + + def test_communicate_stdin(self): + with subprocess.Popen([sys.executable, "-c", + "import sys;" + "sys.exit(sys.stdin.read() == 'context')"], + stdin=subprocess.PIPE) as proc: + proc.communicate(b"context") + self.assertEqual(proc.returncode, 1) + + def test_invalid_args(self): + with self.assertRaises(EnvironmentError) as c: + with subprocess.Popen(['nonexisting_i_hope'], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) as proc: + pass + + if c.exception.errno != errno.ENOENT: # ignore "no such file" + raise c.exception + + def test_main(): unit_tests = (ProcessTestCase, POSIXProcessTestCase, @@ -1191,7 +1359,8 @@ CommandTests, ProcessTestCaseNoPoll, HelperFunctionTests, - CommandsWithSpaces) + CommandsWithSpaces, + ContextManagerTests) support.run_unittest(*unit_tests) support.reap_children() Modified: python/branches/py3k-cdecimal/Lib/test/test_sys.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_sys.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_sys.py Sun Jan 2 13:18:37 2011 @@ -569,7 +569,7 @@ TPFLAGS_HEAPTYPE = 1<<9 def setUp(self): - self.c = len(struct.pack('c', ' ')) + self.c = len(struct.pack('c', b' ')) self.H = len(struct.pack('H', 0)) self.i = len(struct.pack('i', 0)) self.l = len(struct.pack('l', 0)) @@ -782,8 +782,8 @@ # reverse check(reversed(''), size(h + 'PP')) # range - check(range(1), size(h + '3P')) - check(range(66000), size(h + '3P')) + check(range(1), size(h + '4P')) + check(range(66000), size(h + '4P')) # set # frozenset PySet_MINSIZE = 8 Modified: python/branches/py3k-cdecimal/Lib/test/test_syslog.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_syslog.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_syslog.py Sun Jan 2 13:18:37 2011 @@ -11,6 +11,8 @@ def test_openlog(self): syslog.openlog('python') + # Issue #6697. + self.assertRaises(UnicodeEncodeError, syslog.openlog, '\uD800') def test_syslog(self): syslog.openlog('python') Modified: python/branches/py3k-cdecimal/Lib/test/test_telnetlib.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_telnetlib.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_telnetlib.py Sun Jan 2 13:18:37 2011 @@ -342,6 +342,16 @@ expected = "send b'xxx'\n" self.assertIn(expected, telnet._messages) + def test_debug_accepts_str_port(self): + # Issue 10695 + with test_socket([]): + telnet = TelnetAlike('dummy', '0') + telnet._messages = '' + telnet.set_debuglevel(1) + telnet.msg('test') + self.assertRegex(telnet._messages, r'0.*test') + + def test_main(verbose=None): support.run_unittest(GeneralTests, ReadTests, WriteTests, OptionTests) Modified: python/branches/py3k-cdecimal/Lib/test/test_tempfile.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_tempfile.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_tempfile.py Sun Jan 2 13:18:37 2011 @@ -925,6 +925,15 @@ f.write(b"Hello world!") return tmp + def test_mkdtemp_failure(self): + # Check no additional exception if mkdtemp fails + # Previously would raise AttributeError instead + # (noted as part of Issue #10188) + with tempfile.TemporaryDirectory() as nonexistent: + pass + with self.assertRaises(os.error): + tempfile.TemporaryDirectory(dir=nonexistent) + def test_explicit_cleanup(self): # A TemporaryDirectory is deleted when cleaned up dir = tempfile.mkdtemp() @@ -955,20 +964,56 @@ def test_del_on_shutdown(self): # A TemporaryDirectory may be cleaned up during shutdown # Make sure it works with the relevant modules nulled out - dir = tempfile.mkdtemp() - try: + with self.do_create() as dir: d = self.do_create(dir=dir) # Mimic the nulling out of modules that # occurs during system shutdown modules = [os, os.path] if has_stat: modules.append(stat) - with NulledModules(*modules): - d.cleanup() + # Currently broken, so suppress the warning + # that is otherwise emitted on stdout + with support.captured_stderr() as err: + with NulledModules(*modules): + d.cleanup() + # Currently broken, so stop spurious exception by + # indicating the object has already been closed + d._closed = True + # And this assert will fail, as expected by the + # unittest decorator... self.assertFalse(os.path.exists(d.name), "TemporaryDirectory %s exists after cleanup" % d.name) - finally: - os.rmdir(dir) + + def test_warnings_on_cleanup(self): + # Two kinds of warning on shutdown + # Issue 10888: may write to stderr if modules are nulled out + # ResourceWarning will be triggered by __del__ + with self.do_create() as dir: + if os.sep != '\\': + # Embed a backslash in order to make sure string escaping + # in the displayed error message is dealt with correctly + suffix = '\\check_backslash_handling' + else: + suffix = '' + d = self.do_create(dir=dir, suf=suffix) + + #Check for the Issue 10888 message + modules = [os, os.path] + if has_stat: + modules.append(stat) + with support.captured_stderr() as err: + with NulledModules(*modules): + d.cleanup() + message = err.getvalue().replace('\\\\', '\\') + self.assertIn("while cleaning up", message) + self.assertIn(d.name, message) + + # Check for the resource warning + with support.check_warnings(('Implicitly', ResourceWarning), quiet=False): + warnings.filterwarnings("always", category=ResourceWarning) + d.__del__() + self.assertFalse(os.path.exists(d.name), + "TemporaryDirectory %s exists after __del__" % d.name) def test_multiple_close(self): # Can be cleaned-up many times without error Modified: python/branches/py3k-cdecimal/Lib/test/test_threadsignals.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_threadsignals.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_threadsignals.py Sun Jan 2 13:18:37 2011 @@ -6,6 +6,7 @@ import sys from test.support import run_unittest, import_module thread = import_module('_thread') +import time if sys.platform[:3] in ('win', 'os2') or sys.platform=='riscos': raise unittest.SkipTest("Can't test signal on %s" % sys.platform) @@ -34,12 +35,12 @@ signalled_all.release() class ThreadSignals(unittest.TestCase): - """Test signal handling semantics of threads. - We spawn a thread, have the thread send two signals, and - wait for it to finish. Check that we got both signals - and that they were run by the main thread. - """ + def test_signals(self): + # Test signal handling semantics of threads. + # We spawn a thread, have the thread send two signals, and + # wait for it to finish. Check that we got both signals + # and that they were run by the main thread. signalled_all.acquire() self.spawnSignallingThread() signalled_all.acquire() @@ -66,6 +67,120 @@ def spawnSignallingThread(self): thread.start_new_thread(send_signals, ()) + def alarm_interrupt(self, sig, frame): + raise KeyboardInterrupt + + def test_lock_acquire_interruption(self): + # Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck + # in a deadlock. + oldalrm = signal.signal(signal.SIGALRM, self.alarm_interrupt) + try: + lock = thread.allocate_lock() + lock.acquire() + signal.alarm(1) + self.assertRaises(KeyboardInterrupt, lock.acquire) + finally: + signal.signal(signal.SIGALRM, oldalrm) + + def test_rlock_acquire_interruption(self): + # Mimic receiving a SIGINT (KeyboardInterrupt) with SIGALRM while stuck + # in a deadlock. + oldalrm = signal.signal(signal.SIGALRM, self.alarm_interrupt) + try: + rlock = thread.RLock() + # For reentrant locks, the initial acquisition must be in another + # thread. + def other_thread(): + rlock.acquire() + thread.start_new_thread(other_thread, ()) + # Wait until we can't acquire it without blocking... + while rlock.acquire(blocking=False): + rlock.release() + time.sleep(0.01) + signal.alarm(1) + self.assertRaises(KeyboardInterrupt, rlock.acquire) + finally: + signal.signal(signal.SIGALRM, oldalrm) + + def acquire_retries_on_intr(self, lock): + self.sig_recvd = False + def my_handler(signal, frame): + self.sig_recvd = True + old_handler = signal.signal(signal.SIGUSR1, my_handler) + try: + def other_thread(): + # Acquire the lock in a non-main thread, so this test works for + # RLocks. + lock.acquire() + # Wait until the main thread is blocked in the lock acquire, and + # then wake it up with this. + time.sleep(0.5) + os.kill(process_pid, signal.SIGUSR1) + # Let the main thread take the interrupt, handle it, and retry + # the lock acquisition. Then we'll let it run. + time.sleep(0.5) + lock.release() + thread.start_new_thread(other_thread, ()) + # Wait until we can't acquire it without blocking... + while lock.acquire(blocking=False): + lock.release() + time.sleep(0.01) + result = lock.acquire() # Block while we receive a signal. + self.assertTrue(self.sig_recvd) + self.assertTrue(result) + finally: + signal.signal(signal.SIGUSR1, old_handler) + + def test_lock_acquire_retries_on_intr(self): + self.acquire_retries_on_intr(thread.allocate_lock()) + + def test_rlock_acquire_retries_on_intr(self): + self.acquire_retries_on_intr(thread.RLock()) + + def test_interrupted_timed_acquire(self): + # Test to make sure we recompute lock acquisition timeouts when we + # receive a signal. Check this by repeatedly interrupting a lock + # acquire in the main thread, and make sure that the lock acquire times + # out after the right amount of time. + # NOTE: this test only behaves as expected if C signals get delivered + # to the main thread. Otherwise lock.acquire() itself doesn't get + # interrupted and the test trivially succeeds. + self.start = None + self.end = None + self.sigs_recvd = 0 + done = thread.allocate_lock() + done.acquire() + lock = thread.allocate_lock() + lock.acquire() + def my_handler(signum, frame): + self.sigs_recvd += 1 + old_handler = signal.signal(signal.SIGUSR1, my_handler) + try: + def timed_acquire(): + self.start = time.time() + lock.acquire(timeout=0.5) + self.end = time.time() + def send_signals(): + for _ in range(40): + time.sleep(0.02) + os.kill(process_pid, signal.SIGUSR1) + done.release() + + # Send the signals from the non-main thread, since the main thread + # is the only one that can process signals. + thread.start_new_thread(send_signals, ()) + timed_acquire() + # Wait for thread to finish + done.acquire() + # This allows for some timing and scheduling imprecision + self.assertLess(self.end - self.start, 2.0) + self.assertGreater(self.end - self.start, 0.3) + # If the signal is received several times before PyErr_CheckSignals() + # is called, the handler will get called less than 40 times. + self.assertGreater(self.sigs_recvd, 20) + finally: + signal.signal(signal.SIGUSR1, old_handler) + def test_main(): global signal_blackboard Modified: python/branches/py3k-cdecimal/Lib/test/test_time.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_time.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_time.py Sun Jan 2 13:18:37 2011 @@ -126,9 +126,9 @@ def test_asctime_bounding_check(self): self._bounds_checking(time.asctime) + @unittest.skipIf(not hasattr(time, "tzset"), + "time module has no attribute tzset") def test_tzset(self): - if not hasattr(time, "tzset"): - return # Can't test this; don't want the test suite to fail from os import environ Modified: python/branches/py3k-cdecimal/Lib/test/test_trace.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_trace.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_trace.py Sun Jan 2 13:18:37 2011 @@ -330,7 +330,7 @@ lines, cov, module = line.split()[:3] coverage[module] = (int(lines), int(cov[:-1])) # XXX This is needed to run regrtest.py as a script - modname = trace.fullmodname(sys.modules[modname].__file__) + modname = trace._fullmodname(sys.modules[modname].__file__) self.assertIn(modname, coverage) self.assertEqual(coverage[modname], (5, 100)) @@ -340,7 +340,7 @@ class Test_Ignore(unittest.TestCase): def test_ignored(self): jn = os.path.join - ignore = trace.Ignore(['x', 'y.z'], [jn('foo', 'bar')]) + ignore = trace._Ignore(['x', 'y.z'], [jn('foo', 'bar')]) self.assertTrue(ignore.names('x.py', 'x')) self.assertFalse(ignore.names('xy.py', 'xy')) self.assertFalse(ignore.names('y.py', 'y')) Modified: python/branches/py3k-cdecimal/Lib/test/test_tuple.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_tuple.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_tuple.py Sun Jan 2 13:18:37 2011 @@ -6,7 +6,7 @@ type2test = tuple def test_constructors(self): - super().test_len() + super().test_constructors() # calling built-in types without argument must return empty self.assertEqual(tuple(), ()) t0_3 = (0, 1, 2, 3) Modified: python/branches/py3k-cdecimal/Lib/test/test_types.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_types.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_types.py Sun Jan 2 13:18:37 2011 @@ -396,13 +396,9 @@ self.assertEqual(len(format(0, cfmt)), len(format(x, cfmt))) def test_float__format__(self): - # these should be rewritten to use both format(x, spec) and - # x.__format__(spec) - def test(f, format_spec, result): - assert type(f) == float - assert type(format_spec) == str self.assertEqual(f.__format__(format_spec), result) + self.assertEqual(format(f, format_spec), result) test(0.0, 'f', '0.000000') @@ -516,9 +512,27 @@ self.assertRaises(ValueError, format, 1e-100, format_spec) self.assertRaises(ValueError, format, -1e-100, format_spec) - # Alternate formatting is not supported - self.assertRaises(ValueError, format, 0.0, '#') - self.assertRaises(ValueError, format, 0.0, '#20f') + # Alternate float formatting + test(1.0, '.0e', '1e+00') + test(1.0, '#.0e', '1.e+00') + test(1.0, '.0f', '1') + test(1.0, '#.0f', '1.') + test(1.1, 'g', '1.1') + test(1.1, '#g', '1.10000') + test(1.0, '.0%', '100%') + test(1.0, '#.0%', '100.%') + + # Issue 7094: Alternate formatting (specified by #) + test(1.0, '0e', '1.000000e+00') + test(1.0, '#0e', '1.000000e+00') + test(1.0, '0f', '1.000000' ) + test(1.0, '#0f', '1.000000') + test(1.0, '.1e', '1.0e+00') + test(1.0, '#.1e', '1.0e+00') + test(1.0, '.1f', '1.0') + test(1.0, '#.1f', '1.0') + test(1.0, '.1%', '100.0%') + test(1.0, '#.1%', '100.0%') # Issue 6902 test(12345.6, "0<20", '12345.60000000000000') Modified: python/branches/py3k-cdecimal/Lib/test/test_unicode.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_unicode.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_unicode.py Sun Jan 2 13:18:37 2011 @@ -1168,8 +1168,13 @@ # Error handling (wrong arguments) self.assertRaises(TypeError, "hello".encode, 42, 42, 42) - # Error handling (PyUnicode_EncodeDecimal()) - self.assertRaises(UnicodeError, int, "\u0200") + # Error handling (lone surrogate in PyUnicode_TransformDecimalToASCII()) + self.assertRaises(UnicodeError, int, "\ud800") + self.assertRaises(UnicodeError, int, "\udf00") + self.assertRaises(UnicodeError, float, "\ud800") + self.assertRaises(UnicodeError, float, "\udf00") + self.assertRaises(UnicodeError, complex, "\ud800") + self.assertRaises(UnicodeError, complex, "\udf00") def test_codecs(self): # Encoding @@ -1427,7 +1432,7 @@ # non-ascii format, ascii argument: ensure that PyUnicode_FromFormat() # raises an error for a non-ascii format string. - self.assertRaisesRegexp(ValueError, + self.assertRaisesRegex(ValueError, '^PyUnicode_FromFormatV\(\) expects an ASCII-encoded format ' 'string, got a non-ASCII byte: 0xe9$', format_unicode, b'unicode\xe9=%s', 'ascii') @@ -1439,6 +1444,7 @@ # Test PyUnicode_AsWideChar() def test_aswidechar(self): from _testcapi import unicode_aswidechar + support.import_module('ctypes') from ctypes import c_wchar, sizeof wchar, size = unicode_aswidechar('abcdef', 2) @@ -1475,6 +1481,7 @@ # Test PyUnicode_AsWideCharString() def test_aswidecharstring(self): from _testcapi import unicode_aswidecharstring + support.import_module('ctypes') from ctypes import c_wchar, sizeof wchar, size = unicode_aswidecharstring('abc') Modified: python/branches/py3k-cdecimal/Lib/test/test_unicodedata.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_unicodedata.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_unicodedata.py Sun Jan 2 13:18:37 2011 @@ -188,9 +188,22 @@ def test_pr29(self): # http://www.unicode.org/review/pr-29.html - for text in ("\u0b47\u0300\u0b3e", "\u1100\u0300\u1161"): + # See issues #1054943 and #10254. + composed = ("\u0b47\u0300\u0b3e", "\u1100\u0300\u1161", + 'Li\u030dt-s\u1e73\u0301', + '\u092e\u093e\u0930\u094d\u0915 \u091c\u093c' + + '\u0941\u0915\u0947\u0930\u092c\u0930\u094d\u0917', + '\u0915\u093f\u0930\u094d\u0917\u093f\u091c\u093c' + + '\u0938\u094d\u0924\u093e\u0928') + for text in composed: self.assertEqual(self.db.normalize('NFC', text), text) + def test_issue10254(self): + # Crash reported in #10254 + a = 'C\u0338' * 20 + 'C\u0327' + b = 'C\u0338' * 20 + '\xC7' + self.assertEqual(self.db.normalize('NFC', a), b) + def test_east_asian_width(self): eaw = self.db.east_asian_width self.assertRaises(TypeError, eaw, b'a') Modified: python/branches/py3k-cdecimal/Lib/test/test_unittest.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_unittest.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_unittest.py Sun Jan 2 13:18:37 2011 @@ -4,8 +4,13 @@ def test_main(): + # used by regrtest support.run_unittest(unittest.test.suite()) support.reap_children() +def load_tests(*_): + # used by unittest + return unittest.test.suite() + if __name__ == "__main__": test_main() Modified: python/branches/py3k-cdecimal/Lib/test/test_urllib.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_urllib.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_urllib.py Sun Jan 2 13:18:37 2011 @@ -139,8 +139,10 @@ def fakehttp(self, fakedata): class FakeSocket(io.BytesIO): + io_refs = 1 def sendall(self, str): pass def makefile(self, *args, **kwds): + self.io_refs += 1 return self def read(self, amt=None): if self.closed: return b"" @@ -148,6 +150,10 @@ def readline(self, length=None): if self.closed: return b"" return io.BytesIO.readline(self, length) + def close(self): + self.io_refs -= 1 + if self.io_refs == 0: + io.BytesIO.close(self) class FakeHTTPConnection(http.client.HTTPConnection): def connect(self): self.sock = FakeSocket(fakedata) @@ -157,8 +163,8 @@ def unfakehttp(self): http.client.HTTPConnection = self._connection_class - def test_read(self): - self.fakehttp(b"Hello!") + def check_read(self, ver): + self.fakehttp(b"HTTP/" + ver + b" 200 OK\r\n\r\nHello!") try: fp = urlopen("http://python.org/") self.assertEqual(fp.readline(), b"Hello!") @@ -168,6 +174,17 @@ finally: self.unfakehttp() + def test_read_0_9(self): + # "0.9" response accepted (but not "simple responses" without + # a status line) + self.check_read(b"0.9") + + def test_read_1_0(self): + self.check_read(b"1.0") + + def test_read_1_1(self): + self.check_read(b"1.1") + def test_read_bogus(self): # urlopen() should raise IOError for many error codes. self.fakehttp(b'''HTTP/1.1 401 Authentication Required @@ -191,7 +208,7 @@ self.unfakehttp() def test_userpass_inurl(self): - self.fakehttp(b"Hello!") + self.fakehttp(b"HTTP/1.0 200 OK\r\n\r\nHello!") try: fp = urlopen("http://user:pass at python.org/") self.assertEqual(fp.readline(), b"Hello!") Modified: python/branches/py3k-cdecimal/Lib/test/test_urllib2.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_urllib2.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_urllib2.py Sun Jan 2 13:18:37 2011 @@ -4,6 +4,7 @@ import os import io import socket +import array import urllib.request from urllib.request import Request, OpenerDirector @@ -765,7 +766,7 @@ o = h.parent = MockOpener() url = "http://example.com/" - for method, data in [("GET", None), ("POST", "blah")]: + for method, data in [("GET", None), ("POST", b"blah")]: req = Request(url, data, {"Foo": "bar"}) req.timeout = None req.add_unredirected_header("Spam", "eggs") @@ -795,7 +796,7 @@ # check adding of standard headers o.addheaders = [("Spam", "eggs")] - for data in "", None: # POST, GET + for data in b"", None: # POST, GET req = Request("http://example.com/", data) r = MockResponse(200, "OK", {}, "") newreq = h.do_request_(req) @@ -821,6 +822,48 @@ self.assertEqual(req.unredirected_hdrs["Host"], "baz") self.assertEqual(req.unredirected_hdrs["Spam"], "foo") + # Check iterable body support + def iterable_body(): + yield b"one" + yield b"two" + yield b"three" + + for headers in {}, {"Content-Length": 11}: + req = Request("http://example.com/", iterable_body(), headers) + if not headers: + # Having an iterable body without a Content-Length should + # raise an exception + self.assertRaises(ValueError, h.do_request_, req) + else: + newreq = h.do_request_(req) + + # A file object + + file_obj = io.StringIO() + file_obj.write("Something\nSomething\nSomething\n") + + for headers in {}, {"Content-Length": 30}: + req = Request("http://example.com/", file_obj, headers) + if not headers: + # Having an iterable body without a Content-Length should + # raise an exception + self.assertRaises(ValueError, h.do_request_, req) + else: + newreq = h.do_request_(req) + self.assertEqual(int(newreq.get_header('Content-length')),30) + + file_obj.close() + + # array.array Iterable - Content Length is calculated + + iterable_array = array.array("I",[1,2,3,4]) + + for headers in {}, {"Content-Length": 16}: + req = Request("http://example.com/", iterable_array, headers) + newreq = h.do_request_(req) + self.assertEqual(int(newreq.get_header('Content-length')),16) + + def test_http_doubleslash(self): # Checks the presence of any unnecessary double slash in url does not # break anything. Previously, a double slash directly after the host @@ -828,7 +871,7 @@ h = urllib.request.AbstractHTTPHandler() o = h.parent = MockOpener() - data = "" + data = b"" ds_urls = [ "http://example.com/foo/bar/baz.html", "http://example.com//foo/bar/baz.html", Modified: python/branches/py3k-cdecimal/Lib/test/test_urllibnet.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_urllibnet.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_urllibnet.py Sun Jan 2 13:18:37 2011 @@ -13,7 +13,7 @@ class URLTimeoutTest(unittest.TestCase): - TIMEOUT = 10.0 + TIMEOUT = 30.0 def setUp(self): socket.setdefaulttimeout(self.TIMEOUT) Modified: python/branches/py3k-cdecimal/Lib/test/test_urlparse.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_urlparse.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_urlparse.py Sun Jan 2 13:18:37 2011 @@ -24,6 +24,17 @@ ("&a=b", [('a', 'b')]), ("a=a+b&b=b+c", [('a', 'a b'), ('b', 'b c')]), ("a=1&a=2", [('a', '1'), ('a', '2')]), + (b"", []), + (b"&", []), + (b"&&", []), + (b"=", [(b'', b'')]), + (b"=a", [(b'', b'a')]), + (b"a", [(b'a', b'')]), + (b"a=", [(b'a', b'')]), + (b"a=", [(b'a', b'')]), + (b"&a=b", [(b'a', b'b')]), + (b"a=a+b&b=b+c", [(b'a', b'a b'), (b'b', b'b c')]), + (b"a=1&a=2", [(b'a', b'1'), (b'a', b'2')]), ] class UrlParseTestCase(unittest.TestCase): @@ -86,7 +97,7 @@ def test_roundtrips(self): - testcases = [ + str_cases = [ ('file:///tmp/junk.txt', ('file', '', '/tmp/junk.txt', '', '', ''), ('file', '', '/tmp/junk.txt', '', '')), @@ -110,16 +121,21 @@ ('git+ssh', 'git at github.com','/user/project.git', '','',''), ('git+ssh', 'git at github.com','/user/project.git', - '', '')) + '', '')), ] - for url, parsed, split in testcases: + def _encode(t): + return (t[0].encode('ascii'), + tuple(x.encode('ascii') for x in t[1]), + tuple(x.encode('ascii') for x in t[2])) + bytes_cases = [_encode(x) for x in str_cases] + for url, parsed, split in str_cases + bytes_cases: self.checkRoundtrips(url, parsed, split) def test_http_roundtrips(self): # urllib.parse.urlsplit treats 'http:' as an optimized special case, # so we test both 'http:' and 'https:' in all the following. # Three cheers for white box knowledge! - testcases = [ + str_cases = [ ('://www.python.org', ('www.python.org', '', '', '', ''), ('www.python.org', '', '', '')), @@ -136,19 +152,34 @@ ('a', '/b/c/d', 'p', 'q', 'f'), ('a', '/b/c/d;p', 'q', 'f')), ] - for scheme in ('http', 'https'): - for url, parsed, split in testcases: - url = scheme + url - parsed = (scheme,) + parsed - split = (scheme,) + split - self.checkRoundtrips(url, parsed, split) + def _encode(t): + return (t[0].encode('ascii'), + tuple(x.encode('ascii') for x in t[1]), + tuple(x.encode('ascii') for x in t[2])) + bytes_cases = [_encode(x) for x in str_cases] + str_schemes = ('http', 'https') + bytes_schemes = (b'http', b'https') + str_tests = str_schemes, str_cases + bytes_tests = bytes_schemes, bytes_cases + for schemes, test_cases in (str_tests, bytes_tests): + for scheme in schemes: + for url, parsed, split in test_cases: + url = scheme + url + parsed = (scheme,) + parsed + split = (scheme,) + split + self.checkRoundtrips(url, parsed, split) def checkJoin(self, base, relurl, expected): - self.assertEqual(urllib.parse.urljoin(base, relurl), expected, - (base, relurl, expected)) + str_components = (base, relurl, expected) + self.assertEqual(urllib.parse.urljoin(base, relurl), expected) + bytes_components = baseb, relurlb, expectedb = [ + x.encode('ascii') for x in str_components] + self.assertEqual(urllib.parse.urljoin(baseb, relurlb), expectedb) def test_unparse_parse(self): - for u in ['Python', './Python','x-newscheme://foo.com/stuff','x://y','x:/y','x:/','/',]: + str_cases = ['Python', './Python','x-newscheme://foo.com/stuff','x://y','x:/y','x:/','/',] + bytes_cases = [x.encode('ascii') for x in str_cases] + for u in str_cases + bytes_cases: self.assertEqual(urllib.parse.urlunsplit(urllib.parse.urlsplit(u)), u) self.assertEqual(urllib.parse.urlunparse(urllib.parse.urlparse(u)), u) @@ -296,6 +327,9 @@ #self.checkJoin(RFC3986_BASE, 'http:g','http:g') # strict parser self.checkJoin(RFC3986_BASE, 'http:g','http://a/b/c/g') #relaxed parser + # Test for issue9721 + self.checkJoin('http://a/b/c/de', ';x','http://a/b/c/;x') + def test_urljoins(self): self.checkJoin(SIMPLE_BASE, 'g:h','g:h') self.checkJoin(SIMPLE_BASE, 'http:g','http://a/b/c/g') @@ -328,7 +362,7 @@ self.checkJoin(SIMPLE_BASE, 'http:g?y/./x','http://a/b/c/g?y/./x') def test_RFC2732(self): - for url, hostname, port in [ + str_cases = [ ('http://Test.python.org:5432/foo/', 'test.python.org', 5432), ('http://12.34.56.78:5432/foo/', '12.34.56.78', 5432), ('http://[::1]:5432/foo/', '::1', 5432), @@ -349,20 +383,26 @@ ('http://[::12.34.56.78]/foo/', '::12.34.56.78', None), ('http://[::ffff:12.34.56.78]/foo/', '::ffff:12.34.56.78', None), - ]: + ] + def _encode(t): + return t[0].encode('ascii'), t[1].encode('ascii'), t[2] + bytes_cases = [_encode(x) for x in str_cases] + for url, hostname, port in str_cases + bytes_cases: urlparsed = urllib.parse.urlparse(url) self.assertEqual((urlparsed.hostname, urlparsed.port) , (hostname, port)) - for invalid_url in [ + str_cases = [ 'http://::12.34.56.78]/', 'http://[::1/foo/', 'ftp://[::1/foo/bad]/bad', 'http://[::1/foo/bad]/bad', - 'http://[::ffff:12.34.56.78']: + 'http://[::ffff:12.34.56.78'] + bytes_cases = [x.encode('ascii') for x in str_cases] + for invalid_url in str_cases + bytes_cases: self.assertRaises(ValueError, urllib.parse.urlparse, invalid_url) def test_urldefrag(self): - for url, defrag, frag in [ + str_cases = [ ('http://python.org#frag', 'http://python.org', 'frag'), ('http://python.org', 'http://python.org', ''), ('http://python.org/#frag', 'http://python.org/', 'frag'), @@ -373,8 +413,16 @@ ('http://python.org/p?q', 'http://python.org/p?q', ''), (RFC1808_BASE, 'http://a/b/c/d;p?q', 'f'), (RFC2396_BASE, 'http://a/b/c/d;p?q', ''), - ]: - self.assertEqual(urllib.parse.urldefrag(url), (defrag, frag)) + ] + def _encode(t): + return type(t)(x.encode('ascii') for x in t) + bytes_cases = [_encode(x) for x in str_cases] + for url, defrag, frag in str_cases + bytes_cases: + result = urllib.parse.urldefrag(url) + self.assertEqual(result.geturl(), url) + self.assertEqual(result, (defrag, frag)) + self.assertEqual(result.url, defrag) + self.assertEqual(result.fragment, frag) def test_urlsplit_attributes(self): url = "HTTP://WWW.PYTHON.ORG/doc/#frag" @@ -390,7 +438,8 @@ self.assertEqual(p.port, None) # geturl() won't return exactly the original URL in this case # since the scheme is always case-normalized - #self.assertEqual(p.geturl(), url) + # We handle this by ignoring the first 4 characters of the URL + self.assertEqual(p.geturl()[4:], url[4:]) url = "http://User:Pass at www.python.org:080/doc/?query=yes#frag" p = urllib.parse.urlsplit(url) @@ -422,6 +471,45 @@ self.assertEqual(p.port, 80) self.assertEqual(p.geturl(), url) + # And check them all again, only with bytes this time + url = b"HTTP://WWW.PYTHON.ORG/doc/#frag" + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, b"http") + self.assertEqual(p.netloc, b"WWW.PYTHON.ORG") + self.assertEqual(p.path, b"/doc/") + self.assertEqual(p.query, b"") + self.assertEqual(p.fragment, b"frag") + self.assertEqual(p.username, None) + self.assertEqual(p.password, None) + self.assertEqual(p.hostname, b"www.python.org") + self.assertEqual(p.port, None) + self.assertEqual(p.geturl()[4:], url[4:]) + + url = b"http://User:Pass at www.python.org:080/doc/?query=yes#frag" + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, b"http") + self.assertEqual(p.netloc, b"User:Pass at www.python.org:080") + self.assertEqual(p.path, b"/doc/") + self.assertEqual(p.query, b"query=yes") + self.assertEqual(p.fragment, b"frag") + self.assertEqual(p.username, b"User") + self.assertEqual(p.password, b"Pass") + self.assertEqual(p.hostname, b"www.python.org") + self.assertEqual(p.port, 80) + self.assertEqual(p.geturl(), url) + + url = b"http://User at example.com:Pass at www.python.org:080/doc/?query=yes#frag" + p = urllib.parse.urlsplit(url) + self.assertEqual(p.scheme, b"http") + self.assertEqual(p.netloc, b"User at example.com:Pass at www.python.org:080") + self.assertEqual(p.path, b"/doc/") + self.assertEqual(p.query, b"query=yes") + self.assertEqual(p.fragment, b"frag") + self.assertEqual(p.username, b"User at example.com") + self.assertEqual(p.password, b"Pass") + self.assertEqual(p.hostname, b"www.python.org") + self.assertEqual(p.port, 80) + self.assertEqual(p.geturl(), url) def test_attributes_bad_port(self): """Check handling of non-integer ports.""" @@ -433,6 +521,15 @@ self.assertEqual(p.netloc, "www.example.net:foo") self.assertRaises(ValueError, lambda: p.port) + # Once again, repeat ourselves to test bytes + p = urllib.parse.urlsplit(b"http://www.example.net:foo") + self.assertEqual(p.netloc, b"www.example.net:foo") + self.assertRaises(ValueError, lambda: p.port) + + p = urllib.parse.urlparse(b"http://www.example.net:foo") + self.assertEqual(p.netloc, b"www.example.net:foo") + self.assertRaises(ValueError, lambda: p.port) + def test_attributes_without_netloc(self): # This example is straight from RFC 3261. It looks like it # should allow the username, hostname, and port to be filled @@ -456,10 +553,30 @@ self.assertEqual(p.port, None) self.assertEqual(p.geturl(), uri) + # You guessed it, repeating the test with bytes input + uri = b"sip:alice at atlanta.com;maddr=239.255.255.1;ttl=15" + p = urllib.parse.urlsplit(uri) + self.assertEqual(p.netloc, b"") + self.assertEqual(p.username, None) + self.assertEqual(p.password, None) + self.assertEqual(p.hostname, None) + self.assertEqual(p.port, None) + self.assertEqual(p.geturl(), uri) + + p = urllib.parse.urlparse(uri) + self.assertEqual(p.netloc, b"") + self.assertEqual(p.username, None) + self.assertEqual(p.password, None) + self.assertEqual(p.hostname, None) + self.assertEqual(p.port, None) + self.assertEqual(p.geturl(), uri) + def test_noslash(self): # Issue 1637: http://foo.com?query is legal self.assertEqual(urllib.parse.urlparse("http://example.com?blahblah=/foo"), ('http', 'example.com', '', '', 'blahblah=/foo', '')) + self.assertEqual(urllib.parse.urlparse(b"http://example.com?blahblah=/foo"), + (b'http', b'example.com', b'', b'', b'blahblah=/foo', b'')) def test_withoutscheme(self): # Test urlparse without scheme @@ -472,6 +589,13 @@ ('','www.python.org:80','','','','')) self.assertEqual(urllib.parse.urlparse("http://www.python.org:80"), ('http','www.python.org:80','','','','')) + # Repeat for bytes input + self.assertEqual(urllib.parse.urlparse(b"path"), + (b'',b'',b'path',b'',b'',b'')) + self.assertEqual(urllib.parse.urlparse(b"//www.python.org:80"), + (b'',b'www.python.org:80',b'',b'',b'',b'')) + self.assertEqual(urllib.parse.urlparse(b"http://www.python.org:80"), + (b'http',b'www.python.org:80',b'',b'',b'',b'')) def test_portseparator(self): # Issue 754016 makes changes for port separator ':' from scheme separator @@ -481,6 +605,13 @@ self.assertEqual(urllib.parse.urlparse("https:"),('https','','','','','')) self.assertEqual(urllib.parse.urlparse("http://www.python.org:80"), ('http','www.python.org:80','','','','')) + # As usual, need to check bytes input as well + self.assertEqual(urllib.parse.urlparse(b"path:80"), + (b'',b'',b'path:80',b'',b'',b'')) + self.assertEqual(urllib.parse.urlparse(b"http:"),(b'http',b'',b'',b'',b'',b'')) + self.assertEqual(urllib.parse.urlparse(b"https:"),(b'https',b'',b'',b'',b'',b'')) + self.assertEqual(urllib.parse.urlparse(b"http://www.python.org:80"), + (b'http',b'www.python.org:80',b'',b'',b'',b'')) def test_usingsys(self): # Issue 3314: sys module is used in the error @@ -492,6 +623,71 @@ ('s3', 'foo.com', '/stuff', '', '', '')) self.assertEqual(urllib.parse.urlparse("x-newscheme://foo.com/stuff"), ('x-newscheme', 'foo.com', '/stuff', '', '', '')) + # And for bytes... + self.assertEqual(urllib.parse.urlparse(b"s3://foo.com/stuff"), + (b's3', b'foo.com', b'/stuff', b'', b'', b'')) + self.assertEqual(urllib.parse.urlparse(b"x-newscheme://foo.com/stuff"), + (b'x-newscheme', b'foo.com', b'/stuff', b'', b'', b'')) + + def test_mixed_types_rejected(self): + # Several functions that process either strings or ASCII encoded bytes + # accept multiple arguments. Check they reject mixed type input + with self.assertRaisesRegex(TypeError, "Cannot mix str"): + urllib.parse.urlparse("www.python.org", b"http") + with self.assertRaisesRegex(TypeError, "Cannot mix str"): + urllib.parse.urlparse(b"www.python.org", "http") + with self.assertRaisesRegex(TypeError, "Cannot mix str"): + urllib.parse.urlsplit("www.python.org", b"http") + with self.assertRaisesRegex(TypeError, "Cannot mix str"): + urllib.parse.urlsplit(b"www.python.org", "http") + with self.assertRaisesRegex(TypeError, "Cannot mix str"): + urllib.parse.urlunparse(( b"http", "www.python.org","","","","")) + with self.assertRaisesRegex(TypeError, "Cannot mix str"): + urllib.parse.urlunparse(("http", b"www.python.org","","","","")) + with self.assertRaisesRegex(TypeError, "Cannot mix str"): + urllib.parse.urlunsplit((b"http", "www.python.org","","","")) + with self.assertRaisesRegex(TypeError, "Cannot mix str"): + urllib.parse.urlunsplit(("http", b"www.python.org","","","")) + with self.assertRaisesRegex(TypeError, "Cannot mix str"): + urllib.parse.urljoin("http://python.org", b"http://python.org") + with self.assertRaisesRegex(TypeError, "Cannot mix str"): + urllib.parse.urljoin(b"http://python.org", "http://python.org") + + def _check_result_type(self, str_type): + num_args = len(str_type._fields) + bytes_type = str_type._encoded_counterpart + self.assertIs(bytes_type._decoded_counterpart, str_type) + str_args = ('',) * num_args + bytes_args = (b'',) * num_args + str_result = str_type(*str_args) + bytes_result = bytes_type(*bytes_args) + encoding = 'ascii' + errors = 'strict' + self.assertEqual(str_result, str_args) + self.assertEqual(bytes_result.decode(), str_args) + self.assertEqual(bytes_result.decode(), str_result) + self.assertEqual(bytes_result.decode(encoding), str_args) + self.assertEqual(bytes_result.decode(encoding), str_result) + self.assertEqual(bytes_result.decode(encoding, errors), str_args) + self.assertEqual(bytes_result.decode(encoding, errors), str_result) + self.assertEqual(bytes_result, bytes_args) + self.assertEqual(str_result.encode(), bytes_args) + self.assertEqual(str_result.encode(), bytes_result) + self.assertEqual(str_result.encode(encoding), bytes_args) + self.assertEqual(str_result.encode(encoding), bytes_result) + self.assertEqual(str_result.encode(encoding, errors), bytes_args) + self.assertEqual(str_result.encode(encoding, errors), bytes_result) + + def test_result_pairs(self): + # Check encoding and decoding between result pairs + result_types = [ + urllib.parse.DefragResult, + urllib.parse.SplitResult, + urllib.parse.ParseResult, + ] + for result_type in result_types: + self._check_result_type(result_type) + def test_main(): support.run_unittest(UrlParseTestCase) Modified: python/branches/py3k-cdecimal/Lib/test/test_weakset.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_weakset.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_weakset.py Sun Jan 2 13:18:37 2011 @@ -50,7 +50,8 @@ def test_contains(self): for c in self.letters: self.assertEqual(c in self.s, c in self.d) - self.assertRaises(TypeError, self.s.__contains__, [[]]) + # 1 is not weakref'able, but that TypeError is caught by __contains__ + self.assertNotIn(1, self.s) self.assertIn(self.obj, self.fs) del self.obj self.assertNotIn(ustr('F'), self.fs) Modified: python/branches/py3k-cdecimal/Lib/test/test_winsound.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_winsound.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_winsound.py Sun Jan 2 13:18:37 2011 @@ -249,6 +249,7 @@ p = subprocess.Popen([cscript_path, check_script], stdout=subprocess.PIPE) __have_soundcard_cache = not p.wait() + p.stdout.close() return __have_soundcard_cache Modified: python/branches/py3k-cdecimal/Lib/test/test_wsgiref.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_wsgiref.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_wsgiref.py Sun Jan 2 13:18:37 2011 @@ -342,6 +342,10 @@ self.checkReqURI("http://127.0.0.1/sp%C3%A4m", SCRIPT_NAME="/sp??m") self.checkReqURI("http://127.0.0.1/spammity/spam", SCRIPT_NAME="/spammity", PATH_INFO="/spam") + self.checkReqURI("http://127.0.0.1/spammity/spam;ham", + SCRIPT_NAME="/spammity", PATH_INFO="/spam;ham") + self.checkReqURI("http://127.0.0.1/spammity/spam;cookie=1234,5678", + SCRIPT_NAME="/spammity", PATH_INFO="/spam;cookie=1234,5678") self.checkReqURI("http://127.0.0.1/spammity/spam?say=ni", SCRIPT_NAME="/spammity", PATH_INFO="/spam",QUERY_STRING="say=ni") self.checkReqURI("http://127.0.0.1/spammity/spam", 0, Modified: python/branches/py3k-cdecimal/Lib/test/test_xml_etree.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_xml_etree.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_xml_etree.py Sun Jan 2 13:18:37 2011 @@ -1841,6 +1841,15 @@ """ +def check_issue10777(): + """ + Registering a namespace twice caused a "dictionary changed size during + iteration" bug. + + >>> ET.register_namespace('test10777', 'http://myuri/') + >>> ET.register_namespace('test10777', 'http://myuri/') + """ + # -------------------------------------------------------------------- Modified: python/branches/py3k-cdecimal/Lib/test/test_xml_etree_c.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_xml_etree_c.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_xml_etree_c.py Sun Jan 2 13:18:37 2011 @@ -8,10 +8,26 @@ # cElementTree specific tests def sanity(): - """ + r""" Import sanity. >>> from xml.etree import cElementTree + + Issue #6697. + + >>> e = cElementTree.Element('a') + >>> getattr(e, '\uD800') # doctest: +ELLIPSIS + Traceback (most recent call last): + ... + UnicodeEncodeError: ... + + >>> p = cElementTree.XMLParser() + >>> p.version.split()[0] + 'Expat' + >>> getattr(p, '\uD800') + Traceback (most recent call last): + ... + AttributeError: 'XMLParser' object has no attribute '\ud800' """ Modified: python/branches/py3k-cdecimal/Lib/test/test_xmlrpc.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_xmlrpc.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_xmlrpc.py Sun Jan 2 13:18:37 2011 @@ -715,8 +715,8 @@ t.encode_threshold = None t.fake_gzip = True p = xmlrpclib.ServerProxy(URL, transport=t) - cm = self.assertRaisesRegexp(xmlrpclib.ProtocolError, - re.compile(r"\b400\b")) + cm = self.assertRaisesRegex(xmlrpclib.ProtocolError, + re.compile(r"\b400\b")) with cm: p.pow(6, 8) Modified: python/branches/py3k-cdecimal/Lib/test/test_zipfile.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_zipfile.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_zipfile.py Sun Jan 2 13:18:37 2011 @@ -6,6 +6,7 @@ import io import os +import sys import imp import time import shutil @@ -23,6 +24,7 @@ TESTFN2 = TESTFN + "2" TESTFNDIR = TESTFN + "d" FIXEDTEST_SIZE = 1000 +DATAFILES_DIR = 'zipfile_datafiles' SMALL_TEST_DATA = [('_ziptest1', '1q2w3e4r5t'), ('ziptest2dir/_ziptest2', 'qawsedrftg'), @@ -487,6 +489,13 @@ except zipfile.BadZipFile: self.assertTrue(zipfp2.fp is None, 'zipfp is not closed') + def test_unicode_filenames(self): + # bug #10801 + fname = findfile('zip_cp437_header.zip') + with zipfile.ZipFile(fname) as zipfp: + for name in zipfp.namelist(): + zipfp.open(name).close() + def tearDown(self): unlink(TESTFN) unlink(TESTFN2) @@ -609,7 +618,7 @@ class PyZipFileTests(unittest.TestCase): def test_write_pyfile(self): - with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp: + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: fn = __file__ if fn.endswith('.pyc') or fn.endswith('.pyo'): path_split = fn.split(os.sep) @@ -627,7 +636,7 @@ self.assertTrue(bn + 'o' in zipfp.namelist() or bn + 'c' in zipfp.namelist()) - with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp: + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: fn = __file__ if fn.endswith(('.pyc', '.pyo')): fn = fn[:-1] @@ -643,7 +652,7 @@ import email packagedir = os.path.dirname(email.__file__) - with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp: + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: zipfp.writepy(packagedir) # Check for a couple of modules at different levels of the @@ -654,6 +663,22 @@ self.assertTrue('email/mime/text.pyo' in names or 'email/mime/text.pyc' in names) + def test_write_with_optimization(self): + import email + packagedir = os.path.dirname(email.__file__) + # use .pyc if running test in optimization mode, + # use .pyo if running test in debug mode + optlevel = 1 if __debug__ else 0 + ext = '.pyo' if optlevel == 1 else '.pyc' + + with TemporaryFile() as t, \ + zipfile.PyZipFile(t, "w", optimize=optlevel) as zipfp: + zipfp.writepy(packagedir) + + names = zipfp.namelist() + self.assertIn('email/__init__' + ext, names) + self.assertIn('email/mime/text' + ext, names) + def test_write_python_directory(self): os.mkdir(TESTFN2) try: @@ -666,26 +691,25 @@ with open(os.path.join(TESTFN2, "mod2.txt"), "w") as fp: fp.write("bla bla bla\n") - zipfp = zipfile.PyZipFile(TemporaryFile(), "w") - zipfp.writepy(TESTFN2) + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: + zipfp.writepy(TESTFN2) - names = zipfp.namelist() - self.assertTrue('mod1.pyc' in names or 'mod1.pyo' in names) - self.assertTrue('mod2.pyc' in names or 'mod2.pyo' in names) - self.assertNotIn('mod2.txt', names) + names = zipfp.namelist() + self.assertTrue('mod1.pyc' in names or 'mod1.pyo' in names) + self.assertTrue('mod2.pyc' in names or 'mod2.pyo' in names) + self.assertNotIn('mod2.txt', names) finally: shutil.rmtree(TESTFN2) def test_write_non_pyfile(self): - with zipfile.PyZipFile(TemporaryFile(), "w") as zipfp: + with TemporaryFile() as t, zipfile.PyZipFile(t, "w") as zipfp: with open(TESTFN, 'w') as f: f.write('most definitely not a python file') self.assertRaises(RuntimeError, zipfp.writepy, TESTFN) os.remove(TESTFN) - class OtherTests(unittest.TestCase): zips_with_bad_crc = { zipfile.ZIP_STORED: ( @@ -1074,6 +1098,12 @@ self.zip2.setpassword(b"12345") self.assertEqual(self.zip2.read("zero"), self.plain2) + def test_unicode_password(self): + self.assertRaises(TypeError, self.zip.setpassword, "unicode") + self.assertRaises(TypeError, self.zip.read, "test.txt", "python") + self.assertRaises(TypeError, self.zip.open, "test.txt", pwd="python") + self.assertRaises(TypeError, self.zip.extract, "test.txt", pwd="python") + class TestsWithRandomBinaryFiles(unittest.TestCase): def setUp(self): Modified: python/branches/py3k-cdecimal/Lib/test/test_zipimport_support.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_zipimport_support.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_zipimport_support.py Sun Jan 2 13:18:37 2011 @@ -200,7 +200,7 @@ pass import pdb - pdb.runcall(f) + pdb.Pdb(nosigint=True).runcall(f) """) with temp_dir() as d: script_name = make_script(d, 'script', test_src) Modified: python/branches/py3k-cdecimal/Lib/test/test_zlib.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/test_zlib.py (original) +++ python/branches/py3k-cdecimal/Lib/test/test_zlib.py Sun Jan 2 13:18:37 2011 @@ -143,7 +143,7 @@ def test_incomplete_stream(self): # An useful error message is given x = zlib.compress(HAMLET_SCENE) - self.assertRaisesRegexp(zlib.error, + self.assertRaisesRegex(zlib.error, "Error -5 while decompressing data: incomplete or truncated stream", zlib.decompress, x[:-1]) Modified: python/branches/py3k-cdecimal/Lib/test/win_console_handler.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/win_console_handler.py (original) +++ python/branches/py3k-cdecimal/Lib/test/win_console_handler.py Sun Jan 2 13:18:37 2011 @@ -40,7 +40,7 @@ print("Unable to add SetConsoleCtrlHandler") exit(-1) - # Awaken mail process + # Awake main process m = mmap.mmap(-1, 1, sys.argv[1]) m[0] = 1 Modified: python/branches/py3k-cdecimal/Lib/threading.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/threading.py (original) +++ python/branches/py3k-cdecimal/Lib/threading.py Sun Jan 2 13:18:37 2011 @@ -55,8 +55,14 @@ def _note(self, format, *args): if self._verbose: format = format % args - format = "%s: %s\n" % ( - current_thread().name, format) + # Issue #4188: calling current_thread() can incur an infinite + # recursion if it has to create a DummyThread on the fly. + ident = _get_ident() + try: + name = _active[ident].name + except KeyError: + name = "" % ident + format = "%s: %s\n" % (name, format) _sys.stderr.write(format) else: Modified: python/branches/py3k-cdecimal/Lib/tkinter/__init__.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/tkinter/__init__.py (original) +++ python/branches/py3k-cdecimal/Lib/tkinter/__init__.py Sun Jan 2 13:18:37 2011 @@ -216,8 +216,8 @@ self._master.deletecommand(cbname) def trace_vinfo(self): """Return all trace callback information.""" - return map(self._tk.split, self._tk.splitlist( - self._tk.call("trace", "vinfo", self._name))) + return [self._tk.split(x) for x in self._tk.splitlist( + self._tk.call("trace", "vinfo", self._name))] def __eq__(self, other): """Comparison for equality (==). @@ -855,7 +855,7 @@ includeids and 'includeids' or None)) if isinstance(data, str): data = [self.tk.split(data)] - return map(self.__winfo_parseitem, data) + return [self.__winfo_parseitem(x) for x in data] def __winfo_parseitem(self, t): """Internal function.""" return t[:1] + tuple(map(self.__winfo_getint, t[1:])) @@ -1200,8 +1200,8 @@ self.configure({key: value}) def keys(self): """Return a list of all resource names of this widget.""" - return map(lambda x: x[0][1:], - self.tk.split(self.tk.call(self._w, 'configure'))) + return [x[0][1:] for x in + self.tk.split(self.tk.call(self._w, 'configure'))] def __str__(self): """Return the window path name of this widget.""" return self._w @@ -1223,18 +1223,18 @@ def pack_slaves(self): """Return a list of all slaves of this widget in its packing order.""" - return map(self._nametowidget, - self.tk.splitlist( - self.tk.call('pack', 'slaves', self._w))) + return [self._nametowidget(x) for x in + self.tk.splitlist( + self.tk.call('pack', 'slaves', self._w))] slaves = pack_slaves # Place method that applies to the master def place_slaves(self): """Return a list of all slaves of this widget in its packing order.""" - return map(self._nametowidget, - self.tk.splitlist( + return [self._nametowidget(x) for x in + self.tk.splitlist( self.tk.call( - 'place', 'slaves', self._w))) + 'place', 'slaves', self._w))] # Grid methods that apply to the master def grid_bbox(self, column=None, row=None, col2=None, row2=None): """Return a tuple of integer coordinates for the bounding @@ -1338,9 +1338,9 @@ args = args + ('-row', row) if column is not None: args = args + ('-column', column) - return map(self._nametowidget, - self.tk.splitlist(self.tk.call( - ('grid', 'slaves', self._w) + args))) + return [self._nametowidget(x) for x in + self.tk.splitlist(self.tk.call( + ('grid', 'slaves', self._w) + args))] # Support for the "event" command, new in Tk 4.2. # By Case Roole. @@ -1494,7 +1494,7 @@ if len(wlist) > 1: wlist = (wlist,) # Tk needs a list of windows here args = ('wm', 'colormapwindows', self._w) + wlist - return map(self._nametowidget, self.tk.call(args)) + return [self._nametowidget(x) for x in self.tk.call(args)] colormapwindows = wm_colormapwindows def wm_command(self, value=None): """Store VALUE in WM_COMMAND property. It is the command @@ -2157,9 +2157,9 @@ def coords(self, *args): """Return a list of coordinates for the item given in ARGS.""" # XXX Should use _flatten on args - return map(getdouble, + return [getdouble(x) for x in self.tk.splitlist( - self.tk.call((self._w, 'coords') + args))) + self.tk.call((self._w, 'coords') + args))] def _create(self, itemType, args, kw): # Args: (val, val, ..., cnf={}) """Internal function.""" args = _flatten(args) Modified: python/branches/py3k-cdecimal/Lib/tkinter/scrolledtext.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/tkinter/scrolledtext.py (original) +++ python/branches/py3k-cdecimal/Lib/tkinter/scrolledtext.py Sun Jan 2 13:18:37 2011 @@ -30,8 +30,8 @@ # Copy geometry methods of self.frame without overriding Text # methods -- hack! text_meths = vars(Text).keys() - methods = vars(Pack).keys() + vars(Grid).keys() + vars(Place).keys() - methods = set(methods).difference(text_meths) + methods = vars(Pack).keys() | vars(Grid).keys() | vars(Place).keys() + methods = methods.difference(text_meths) for m in methods: if m[0] != '_' and m != 'config' and m != 'configure': @@ -42,11 +42,10 @@ def example(): - import __main__ from tkinter.constants import END stext = ScrolledText(bg='white', height=10) - stext.insert(END, __main__.__doc__) + stext.insert(END, __doc__) stext.pack(fill=BOTH, side=LEFT, expand=True) stext.focus_set() stext.mainloop() Modified: python/branches/py3k-cdecimal/Lib/tkinter/test/test_ttk/test_widgets.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/tkinter/test/test_ttk/test_widgets.py (original) +++ python/branches/py3k-cdecimal/Lib/tkinter/test/test_ttk/test_widgets.py Sun Jan 2 13:18:37 2011 @@ -1,5 +1,6 @@ import unittest import tkinter +import os from tkinter import ttk from test.support import requires, run_unittest @@ -925,7 +926,8 @@ self.assertRaises(tkinter.TclError, self.tv.heading, '#0', anchor=1) - + # XXX skipping for now; should be fixed to work with newer ttk + @unittest.skip def test_heading_callback(self): def simulate_heading_click(x, y): support.simulate_mouse_click(self.tv, x, y) Modified: python/branches/py3k-cdecimal/Lib/tkinter/tix.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/tkinter/tix.py (original) +++ python/branches/py3k-cdecimal/Lib/tkinter/tix.py Sun Jan 2 13:18:37 2011 @@ -268,10 +268,10 @@ return self.tk.call('tixForm', 'info', self._w, option) def slaves(self): - return map(self._nametowidget, - self.tk.splitlist( + return [self._nametowidget(x) for x in + self.tk.splitlist( self.tk.call( - 'tixForm', 'slaves', self._w))) + 'tixForm', 'slaves', self._w))] Modified: python/branches/py3k-cdecimal/Lib/turtle.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/turtle.py (original) +++ python/branches/py3k-cdecimal/Lib/turtle.py Sun Jan 2 13:18:37 2011 @@ -752,7 +752,7 @@ [(0.0, 9.9999999999999982), (0.0, -9.9999999999999982), (9.9999999999999982, 0.0)] >>> """ - cl = list(self.cv.coords(item)) + cl = self.cv.coords(item) pl = [(cl[i], -cl[i+1]) for i in range(0, len(cl), 2)] return pl Modified: python/branches/py3k-cdecimal/Lib/turtledemo/about_turtledemo.txt ============================================================================== --- python/branches/py3k-cdecimal/Lib/turtledemo/about_turtledemo.txt (original) +++ python/branches/py3k-cdecimal/Lib/turtledemo/about_turtledemo.txt Sun Jan 2 13:18:37 2011 @@ -1,9 +1,9 @@ -------------------------------------- - About turtleDemo.py + About this viewer -------------------------------------- - Tiny demo Viewer to view turtle graphics example scripts. + Tiny demo viewer to view turtle graphics example scripts. Quickly and dirtyly assembled by Gregor Lingl. June, 2006 Modified: python/branches/py3k-cdecimal/Lib/turtledemo/demohelp.txt ============================================================================== --- python/branches/py3k-cdecimal/Lib/turtledemo/demohelp.txt (original) +++ python/branches/py3k-cdecimal/Lib/turtledemo/demohelp.txt Sun Jan 2 13:18:37 2011 @@ -53,12 +53,7 @@ (2) How to add your own demos to the demo repository - - scriptname: must begin with tdemo_ , - so it must have the form tdemo_.py - - - place: same directory as turtleDemo.py or some - subdirectory, the name of which must also begin with - tdemo_..... + - place: same directory as turtledemo/__main__.py - requirements on source code: code must contain a main() function which will Modified: python/branches/py3k-cdecimal/Lib/unittest/case.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/case.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/case.py Sun Jan 2 13:18:37 2011 @@ -6,10 +6,12 @@ import pprint import re import warnings +import collections from . import result from .util import (strclass, safe_repr, sorted_list_difference, - unorderable_list_difference) + unorderable_list_difference, _count_diff_all_purpose, + _count_diff_hashable) __unittest = True @@ -24,7 +26,6 @@ Usually you can use TestResult.skip() or one of the skipping decorators instead of raising this directly. """ - pass class _ExpectedFailure(Exception): """ @@ -41,7 +42,17 @@ """ The test was supposed to fail, but it didn't! """ - pass + + +class _Outcome(object): + def __init__(self): + self.success = True + self.skipped = None + self.unexpectedSuccess = None + self.expectedFailure = None + self.errors = [] + self.failures = [] + def _id(obj): return obj @@ -93,7 +104,7 @@ class _AssertRaisesBaseContext(object): def __init__(self, expected, test_case, callable_obj=None, - expected_regexp=None): + expected_regex=None): self.expected = expected self.failureException = test_case.failureException if callable_obj is not None: @@ -103,9 +114,9 @@ self.obj_name = str(callable_obj) else: self.obj_name = None - if isinstance(expected_regexp, (bytes, str)): - expected_regexp = re.compile(expected_regexp) - self.expected_regexp = expected_regexp + if isinstance(expected_regex, (bytes, str)): + expected_regex = re.compile(expected_regex) + self.expected_regex = expected_regex class _AssertRaisesContext(_AssertRaisesBaseContext): @@ -131,13 +142,13 @@ return False # store exception, without traceback, for later retrieval self.exception = exc_value.with_traceback(None) - if self.expected_regexp is None: + if self.expected_regex is None: return True - expected_regexp = self.expected_regexp - if not expected_regexp.search(str(exc_value)): + expected_regex = self.expected_regex + if not expected_regex.search(str(exc_value)): raise self.failureException('"%s" does not match "%s"' % - (expected_regexp.pattern, str(exc_value))) + (expected_regex.pattern, str(exc_value))) return True @@ -171,8 +182,8 @@ continue if first_matching is None: first_matching = w - if (self.expected_regexp is not None and - not self.expected_regexp.search(str(w))): + if (self.expected_regex is not None and + not self.expected_regex.search(str(w))): continue # store warning for later retrieval self.warning = w @@ -182,7 +193,7 @@ # Now we simply try to choose a helpful failure message if first_matching is not None: raise self.failureException('"%s" does not match "%s"' % - (self.expected_regexp.pattern, str(first_matching))) + (self.expected_regex.pattern, str(first_matching))) if self.obj_name: raise self.failureException("{0} not triggered by {1}" .format(exc_name, self.obj_name)) @@ -244,7 +255,7 @@ # objects used in assert methods) will be printed on failure in *addition* # to any explicit message passed. - longMessage = False + longMessage = True # This attribute sets the maximum length of a diff in failure messages # by assert methods using difflib. It is looked up as an instance attribute @@ -262,7 +273,7 @@ not have a method with the specified name. """ self._testMethodName = methodName - self._resultForDoCleanups = None + self._outcomeForDoCleanups = None try: testMethod = getattr(self, methodName) except AttributeError: @@ -366,6 +377,36 @@ RuntimeWarning, 2) result.addSuccess(self) + def _executeTestPart(self, function, outcome, isTest=False): + try: + function() + except KeyboardInterrupt: + raise + except SkipTest as e: + outcome.success = False + outcome.skipped = str(e) + except _UnexpectedSuccess: + exc_info = sys.exc_info() + outcome.success = False + if isTest: + outcome.unexpectedSuccess = exc_info + else: + outcome.errors.append(exc_info) + except _ExpectedFailure: + outcome.success = False + exc_info = sys.exc_info() + if isTest: + outcome.expectedFailure = exc_info + else: + outcome.errors.append(exc_info) + except self.failureException: + outcome.success = False + outcome.failures.append(sys.exc_info()) + exc_info = sys.exc_info() + except: + outcome.success = False + outcome.errors.append(sys.exc_info()) + def run(self, result=None): orig_result = result if result is None: @@ -374,7 +415,6 @@ if startTestRun is not None: startTestRun() - self._resultForDoCleanups = result result.startTest(self) testMethod = getattr(self, self._testMethodName) @@ -389,51 +429,42 @@ result.stopTest(self) return try: - success = False - try: - self.setUp() - except SkipTest as e: - self._addSkip(result, str(e)) - except Exception: - result.addError(self, sys.exc_info()) + outcome = _Outcome() + self._outcomeForDoCleanups = outcome + + self._executeTestPart(self.setUp, outcome) + if outcome.success: + self._executeTestPart(testMethod, outcome, isTest=True) + self._executeTestPart(self.tearDown, outcome) + + self.doCleanups() + if outcome.success: + result.addSuccess(self) else: - try: - testMethod() - except self.failureException: - result.addFailure(self, sys.exc_info()) - except _ExpectedFailure as e: - addExpectedFailure = getattr(result, 'addExpectedFailure', None) - if addExpectedFailure is not None: - addExpectedFailure(self, e.exc_info) - else: - warnings.warn("TestResult has no addExpectedFailure method, reporting as passes", - RuntimeWarning) - result.addSuccess(self) - except _UnexpectedSuccess: + if outcome.skipped is not None: + self._addSkip(result, outcome.skipped) + for exc_info in outcome.errors: + result.addError(self, exc_info) + for exc_info in outcome.failures: + result.addFailure(self, exc_info) + if outcome.unexpectedSuccess is not None: addUnexpectedSuccess = getattr(result, 'addUnexpectedSuccess', None) if addUnexpectedSuccess is not None: addUnexpectedSuccess(self) else: warnings.warn("TestResult has no addUnexpectedSuccess method, reporting as failures", RuntimeWarning) - result.addFailure(self, sys.exc_info()) - except SkipTest as e: - self._addSkip(result, str(e)) - except Exception: - result.addError(self, sys.exc_info()) - else: - success = True + result.addFailure(self, outcome.unexpectedSuccess) + + if outcome.expectedFailure is not None: + addExpectedFailure = getattr(result, 'addExpectedFailure', None) + if addExpectedFailure is not None: + addExpectedFailure(self, outcome.expectedFailure) + else: + warnings.warn("TestResult has no addExpectedFailure method, reporting as passes", + RuntimeWarning) + result.addSuccess(self) - try: - self.tearDown() - except Exception: - result.addError(self, sys.exc_info()) - success = False - - cleanUpSuccess = self.doCleanups() - success = success and cleanUpSuccess - if success: - result.addSuccess(self) finally: result.stopTest(self) if orig_result is None: @@ -444,16 +475,15 @@ def doCleanups(self): """Execute all cleanup functions. Normally called for you after tearDown.""" - result = self._resultForDoCleanups - ok = True + outcome = self._outcomeForDoCleanups or _Outcome() while self._cleanups: - function, args, kwargs = self._cleanups.pop(-1) - try: - function(*args, **kwargs) - except Exception: - ok = False - result.addError(self, sys.exc_info()) - return ok + function, args, kwargs = self._cleanups.pop() + part = lambda: function(*args, **kwargs) + self._executeTestPart(part, outcome) + + # return this for backwards compatibility + # even though we no longer us it internally + return outcome.success def __call__(self, *args, **kwds): return self.run(*args, **kwds) @@ -476,15 +506,15 @@ raise self.failureException(msg) def assertFalse(self, expr, msg=None): - "Fail the test if the expression is true." + """Check that the expression is false.""" if expr: - msg = self._formatMessage(msg, "%s is not False" % safe_repr(expr)) + msg = self._formatMessage(msg, "%s is not false" % safe_repr(expr)) raise self.failureException(msg) def assertTrue(self, expr, msg=None): - """Fail the test unless the expression is true.""" + """Check that the expression is true.""" if not expr: - msg = self._formatMessage(msg, "%s is not True" % safe_repr(expr)) + msg = self._formatMessage(msg, "%s is not true" % safe_repr(expr)) raise self.failureException(msg) def _formatMessage(self, msg, standardMsg): @@ -687,34 +717,6 @@ msg = self._formatMessage(msg, standardMsg) raise self.failureException(msg) - # Synonyms for assertion methods - - # The plurals are undocumented. Keep them that way to discourage use. - # Do not add more. Do not remove. - # Going through a deprecation cycle on these would annoy many people. - assertEquals = assertEqual - assertNotEquals = assertNotEqual - assertAlmostEquals = assertAlmostEqual - assertNotAlmostEquals = assertNotAlmostEqual - assert_ = assertTrue - - # These fail* assertion method names are pending deprecation and will - # be a DeprecationWarning in 3.2; http://bugs.python.org/issue2578 - def _deprecate(original_func): - def deprecated_func(*args, **kwargs): - warnings.warn( - 'Please use {0} instead.'.format(original_func.__name__), - DeprecationWarning, 2) - return original_func(*args, **kwargs) - return deprecated_func - - failUnlessEqual = _deprecate(assertEqual) - failIfEqual = _deprecate(assertNotEqual) - failUnlessAlmostEqual = _deprecate(assertAlmostEqual) - failIfAlmostEqual = _deprecate(assertNotAlmostEqual) - failUnless = _deprecate(assertTrue) - failUnlessRaises = _deprecate(assertRaises) - failIf = _deprecate(assertFalse) def assertSequenceEqual(self, seq1, seq2, msg=None, seq_type=None): """An equality assertion for ordered sequences (like lists and tuples). @@ -931,17 +933,19 @@ standardMsg = self._truncateMessage(standardMsg, diff) self.fail(self._formatMessage(msg, standardMsg)) - def assertDictContainsSubset(self, expected, actual, msg=None): - """Checks whether actual is a superset of expected.""" + def assertDictContainsSubset(self, subset, dictionary, msg=None): + """Checks whether dictionary is a superset of subset.""" + warnings.warn('assertDictContainsSubset is deprecated', + DeprecationWarning) missing = [] mismatched = [] - for key, value in expected.items(): - if key not in actual: + for key, value in subset.items(): + if key not in dictionary: missing.append(key) - elif value != actual[key]: + elif value != dictionary[key]: mismatched.append('%s, expected: %s, actual: %s' % (safe_repr(key), safe_repr(value), - safe_repr(actual[key]))) + safe_repr(dictionary[key]))) if not (missing or mismatched): return @@ -1000,42 +1004,38 @@ self.fail(self._formatMessage(msg, standardMsg)) - def assertItemsEqual(self, expected_seq, actual_seq, msg=None): - """An unordered sequence / set specific comparison. It asserts that - expected_seq and actual_seq contain the same elements. It is - the equivalent of:: + def assertCountEqual(self, first, second, msg=None): + """An unordered sequence comparison asserting that the same elements, + regardless of order. If the same element occurs more than once, + it verifies that the elements occur the same number of times. - self.assertEqual(sorted(expected_seq), sorted(actual_seq)) + self.assertEqual(Counter(list(first)), + Counter(list(second))) - Raises with an error message listing which elements of expected_seq - are missing from actual_seq and vice versa if any. - - Asserts that each element has the same count in both sequences. - Example: + Example: - [0, 1, 1] and [1, 0, 1] compare equal. - [0, 0, 1] and [0, 1] compare unequal. + """ + actual_seq, expected_seq = list(first), list(second) try: - expected = sorted(expected_seq) - actual = sorted(actual_seq) + actual = collections.Counter(actual_seq) + expected = collections.Counter(expected_seq) except TypeError: - # Unsortable items (example: set(), complex(), ...) - expected = list(expected_seq) - actual = list(actual_seq) - missing, unexpected = unorderable_list_difference(expected, actual) + # Handle case with unhashable elements + differences = _count_diff_all_purpose(actual_seq, expected_seq) else: - return self.assertSequenceEqual(expected, actual, msg=msg) + if actual == expected: + return + differences = _count_diff_hashable(actual_seq, expected_seq) - errors = [] - if missing: - errors.append('Expected, but missing:\n %s' % - safe_repr(missing)) - if unexpected: - errors.append('Unexpected, but present:\n %s' % - safe_repr(unexpected)) - if errors: - standardMsg = '\n'.join(errors) - self.fail(self._formatMessage(msg, standardMsg)) + if differences: + standardMsg = 'Element counts were not equal:\n' + lines = ['First has %d, Second has %d: %r' % diff for diff in differences] + diffMsg = '\n'.join(lines) + standardMsg = self._truncateMessage(standardMsg, diffMsg) + msg = self._formatMessage(msg, standardMsg) + self.fail(msg) def assertMultiLineEqual(self, first, second, msg=None): """Assert that two multi-line strings are equal.""" @@ -1103,27 +1103,27 @@ standardMsg = '%s is an instance of %r' % (safe_repr(obj), cls) self.fail(self._formatMessage(msg, standardMsg)) - def assertRaisesRegexp(self, expected_exception, expected_regexp, - callable_obj=None, *args, **kwargs): - """Asserts that the message in a raised exception matches a regexp. + def assertRaisesRegex(self, expected_exception, expected_regex, + callable_obj=None, *args, **kwargs): + """Asserts that the message in a raised exception matches a regex. Args: expected_exception: Exception class expected to be raised. - expected_regexp: Regexp (re pattern object or string) expected + expected_regex: Regex (re pattern object or string) expected to be found in error message. callable_obj: Function to be called. args: Extra args. kwargs: Extra kwargs. """ context = _AssertRaisesContext(expected_exception, self, callable_obj, - expected_regexp) + expected_regex) if callable_obj is None: return context with context: callable_obj(*args, **kwargs) - def assertWarnsRegexp(self, expected_warning, expected_regexp, - callable_obj=None, *args, **kwargs): + def assertWarnsRegex(self, expected_warning, expected_regex, + callable_obj=None, *args, **kwargs): """Asserts that the message in a triggered warning matches a regexp. Basic functioning is similar to assertWarns() with the addition that only warnings whose messages also match the regular expression @@ -1131,42 +1131,65 @@ Args: expected_warning: Warning class expected to be triggered. - expected_regexp: Regexp (re pattern object or string) expected + expected_regex: Regex (re pattern object or string) expected to be found in error message. callable_obj: Function to be called. args: Extra args. kwargs: Extra kwargs. """ context = _AssertWarnsContext(expected_warning, self, callable_obj, - expected_regexp) + expected_regex) if callable_obj is None: return context with context: callable_obj(*args, **kwargs) - def assertRegexpMatches(self, text, expected_regexp, msg=None): + def assertRegex(self, text, expected_regex, msg=None): """Fail the test unless the text matches the regular expression.""" - if isinstance(expected_regexp, (str, bytes)): - expected_regexp = re.compile(expected_regexp) - if not expected_regexp.search(text): - msg = msg or "Regexp didn't match" - msg = '%s: %r not found in %r' % (msg, expected_regexp.pattern, text) + if isinstance(expected_regex, (str, bytes)): + assert expected_regex, "expected_regex must not be empty." + expected_regex = re.compile(expected_regex) + if not expected_regex.search(text): + msg = msg or "Regex didn't match" + msg = '%s: %r not found in %r' % (msg, expected_regex.pattern, text) raise self.failureException(msg) - def assertNotRegexpMatches(self, text, unexpected_regexp, msg=None): + def assertNotRegex(self, text, unexpected_regex, msg=None): """Fail the test if the text matches the regular expression.""" - if isinstance(unexpected_regexp, (str, bytes)): - unexpected_regexp = re.compile(unexpected_regexp) - match = unexpected_regexp.search(text) + if isinstance(unexpected_regex, (str, bytes)): + unexpected_regex = re.compile(unexpected_regex) + match = unexpected_regex.search(text) if match: - msg = msg or "Regexp matched" + msg = msg or "Regex matched" msg = '%s: %r matches %r in %r' % (msg, text[match.start():match.end()], - unexpected_regexp.pattern, + unexpected_regex.pattern, text) raise self.failureException(msg) + def _deprecate(original_func): + def deprecated_func(*args, **kwargs): + warnings.warn( + 'Please use {0} instead.'.format(original_func.__name__), + DeprecationWarning, 2) + return original_func(*args, **kwargs) + return deprecated_func + + # The fail* methods can be removed in 3.3, the 5 assert* methods will + # have to stay around for a few more versions. See #9424. + failUnlessEqual = assertEquals = _deprecate(assertEqual) + failIfEqual = assertNotEquals = _deprecate(assertNotEqual) + failUnlessAlmostEqual = assertAlmostEquals = _deprecate(assertAlmostEqual) + failIfAlmostEqual = assertNotAlmostEquals = _deprecate(assertNotAlmostEqual) + failUnless = assert_ = _deprecate(assertTrue) + failUnlessRaises = _deprecate(assertRaises) + failIf = _deprecate(assertFalse) + assertRaisesRegexp = _deprecate(assertRaisesRegex) + assertRegexpMatches = _deprecate(assertRegex) + + + class FunctionTestCase(TestCase): """A test case that wraps a test function. Modified: python/branches/py3k-cdecimal/Lib/unittest/main.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/main.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/main.py Sun Jan 2 13:18:37 2011 @@ -58,7 +58,24 @@ in MyTestCase """ +def _convert_name(name): + # on Linux / Mac OS X 'foo.PY' is not importable, but on + # Windows it is. Simpler to do a case insensitive match + # a better check would be to check that the name is a + # valid Python module name. + if os.path.isfile(name) and name.lower().endswith('.py'): + if os.path.isabs(name): + rel_path = os.path.relpath(name, os.getcwd()) + if os.path.isabs(rel_path) or rel_path.startswith(os.pardir): + return name + name = rel_path + # on Windows both '\' and '/' are used as path + # separators. Better to replace both than rely on os.path.sep + return name[:-3].replace('\\', '.').replace('/', '.') + return name +def _convert_names(names): + return [_convert_name(name) for name in names] class TestProgram(object): """A command-line program that runs a set of tests; this is primarily @@ -67,12 +84,12 @@ USAGE = USAGE_FROM_MODULE # defaults for testing - failfast = catchbreak = buffer = progName = None + failfast = catchbreak = buffer = progName = warnings = None def __init__(self, module='__main__', defaultTest=None, argv=None, testRunner=None, testLoader=loader.defaultTestLoader, exit=True, verbosity=1, failfast=None, catchbreak=None, - buffer=None): + buffer=None, warnings=None): if isinstance(module, str): self.module = __import__(module) for part in module.split('.')[1:]: @@ -87,6 +104,18 @@ self.catchbreak = catchbreak self.verbosity = verbosity self.buffer = buffer + if warnings is None and not sys.warnoptions: + # even if DreprecationWarnings are ignored by default + # print them anyway unless other warnings settings are + # specified by the warnings arg or the -W python flag + self.warnings = 'default' + else: + # here self.warnings is set either to the value passed + # to the warnings args or to None. + # If the user didn't pass a value self.warnings will + # be None. This means that the behavior is unchanged + # and depends on the values passed to -W. + self.warnings = warnings self.defaultTest = defaultTest self.testRunner = testRunner self.testLoader = testLoader @@ -118,38 +147,48 @@ long_opts = ['help', 'verbose', 'quiet', 'failfast', 'catch', 'buffer'] try: options, args = getopt.getopt(argv[1:], 'hHvqfcb', long_opts) - for opt, value in options: - if opt in ('-h','-H','--help'): - self.usageExit() - if opt in ('-q','--quiet'): - self.verbosity = 0 - if opt in ('-v','--verbose'): - self.verbosity = 2 - if opt in ('-f','--failfast'): - if self.failfast is None: - self.failfast = True - # Should this raise an exception if -f is not valid? - if opt in ('-c','--catch'): - if self.catchbreak is None: - self.catchbreak = True - # Should this raise an exception if -c is not valid? - if opt in ('-b','--buffer'): - if self.buffer is None: - self.buffer = True - # Should this raise an exception if -b is not valid? - if len(args) == 0 and self.defaultTest is None: - # createTests will load tests from self.module - self.testNames = None - elif len(args) > 0: - self.testNames = args - if __name__ == '__main__': - # to support python -m unittest ... - self.module = None - else: - self.testNames = (self.defaultTest,) - self.createTests() except getopt.error as msg: self.usageExit(msg) + return + + for opt, value in options: + if opt in ('-h','-H','--help'): + self.usageExit() + if opt in ('-q','--quiet'): + self.verbosity = 0 + if opt in ('-v','--verbose'): + self.verbosity = 2 + if opt in ('-f','--failfast'): + if self.failfast is None: + self.failfast = True + # Should this raise an exception if -f is not valid? + if opt in ('-c','--catch'): + if self.catchbreak is None: + self.catchbreak = True + # Should this raise an exception if -c is not valid? + if opt in ('-b','--buffer'): + if self.buffer is None: + self.buffer = True + # Should this raise an exception if -b is not valid? + + if len(args) == 0 and self.module is None: + # this allows "python -m unittest -v" to still work for + # test discovery. This means -c / -b / -v / -f options will + # be handled twice, which is harmless but not ideal. + self._do_discovery(argv[1:]) + return + + if len(args) == 0 and self.defaultTest is None: + # createTests will load tests from self.module + self.testNames = None + elif len(args) > 0: + self.testNames = _convert_names(args) + if __name__ == '__main__': + # to support python -m unittest ... + self.module = None + else: + self.testNames = (self.defaultTest,) + self.createTests() def createTests(self): if self.testNames is None: @@ -220,7 +259,8 @@ try: testRunner = self.testRunner(verbosity=self.verbosity, failfast=self.failfast, - buffer=self.buffer) + buffer=self.buffer, + warnings=self.warnings) except TypeError: # didn't accept the verbosity, buffer or failfast arguments testRunner = self.testRunner() Modified: python/branches/py3k-cdecimal/Lib/unittest/runner.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/runner.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/runner.py Sun Jan 2 13:18:37 2011 @@ -2,6 +2,7 @@ import sys import time +import warnings from . import result from .signals import registerResult @@ -124,13 +125,16 @@ """ resultclass = TextTestResult - def __init__(self, stream=sys.stderr, descriptions=True, verbosity=1, - failfast=False, buffer=False, resultclass=None): + def __init__(self, stream=None, descriptions=True, verbosity=1, + failfast=False, buffer=False, resultclass=None, warnings=None): + if stream is None: + stream = sys.stderr self.stream = _WritelnDecorator(stream) self.descriptions = descriptions self.verbosity = verbosity self.failfast = failfast self.buffer = buffer + self.warnings = warnings if resultclass is not None: self.resultclass = resultclass @@ -143,17 +147,30 @@ registerResult(result) result.failfast = self.failfast result.buffer = self.buffer - startTime = time.time() - startTestRun = getattr(result, 'startTestRun', None) - if startTestRun is not None: - startTestRun() - try: - test(result) - finally: - stopTestRun = getattr(result, 'stopTestRun', None) - if stopTestRun is not None: - stopTestRun() - stopTime = time.time() + with warnings.catch_warnings(): + if self.warnings: + # if self.warnings is set, use it to filter all the warnings + warnings.simplefilter(self.warnings) + # if the filter is 'default' or 'always', special-case the + # warnings from the deprecated unittest methods to show them + # no more than once per module, because they can be fairly + # noisy. The -Wd and -Wa flags can be used to bypass this + # only when self.warnings is None. + if self.warnings in ['default', 'always']: + warnings.filterwarnings('module', + category=DeprecationWarning, + message='Please use assert\w+ instead.') + startTime = time.time() + startTestRun = getattr(result, 'startTestRun', None) + if startTestRun is not None: + startTestRun() + try: + test(result) + finally: + stopTestRun = getattr(result, 'stopTestRun', None) + if stopTestRun is not None: + stopTestRun() + stopTime = time.time() timeTaken = stopTime - startTime result.printErrors() if hasattr(result, 'separator2'): Modified: python/branches/py3k-cdecimal/Lib/unittest/suite.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/suite.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/suite.py Sun Jan 2 13:18:37 2011 @@ -104,6 +104,7 @@ if topLevel: self._tearDownPreviousClass(None, result) self._handleModuleTearDown(result) + result._testRunEntered = False return result def debug(self): Modified: python/branches/py3k-cdecimal/Lib/unittest/test/test_assertions.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/test/test_assertions.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/test/test_assertions.py Sun Jan 2 13:18:37 2011 @@ -92,15 +92,15 @@ else: self.fail("assertRaises() didn't let exception pass through") - def testAssertNotRegexpMatches(self): - self.assertNotRegexpMatches('Ala ma kota', r'r+') + def testAssertNotRegex(self): + self.assertNotRegex('Ala ma kota', r'r+') try: - self.assertNotRegexpMatches('Ala ma kota', r'k.t', 'Message') + self.assertNotRegex('Ala ma kota', r'k.t', 'Message') except self.failureException as e: self.assertIn("'kot'", e.args[0]) self.assertIn('Message', e.args[0]) else: - self.fail('assertNotRegexpMatches should have failed.') + self.fail('assertNotRegex should have failed.') class TestLongMessage(unittest.TestCase): @@ -127,7 +127,7 @@ self.testableFalse = TestableTestFalse('testTest') def testDefault(self): - self.assertFalse(unittest.TestCase.longMessage) + self.assertTrue(unittest.TestCase.longMessage) def test_formatMsg(self): self.assertEqual(self.testableFalse._formatMessage(None, "foo"), "foo") @@ -153,26 +153,26 @@ test = self.testableTrue return getattr(test, methodName) - for i, expected_regexp in enumerate(errors): + for i, expected_regex in enumerate(errors): testMethod = getMethod(i) kwargs = {} withMsg = i % 2 if withMsg: kwargs = {"msg": "oops"} - with self.assertRaisesRegexp(self.failureException, - expected_regexp=expected_regexp): + with self.assertRaisesRegex(self.failureException, + expected_regex=expected_regex): testMethod(*args, **kwargs) def testAssertTrue(self): self.assertMessages('assertTrue', (False,), - ["^False is not True$", "^oops$", "^False is not True$", - "^False is not True : oops$"]) + ["^False is not true$", "^oops$", "^False is not true$", + "^False is not true : oops$"]) def testAssertFalse(self): self.assertMessages('assertFalse', (True,), - ["^True is not False$", "^oops$", "^True is not False$", - "^True is not False : oops$"]) + ["^True is not false$", "^oops$", "^True is not false$", + "^True is not false : oops$"]) def testNotEqual(self): self.assertMessages('assertNotEqual', (1, 1), @@ -229,12 +229,6 @@ "^Missing: 'key'$", "^Missing: 'key' : oops$"]) - def testAssertItemsEqual(self): - self.assertMessages('assertItemsEqual', ([], [None]), - [r"\[None\]$", "^oops$", - r"\[None\]$", - r"\[None\] : oops$"]) - def testAssertMultiLineEqual(self): self.assertMessages('assertMultiLineEqual', ("", "foo"), [r"\+ foo$", "^oops$", Modified: python/branches/py3k-cdecimal/Lib/unittest/test/test_break.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/test/test_break.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/test/test_break.py Sun Jan 2 13:18:37 2011 @@ -209,7 +209,8 @@ self.assertEqual(FakeRunner.initArgs, [((), {'buffer': None, 'verbosity': verbosity, - 'failfast': failfast})]) + 'failfast': failfast, + 'warnings': None})]) self.assertEqual(FakeRunner.runArgs, [test]) self.assertEqual(p.result, result) @@ -222,7 +223,8 @@ self.assertEqual(FakeRunner.initArgs, [((), {'buffer': None, 'verbosity': verbosity, - 'failfast': failfast})]) + 'failfast': failfast, + 'warnings': None})]) self.assertEqual(FakeRunner.runArgs, [test]) self.assertEqual(p.result, result) Modified: python/branches/py3k-cdecimal/Lib/unittest/test/test_case.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/test/test_case.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/test/test_case.py Sun Jan 2 13:18:37 2011 @@ -177,8 +177,8 @@ super(Foo, self).test() raise RuntimeError('raised by Foo.test') - expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown', - 'stopTest'] + expected = ['startTest', 'setUp', 'test', 'tearDown', + 'addError', 'stopTest'] Foo(events).run(result) self.assertEqual(events, expected) @@ -195,8 +195,8 @@ super(Foo, self).test() raise RuntimeError('raised by Foo.test') - expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addError', - 'tearDown', 'stopTest', 'stopTestRun'] + expected = ['startTestRun', 'startTest', 'setUp', 'test', + 'tearDown', 'addError', 'stopTest', 'stopTestRun'] Foo(events).run() self.assertEqual(events, expected) @@ -216,8 +216,8 @@ super(Foo, self).test() self.fail('raised by Foo.test') - expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown', - 'stopTest'] + expected = ['startTest', 'setUp', 'test', 'tearDown', + 'addFailure', 'stopTest'] Foo(events).run(result) self.assertEqual(events, expected) @@ -231,8 +231,8 @@ super(Foo, self).test() self.fail('raised by Foo.test') - expected = ['startTestRun', 'startTest', 'setUp', 'test', 'addFailure', - 'tearDown', 'stopTest', 'stopTestRun'] + expected = ['startTestRun', 'startTest', 'setUp', 'test', + 'tearDown', 'addFailure', 'stopTest', 'stopTestRun'] events = [] Foo(events).run() self.assertEqual(events, expected) @@ -672,46 +672,68 @@ else: self.fail('assertMultiLineEqual did not fail') - def testAssertItemsEqual(self): + def testAssertCountEqual(self): a = object() - self.assertItemsEqual([1, 2, 3], [3, 2, 1]) - self.assertItemsEqual(['foo', 'bar', 'baz'], ['bar', 'baz', 'foo']) - self.assertItemsEqual([a, a, 2, 2, 3], (a, 2, 3, a, 2)) - self.assertItemsEqual([1, "2", "a", "a"], ["a", "2", True, "a"]) - self.assertRaises(self.failureException, self.assertItemsEqual, + self.assertCountEqual([1, 2, 3], [3, 2, 1]) + self.assertCountEqual(['foo', 'bar', 'baz'], ['bar', 'baz', 'foo']) + self.assertCountEqual([a, a, 2, 2, 3], (a, 2, 3, a, 2)) + self.assertCountEqual([1, "2", "a", "a"], ["a", "2", True, "a"]) + self.assertRaises(self.failureException, self.assertCountEqual, [1, 2] + [3] * 100, [1] * 100 + [2, 3]) - self.assertRaises(self.failureException, self.assertItemsEqual, + self.assertRaises(self.failureException, self.assertCountEqual, [1, "2", "a", "a"], ["a", "2", True, 1]) - self.assertRaises(self.failureException, self.assertItemsEqual, + self.assertRaises(self.failureException, self.assertCountEqual, [10], [10, 11]) - self.assertRaises(self.failureException, self.assertItemsEqual, + self.assertRaises(self.failureException, self.assertCountEqual, [10, 11], [10]) - self.assertRaises(self.failureException, self.assertItemsEqual, + self.assertRaises(self.failureException, self.assertCountEqual, [10, 11, 10], [10, 11]) # Test that sequences of unhashable objects can be tested for sameness: - self.assertItemsEqual([[1, 2], [3, 4], 0], [False, [3, 4], [1, 2]]) + self.assertCountEqual([[1, 2], [3, 4], 0], [False, [3, 4], [1, 2]]) + # Test that iterator of unhashable objects can be tested for sameness: + self.assertCountEqual(iter([1, 2, [], 3, 4]), + iter([1, 2, [], 3, 4])) # hashable types, but not orderable - self.assertRaises(self.failureException, self.assertItemsEqual, + self.assertRaises(self.failureException, self.assertCountEqual, [], [divmod, 'x', 1, 5j, 2j, frozenset()]) # comparing dicts - self.assertItemsEqual([{'a': 1}, {'b': 2}], [{'b': 2}, {'a': 1}]) + self.assertCountEqual([{'a': 1}, {'b': 2}], [{'b': 2}, {'a': 1}]) # comparing heterogenous non-hashable sequences - self.assertItemsEqual([1, 'x', divmod, []], [divmod, [], 'x', 1]) - self.assertRaises(self.failureException, self.assertItemsEqual, + self.assertCountEqual([1, 'x', divmod, []], [divmod, [], 'x', 1]) + self.assertRaises(self.failureException, self.assertCountEqual, [], [divmod, [], 'x', 1, 5j, 2j, set()]) - self.assertRaises(self.failureException, self.assertItemsEqual, + self.assertRaises(self.failureException, self.assertCountEqual, [[1]], [[2]]) # Same elements, but not same sequence length - self.assertRaises(self.failureException, self.assertItemsEqual, + self.assertRaises(self.failureException, self.assertCountEqual, [1, 1, 2], [2, 1]) - self.assertRaises(self.failureException, self.assertItemsEqual, + self.assertRaises(self.failureException, self.assertCountEqual, [1, 1, "2", "a", "a"], ["2", "2", True, "a"]) - self.assertRaises(self.failureException, self.assertItemsEqual, + self.assertRaises(self.failureException, self.assertCountEqual, [1, {'b': 2}, None, True], [{'b': 2}, True, None]) + # Same elements which don't reliably compare, in + # different order, see issue 10242 + a = [{2,4}, {1,2}] + b = a[::-1] + self.assertCountEqual(a, b) + + # test utility functions supporting assertCountEqual() + + diffs = set(unittest.util._count_diff_all_purpose('aaabccd', 'abbbcce')) + expected = {(3,1,'a'), (1,3,'b'), (1,0,'d'), (0,1,'e')} + self.assertEqual(diffs, expected) + + diffs = unittest.util._count_diff_all_purpose([[]], []) + self.assertEqual(diffs, [(1, 0, [])]) + + diffs = set(unittest.util._count_diff_hashable('aaabccd', 'abbbcce')) + expected = {(3,1,'a'), (1,3,'b'), (1,0,'d'), (0,1,'e')} + self.assertEqual(diffs, expected) + def testAssertSetEqual(self): set1 = set() set2 = set() @@ -865,44 +887,44 @@ self.assertIsNotNone('DjZoPloGears on Rails') self.assertRaises(self.failureException, self.assertIsNotNone, None) - def testAssertRegexpMatches(self): - self.assertRegexpMatches('asdfabasdf', r'ab+') - self.assertRaises(self.failureException, self.assertRegexpMatches, + def testAssertRegex(self): + self.assertRegex('asdfabasdf', r'ab+') + self.assertRaises(self.failureException, self.assertRegex, 'saaas', r'aaaa') - def testAssertRaisesRegexp(self): + def testAssertRaisesRegex(self): class ExceptionMock(Exception): pass def Stub(): raise ExceptionMock('We expect') - self.assertRaisesRegexp(ExceptionMock, re.compile('expect$'), Stub) - self.assertRaisesRegexp(ExceptionMock, 'expect$', Stub) + self.assertRaisesRegex(ExceptionMock, re.compile('expect$'), Stub) + self.assertRaisesRegex(ExceptionMock, 'expect$', Stub) - def testAssertNotRaisesRegexp(self): - self.assertRaisesRegexp( + def testAssertNotRaisesRegex(self): + self.assertRaisesRegex( self.failureException, '^Exception not raised by $', - self.assertRaisesRegexp, Exception, re.compile('x'), + self.assertRaisesRegex, Exception, re.compile('x'), lambda: None) - self.assertRaisesRegexp( + self.assertRaisesRegex( self.failureException, '^Exception not raised by $', - self.assertRaisesRegexp, Exception, 'x', + self.assertRaisesRegex, Exception, 'x', lambda: None) - def testAssertRaisesRegexpMismatch(self): + def testAssertRaisesRegexMismatch(self): def Stub(): raise Exception('Unexpected') - self.assertRaisesRegexp( + self.assertRaisesRegex( self.failureException, r'"\^Expected\$" does not match "Unexpected"', - self.assertRaisesRegexp, Exception, '^Expected$', + self.assertRaisesRegex, Exception, '^Expected$', Stub) - self.assertRaisesRegexp( + self.assertRaisesRegex( self.failureException, r'"\^Expected\$" does not match "Unexpected"', - self.assertRaisesRegexp, Exception, + self.assertRaisesRegex, Exception, re.compile('^Expected$'), Stub) def testAssertRaisesExcValue(self): @@ -986,26 +1008,26 @@ with self.assertWarns(DeprecationWarning): _runtime_warn() - def testAssertWarnsRegexpCallable(self): + def testAssertWarnsRegexCallable(self): def _runtime_warn(msg): warnings.warn(msg, RuntimeWarning) - self.assertWarnsRegexp(RuntimeWarning, "o+", - _runtime_warn, "foox") + self.assertWarnsRegex(RuntimeWarning, "o+", + _runtime_warn, "foox") # Failure when no warning is triggered with self.assertRaises(self.failureException): - self.assertWarnsRegexp(RuntimeWarning, "o+", - lambda: 0) + self.assertWarnsRegex(RuntimeWarning, "o+", + lambda: 0) # Failure when another warning is triggered with warnings.catch_warnings(): # Force default filter (in case tests are run with -We) warnings.simplefilter("default", RuntimeWarning) with self.assertRaises(self.failureException): - self.assertWarnsRegexp(DeprecationWarning, "o+", - _runtime_warn, "foox") + self.assertWarnsRegex(DeprecationWarning, "o+", + _runtime_warn, "foox") # Failure when message doesn't match with self.assertRaises(self.failureException): - self.assertWarnsRegexp(RuntimeWarning, "o+", - _runtime_warn, "barz") + self.assertWarnsRegex(RuntimeWarning, "o+", + _runtime_warn, "barz") # A little trickier: we ask RuntimeWarnings to be raised, and then # check for some of them. It is implementation-defined whether # non-matching RuntimeWarnings are simply re-raised, or produce a @@ -1013,15 +1035,15 @@ with warnings.catch_warnings(): warnings.simplefilter("error", RuntimeWarning) with self.assertRaises((RuntimeWarning, self.failureException)): - self.assertWarnsRegexp(RuntimeWarning, "o+", - _runtime_warn, "barz") + self.assertWarnsRegex(RuntimeWarning, "o+", + _runtime_warn, "barz") - def testAssertWarnsRegexpContext(self): - # Same as above, but with assertWarnsRegexp as a context manager + def testAssertWarnsRegexContext(self): + # Same as above, but with assertWarnsRegex as a context manager def _runtime_warn(msg): warnings.warn(msg, RuntimeWarning) _runtime_warn_lineno = inspect.getsourcelines(_runtime_warn)[1] - with self.assertWarnsRegexp(RuntimeWarning, "o+") as cm: + with self.assertWarnsRegex(RuntimeWarning, "o+") as cm: _runtime_warn("foox") self.assertIsInstance(cm.warning, RuntimeWarning) self.assertEqual(cm.warning.args[0], "foox") @@ -1029,18 +1051,18 @@ self.assertEqual(cm.lineno, _runtime_warn_lineno + 1) # Failure when no warning is triggered with self.assertRaises(self.failureException): - with self.assertWarnsRegexp(RuntimeWarning, "o+"): + with self.assertWarnsRegex(RuntimeWarning, "o+"): pass # Failure when another warning is triggered with warnings.catch_warnings(): # Force default filter (in case tests are run with -We) warnings.simplefilter("default", RuntimeWarning) with self.assertRaises(self.failureException): - with self.assertWarnsRegexp(DeprecationWarning, "o+"): + with self.assertWarnsRegex(DeprecationWarning, "o+"): _runtime_warn("foox") # Failure when message doesn't match with self.assertRaises(self.failureException): - with self.assertWarnsRegexp(RuntimeWarning, "o+"): + with self.assertWarnsRegex(RuntimeWarning, "o+"): _runtime_warn("barz") # A little trickier: we ask RuntimeWarnings to be raised, and then # check for some of them. It is implementation-defined whether @@ -1049,42 +1071,49 @@ with warnings.catch_warnings(): warnings.simplefilter("error", RuntimeWarning) with self.assertRaises((RuntimeWarning, self.failureException)): - with self.assertWarnsRegexp(RuntimeWarning, "o+"): + with self.assertWarnsRegex(RuntimeWarning, "o+"): _runtime_warn("barz") - def testSynonymAssertMethodNames(self): - """Test undocumented method name synonyms. + def testDeprecatedMethodNames(self): + """Test that the deprecated methods raise a DeprecationWarning. - Please do not use these methods names in your own code. - - This test confirms their continued existence and functionality - in order to avoid breaking existing code. - """ - self.assertNotEquals(3, 5) - self.assertEquals(3, 3) - self.assertAlmostEquals(2.0, 2.0) - self.assertNotAlmostEquals(3.0, 5.0) - self.assert_(True) - - def testPendingDeprecationMethodNames(self): - """Test fail* methods pending deprecation, they will warn in 3.2. - - Do not use these methods. They will go away in 3.3. + The fail* methods will be removed in 3.3. The assert* methods will + have to stay around for a few more versions. See #9424. """ old = ( (self.failIfEqual, (3, 5)), + (self.assertNotEquals, (3, 5)), (self.failUnlessEqual, (3, 3)), + (self.assertEquals, (3, 3)), (self.failUnlessAlmostEqual, (2.0, 2.0)), + (self.assertAlmostEquals, (2.0, 2.0)), (self.failIfAlmostEqual, (3.0, 5.0)), + (self.assertNotAlmostEquals, (3.0, 5.0)), (self.failUnless, (True,)), + (self.assert_, (True,)), (self.failUnlessRaises, (TypeError, lambda _: 3.14 + 'spam')), (self.failIf, (False,)), - (self.assertSameElements, ([1, 1, 2, 3], [1, 2, 3])) + (self.assertSameElements, ([1, 1, 2, 3], [1, 2, 3])), + (self.assertDictContainsSubset, (dict(a=1, b=2), dict(a=1, b=2, c=3))), + (self.assertRaisesRegexp, (KeyError, 'foo', lambda: {}['foo'])), + (self.assertRegexpMatches, ('bar', 'bar')), ) for meth, args in old: - with support.check_warnings(('', DeprecationWarning)) as w: + with self.assertWarns(DeprecationWarning): meth(*args) - self.assertEqual(len(w.warnings), 1) + + def testDeprecatedFailMethods(self): + """Test that the deprecated fail* methods get removed in 3.3""" + if sys.version_info[:2] < (3, 3): + return + deprecated_names = [ + 'failIfEqual', 'failUnlessEqual', 'failUnlessAlmostEqual', + 'failIfAlmostEqual', 'failUnless', 'failUnlessRaises', 'failIf', + 'assertSameElements', 'assertDictContainsSubset', + ] + for deprecated_name in deprecated_names: + with self.assertRaises(AttributeError): + getattr(self, deprecated_name) # remove these in 3.3 def testDeepcopy(self): # Issue: 5660 @@ -1113,3 +1142,82 @@ # exercise the TestCase instance in a way that will invoke # the type equality lookup mechanism unpickled_test.assertEqual(set(), set()) + + def testKeyboardInterrupt(self): + def _raise(self=None): + raise KeyboardInterrupt + def nothing(self): + pass + + class Test1(unittest.TestCase): + test_something = _raise + + class Test2(unittest.TestCase): + setUp = _raise + test_something = nothing + + class Test3(unittest.TestCase): + test_something = nothing + tearDown = _raise + + class Test4(unittest.TestCase): + def test_something(self): + self.addCleanup(_raise) + + for klass in (Test1, Test2, Test3, Test4): + with self.assertRaises(KeyboardInterrupt): + klass('test_something').run() + + def testSkippingEverywhere(self): + def _skip(self=None): + raise unittest.SkipTest('some reason') + def nothing(self): + pass + + class Test1(unittest.TestCase): + test_something = _skip + + class Test2(unittest.TestCase): + setUp = _skip + test_something = nothing + + class Test3(unittest.TestCase): + test_something = nothing + tearDown = _skip + + class Test4(unittest.TestCase): + def test_something(self): + self.addCleanup(_skip) + + for klass in (Test1, Test2, Test3, Test4): + result = unittest.TestResult() + klass('test_something').run(result) + self.assertEqual(len(result.skipped), 1) + self.assertEqual(result.testsRun, 1) + + def testSystemExit(self): + def _raise(self=None): + raise SystemExit + def nothing(self): + pass + + class Test1(unittest.TestCase): + test_something = _raise + + class Test2(unittest.TestCase): + setUp = _raise + test_something = nothing + + class Test3(unittest.TestCase): + test_something = nothing + tearDown = _raise + + class Test4(unittest.TestCase): + def test_something(self): + self.addCleanup(_raise) + + for klass in (Test1, Test2, Test3, Test4): + result = unittest.TestResult() + klass('test_something').run(result) + self.assertEqual(len(result.errors), 1) + self.assertEqual(result.testsRun, 1) Modified: python/branches/py3k-cdecimal/Lib/unittest/test/test_discovery.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/test/test_discovery.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/test/test_discovery.py Sun Jan 2 13:18:37 2011 @@ -231,6 +231,19 @@ program.parseArgs(['something']) self.assertTrue(self.called) + def test_command_line_handling_discover_by_default_with_options(self): + program = TestableTestProgram() + program.module = None + + args = ['something', '-v', '-b', '-v', '-c', '-f'] + self.called = False + def do_discovery(argv): + self.called = True + self.assertEqual(argv, args[1:]) + program._do_discovery = do_discovery + program.parseArgs(args) + self.assertTrue(self.called) + def test_command_line_handling_do_discovery_too_many_arguments(self): class Stop(Exception): @@ -354,7 +367,7 @@ expected_dir = os.path.abspath('foo') msg = re.escape(r"'foo' module incorrectly imported from %r. Expected %r. " "Is this module globally installed?" % (mod_dir, expected_dir)) - self.assertRaisesRegexp( + self.assertRaisesRegex( ImportError, '^%s$' % msg, loader.discover, start_dir='foo', pattern='foo.py' ) Modified: python/branches/py3k-cdecimal/Lib/unittest/test/test_functiontestcase.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/test/test_functiontestcase.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/test/test_functiontestcase.py Sun Jan 2 13:18:37 2011 @@ -58,8 +58,8 @@ def tearDown(): events.append('tearDown') - expected = ['startTest', 'setUp', 'test', 'addError', 'tearDown', - 'stopTest'] + expected = ['startTest', 'setUp', 'test', 'tearDown', + 'addError', 'stopTest'] unittest.FunctionTestCase(test, setUp, tearDown).run(result) self.assertEqual(events, expected) @@ -84,8 +84,8 @@ def tearDown(): events.append('tearDown') - expected = ['startTest', 'setUp', 'test', 'addFailure', 'tearDown', - 'stopTest'] + expected = ['startTest', 'setUp', 'test', 'tearDown', + 'addFailure', 'stopTest'] unittest.FunctionTestCase(test, setUp, tearDown).run(result) self.assertEqual(events, expected) Modified: python/branches/py3k-cdecimal/Lib/unittest/test/test_loader.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/test/test_loader.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/test/test_loader.py Sun Jan 2 13:18:37 2011 @@ -186,7 +186,7 @@ self.assertEqual(suite.countTestCases(), 1) test = list(suite)[0] - self.assertRaisesRegexp(TypeError, "some failure", test.m) + self.assertRaisesRegex(TypeError, "some failure", test.m) ################################################################ ### /Tests for TestLoader.loadTestsFromModule() Modified: python/branches/py3k-cdecimal/Lib/unittest/test/test_program.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/test/test_program.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/test/test_program.py Sun Jan 2 13:18:37 2011 @@ -99,6 +99,7 @@ defaultTest = None testRunner = None testLoader = unittest.defaultTestLoader + module = '__main__' progName = 'test' test = 'test' def __init__(self, *args): @@ -182,6 +183,27 @@ program.parseArgs([None, opt]) self.assertEqual(getattr(program, attr), not_none) + def testWarning(self): + """Test the warnings argument""" + # see #10535 + class FakeTP(unittest.TestProgram): + def parseArgs(self, *args, **kw): pass + def runTests(self, *args, **kw): pass + warnoptions = sys.warnoptions + try: + sys.warnoptions[:] = [] + # no warn options, no arg -> default + self.assertEqual(FakeTP().warnings, 'default') + # no warn options, w/ arg -> arg value + self.assertEqual(FakeTP(warnings='ignore').warnings, 'ignore') + sys.warnoptions[:] = ['somevalue'] + # warn options, no arg -> None + # warn options, w/ arg -> arg value + self.assertEqual(FakeTP().warnings, None) + self.assertEqual(FakeTP(warnings='ignore').warnings, 'ignore') + finally: + sys.warnoptions[:] = warnoptions + def testRunTestsRunnerClass(self): program = self.program @@ -189,12 +211,14 @@ program.verbosity = 'verbosity' program.failfast = 'failfast' program.buffer = 'buffer' + program.warnings = 'warnings' program.runTests() self.assertEqual(FakeRunner.initArgs, {'verbosity': 'verbosity', 'failfast': 'failfast', - 'buffer': 'buffer'}) + 'buffer': 'buffer', + 'warnings': 'warnings'}) self.assertEqual(FakeRunner.test, 'test') self.assertIs(program.result, RESULT) @@ -250,6 +274,85 @@ program.runTests() self.assertTrue(self.installed) + def _patch_isfile(self, names, exists=True): + def isfile(path): + return path in names + original = os.path.isfile + os.path.isfile = isfile + def restore(): + os.path.isfile = original + self.addCleanup(restore) + + + def testParseArgsFileNames(self): + # running tests with filenames instead of module names + program = self.program + argv = ['progname', 'foo.py', 'bar.Py', 'baz.PY', 'wing.txt'] + self._patch_isfile(argv) + + program.createTests = lambda: None + program.parseArgs(argv) + + # note that 'wing.txt' is not a Python file so the name should + # *not* be converted to a module name + expected = ['foo', 'bar', 'baz', 'wing.txt'] + self.assertEqual(program.testNames, expected) + + + def testParseArgsFilePaths(self): + program = self.program + argv = ['progname', 'foo/bar/baz.py', 'green\\red.py'] + self._patch_isfile(argv) + + program.createTests = lambda: None + program.parseArgs(argv) + + expected = ['foo.bar.baz', 'green.red'] + self.assertEqual(program.testNames, expected) + + + def testParseArgsNonExistentFiles(self): + program = self.program + argv = ['progname', 'foo/bar/baz.py', 'green\\red.py'] + self._patch_isfile([]) + + program.createTests = lambda: None + program.parseArgs(argv) + + self.assertEqual(program.testNames, argv[1:]) + + def testParseArgsAbsolutePathsThatCanBeConverted(self): + cur_dir = os.getcwd() + program = self.program + def _join(name): + return os.path.join(cur_dir, name) + argv = ['progname', _join('foo/bar/baz.py'), _join('green\\red.py')] + self._patch_isfile(argv) + + program.createTests = lambda: None + program.parseArgs(argv) + + expected = ['foo.bar.baz', 'green.red'] + self.assertEqual(program.testNames, expected) + + def testParseArgsAbsolutePathsThatCannotBeConverted(self): + program = self.program + # even on Windows '/...' is considered absolute by os.path.abspath + argv = ['progname', '/foo/bar/baz.py', '/green/red.py'] + self._patch_isfile(argv) + + program.createTests = lambda: None + program.parseArgs(argv) + + self.assertEqual(program.testNames, argv[1:]) + + # it may be better to use platform specific functions to normalise paths + # rather than accepting '.PY' and '\' as file seprator on Linux / Mac + # it would also be better to check that a filename is a valid module + # identifier (we have a regex for this in loader.py) + # for invalid filenames should we raise a useful error rather than + # leaving the current error message (import of filename fails) in place? + if __name__ == '__main__': unittest.main() Modified: python/branches/py3k-cdecimal/Lib/unittest/test/test_runner.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/test/test_runner.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/test/test_runner.py Sun Jan 2 13:18:37 2011 @@ -1,5 +1,8 @@ import io +import os +import sys import pickle +import subprocess import unittest @@ -31,9 +34,7 @@ [(cleanup1, (1, 2, 3), dict(four='hello', five='goodbye')), (cleanup2, (), {})]) - result = test.doCleanups() - self.assertTrue(result) - + self.assertTrue(test.doCleanups()) self.assertEqual(cleanups, [(2, (), {}), (1, (1, 2, 3), dict(four='hello', five='goodbye'))]) def testCleanUpWithErrors(self): @@ -41,14 +42,12 @@ def testNothing(self): pass - class MockResult(object): + class MockOutcome(object): + success = True errors = [] - def addError(self, test, exc_info): - self.errors.append((test, exc_info)) - result = MockResult() test = TestableTest('testNothing') - test._resultForDoCleanups = result + test._outcomeForDoCleanups = MockOutcome exc1 = Exception('foo') exc2 = Exception('bar') @@ -62,10 +61,11 @@ test.addCleanup(cleanup2) self.assertFalse(test.doCleanups()) + self.assertFalse(MockOutcome.success) - (test1, (Type1, instance1, _)), (test2, (Type2, instance2, _)) = reversed(MockResult.errors) - self.assertEqual((test1, Type1, instance1), (test, Exception, exc1)) - self.assertEqual((test2, Type2, instance2), (test, Exception, exc2)) + (Type1, instance1, _), (Type2, instance2, _) = reversed(MockOutcome.errors) + self.assertEqual((Type1, instance1), (Exception, exc1)) + self.assertEqual((Type2, instance2), (Exception, exc2)) def testCleanupInRun(self): blowUp = False @@ -144,6 +144,7 @@ self.assertFalse(runner.failfast) self.assertFalse(runner.buffer) self.assertEqual(runner.verbosity, 1) + self.assertEqual(runner.warnings, None) self.assertTrue(runner.descriptions) self.assertEqual(runner.resultclass, unittest.TextTestResult) @@ -244,3 +245,74 @@ expectedresult = (runner.stream, DESCRIPTIONS, VERBOSITY) self.assertEqual(runner._makeResult(), expectedresult) + + def test_warnings(self): + """ + Check that warnings argument of TextTestRunner correctly affects the + behavior of the warnings. + """ + # see #10535 and the _test_warnings file for more information + + def get_parse_out_err(p): + return [b.splitlines() for b in p.communicate()] + opts = dict(stdout=subprocess.PIPE, stderr=subprocess.PIPE, + cwd=os.path.dirname(__file__)) + ae_msg = b'Please use assertEqual instead.' + at_msg = b'Please use assertTrue instead.' + + # no args -> all the warnings are printed, unittest warnings only once + p = subprocess.Popen([sys.executable, '_test_warnings.py'], **opts) + out, err = get_parse_out_err(p) + self.assertIn(b'OK', err) + # check that the total number of warnings in the output is correct + self.assertEqual(len(out), 12) + # check that the numbers of the different kind of warnings is correct + for msg in [b'dw', b'iw', b'uw']: + self.assertEqual(out.count(msg), 3) + for msg in [ae_msg, at_msg, b'rw']: + self.assertEqual(out.count(msg), 1) + + args_list = ( + # passing 'ignore' as warnings arg -> no warnings + [sys.executable, '_test_warnings.py', 'ignore'], + # -W doesn't affect the result if the arg is passed + [sys.executable, '-Wa', '_test_warnings.py', 'ignore'], + # -W affects the result if the arg is not passed + [sys.executable, '-Wi', '_test_warnings.py'] + ) + # in all these cases no warnings are printed + for args in args_list: + p = subprocess.Popen(args, **opts) + out, err = get_parse_out_err(p) + self.assertIn(b'OK', err) + self.assertEqual(len(out), 0) + + + # passing 'always' as warnings arg -> all the warnings printed, + # unittest warnings only once + p = subprocess.Popen([sys.executable, '_test_warnings.py', 'always'], + **opts) + out, err = get_parse_out_err(p) + self.assertIn(b'OK', err) + self.assertEqual(len(out), 14) + for msg in [b'dw', b'iw', b'uw', b'rw']: + self.assertEqual(out.count(msg), 3) + for msg in [ae_msg, at_msg]: + self.assertEqual(out.count(msg), 1) + + def testStdErrLookedUpAtInstantiationTime(self): + # see issue 10786 + old_stderr = sys.stderr + f = io.StringIO() + sys.stderr = f + try: + runner = unittest.TextTestRunner() + self.assertTrue(runner.stream.stream is f) + finally: + sys.stderr = old_stderr + + def testSpecifiedStreamUsed(self): + # see issue 10786 + f = io.StringIO() + runner = unittest.TextTestRunner(f) + self.assertTrue(runner.stream.stream is f) Modified: python/branches/py3k-cdecimal/Lib/unittest/test/test_setups.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/test/test_setups.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/test/test_setups.py Sun Jan 2 13:18:37 2011 @@ -500,7 +500,7 @@ messages = ('setUpModule', 'tearDownModule', 'setUpClass', 'tearDownClass', 'test_something') for phase, msg in enumerate(messages): - with self.assertRaisesRegexp(Exception, msg): + with self.assertRaisesRegex(Exception, msg): suite.debug() if __name__ == '__main__': Modified: python/branches/py3k-cdecimal/Lib/unittest/test/test_suite.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/test/test_suite.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/test/test_suite.py Sun Jan 2 13:18:37 2011 @@ -353,11 +353,16 @@ unittest.TestSuite.__call__(self, *args, **kw) suite = MySuite() + result = unittest.TestResult() wrapper = unittest.TestSuite() wrapper.addTest(suite) - wrapper(unittest.TestResult()) + wrapper(result) self.assertTrue(suite.called) + # reusing results should be permitted even if abominable + self.assertFalse(result._testRunEntered) + + if __name__ == '__main__': unittest.main() Modified: python/branches/py3k-cdecimal/Lib/unittest/util.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/unittest/util.py (original) +++ python/branches/py3k-cdecimal/Lib/unittest/util.py Sun Jan 2 13:18:37 2011 @@ -1,5 +1,7 @@ """Various utility functions.""" +from collections import namedtuple, OrderedDict + __unittest = True _MAX_LENGTH = 80 @@ -12,7 +14,6 @@ return result return result[:_MAX_LENGTH] + ' [truncated]...' - def strclass(cls): return "%s.%s" % (cls.__module__, cls.__name__) @@ -77,3 +78,63 @@ def three_way_cmp(x, y): """Return -1 if x < y, 0 if x == y and 1 if x > y""" return (x > y) - (x < y) + +_Mismatch = namedtuple('Mismatch', 'actual expected value') + +def _count_diff_all_purpose(actual, expected): + 'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ' + # elements need not be hashable + s, t = list(actual), list(expected) + m, n = len(s), len(t) + NULL = object() + result = [] + for i, elem in enumerate(s): + if elem is NULL: + continue + cnt_s = cnt_t = 0 + for j in range(i, m): + if s[j] == elem: + cnt_s += 1 + s[j] = NULL + for j, other_elem in enumerate(t): + if other_elem == elem: + cnt_t += 1 + t[j] = NULL + if cnt_s != cnt_t: + diff = _Mismatch(cnt_s, cnt_t, elem) + result.append(diff) + + for i, elem in enumerate(t): + if elem is NULL: + continue + cnt_t = 0 + for j in range(i, n): + if t[j] == elem: + cnt_t += 1 + t[j] = NULL + diff = _Mismatch(0, cnt_t, elem) + result.append(diff) + return result + +def _ordered_count(iterable): + 'Return dict of element counts, in the order they were first seen' + c = OrderedDict() + for elem in iterable: + c[elem] = c.get(elem, 0) + 1 + return c + +def _count_diff_hashable(actual, expected): + 'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ' + # elements must be hashable + s, t = _ordered_count(actual), _ordered_count(expected) + result = [] + for elem, cnt_s in s.items(): + cnt_t = t.get(elem, 0) + if cnt_s != cnt_t: + diff = _Mismatch(cnt_s, cnt_t, elem) + result.append(diff) + for elem, cnt_t in t.items(): + if elem not in s: + diff = _Mismatch(0, cnt_t, elem) + result.append(diff) + return result Modified: python/branches/py3k-cdecimal/Lib/urllib/parse.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/urllib/parse.py (original) +++ python/branches/py3k-cdecimal/Lib/urllib/parse.py Sun Jan 2 13:18:37 2011 @@ -11,7 +11,7 @@ RFC 2396: "Uniform Resource Identifiers (URI)": Generic Syntax by T. Berners-Lee, R. Fielding, and L. Masinter, August 1998. -RFC 2368: "The mailto URL scheme", by P.Hoffman , L Masinter, J. Zwinski, July 1998. +RFC 2368: "The mailto URL scheme", by P.Hoffman , L Masinter, J. Zawinski, July 1998. RFC 1808: "Relative Uniform Resource Locators", by R. Fielding, UC Irvine, June 1995. @@ -60,6 +60,7 @@ '0123456789' '+-.') +# XXX: Consider replacing with functools.lru_cache MAX_CACHE_SIZE = 20 _parse_cache = {} @@ -69,66 +70,210 @@ _safe_quoters.clear() -class ResultMixin(object): - """Shared methods for the parsed result objects.""" +# Helpers for bytes handling +# For 3.2, we deliberately require applications that +# handle improperly quoted URLs to do their own +# decoding and encoding. If valid use cases are +# presented, we may relax this by using latin-1 +# decoding internally for 3.3 +_implicit_encoding = 'ascii' +_implicit_errors = 'strict' + +def _noop(obj): + return obj + +def _encode_result(obj, encoding=_implicit_encoding, + errors=_implicit_errors): + return obj.encode(encoding, errors) + +def _decode_args(args, encoding=_implicit_encoding, + errors=_implicit_errors): + return tuple(x.decode(encoding, errors) if x else '' for x in args) + +def _coerce_args(*args): + # Invokes decode if necessary to create str args + # and returns the coerced inputs along with + # an appropriate result coercion function + # - noop for str inputs + # - encoding function otherwise + str_input = isinstance(args[0], str) + for arg in args[1:]: + # We special-case the empty string to support the + # "scheme=''" default argument to some functions + if arg and isinstance(arg, str) != str_input: + raise TypeError("Cannot mix str and non-str arguments") + if str_input: + return args + (_noop,) + return _decode_args(args) + (_encode_result,) + +# Result objects are more helpful than simple tuples +class _ResultMixinStr(object): + """Standard approach to encoding parsed results from str to bytes""" + __slots__ = () + + def encode(self, encoding='ascii', errors='strict'): + return self._encoded_counterpart(*(x.encode(encoding, errors) for x in self)) + + +class _ResultMixinBytes(object): + """Standard approach to decoding parsed results from bytes to str""" + __slots__ = () + + def decode(self, encoding='ascii', errors='strict'): + return self._decoded_counterpart(*(x.decode(encoding, errors) for x in self)) + + +class _NetlocResultMixinBase(object): + """Shared methods for the parsed result objects containing a netloc element""" + __slots__ = () @property def username(self): - netloc = self.netloc - if "@" in netloc: - userinfo = netloc.rsplit("@", 1)[0] - if ":" in userinfo: - userinfo = userinfo.split(":", 1)[0] - return userinfo - return None + return self._userinfo[0] @property def password(self): - netloc = self.netloc - if "@" in netloc: - userinfo = netloc.rsplit("@", 1)[0] - if ":" in userinfo: - return userinfo.split(":", 1)[1] - return None + return self._userinfo[1] @property def hostname(self): - netloc = self.netloc.split('@')[-1] - if '[' in netloc and ']' in netloc: - return netloc.split(']')[0][1:].lower() - elif ':' in netloc: - return netloc.split(':')[0].lower() - elif netloc == '': - return None - else: - return netloc.lower() + hostname = self._hostinfo[0] + if not hostname: + hostname = None + elif hostname is not None: + hostname = hostname.lower() + return hostname @property def port(self): - netloc = self.netloc.split('@')[-1].split(']')[-1] - if ':' in netloc: - port = netloc.split(':')[1] - return int(port, 10) + port = self._hostinfo[1] + if port is not None: + port = int(port, 10) + return port + + +class _NetlocResultMixinStr(_NetlocResultMixinBase, _ResultMixinStr): + __slots__ = () + + @property + def _userinfo(self): + netloc = self.netloc + userinfo, have_info, hostinfo = netloc.rpartition('@') + if have_info: + username, have_password, password = userinfo.partition(':') + if not have_password: + password = None else: - return None + username = password = None + return username, password + + @property + def _hostinfo(self): + netloc = self.netloc + _, _, hostinfo = netloc.rpartition('@') + _, have_open_br, bracketed = hostinfo.partition('[') + if have_open_br: + hostname, _, port = bracketed.partition(']') + _, have_port, port = port.partition(':') + else: + hostname, have_port, port = hostinfo.partition(':') + if not have_port: + port = None + return hostname, port + + +class _NetlocResultMixinBytes(_NetlocResultMixinBase, _ResultMixinBytes): + __slots__ = () + + @property + def _userinfo(self): + netloc = self.netloc + userinfo, have_info, hostinfo = netloc.rpartition(b'@') + if have_info: + username, have_password, password = userinfo.partition(b':') + if not have_password: + password = None + else: + username = password = None + return username, password + + @property + def _hostinfo(self): + netloc = self.netloc + _, _, hostinfo = netloc.rpartition(b'@') + _, have_open_br, bracketed = hostinfo.partition(b'[') + if have_open_br: + hostname, _, port = bracketed.partition(b']') + _, have_port, port = port.partition(b':') + else: + hostname, have_port, port = hostinfo.partition(b':') + if not have_port: + port = None + return hostname, port + from collections import namedtuple -class SplitResult(namedtuple('SplitResult', 'scheme netloc path query fragment'), ResultMixin): +_DefragResultBase = namedtuple('DefragResult', 'url fragment') +_SplitResultBase = namedtuple('SplitResult', 'scheme netloc path query fragment') +_ParseResultBase = namedtuple('ParseResult', 'scheme netloc path params query fragment') + +# For backwards compatibility, alias _NetlocResultMixinStr +# ResultBase is no longer part of the documented API, but it is +# retained since deprecating it isn't worth the hassle +ResultBase = _NetlocResultMixinStr +# Structured result objects for string data +class DefragResult(_DefragResultBase, _ResultMixinStr): __slots__ = () + def geturl(self): + if self.fragment: + return self.url + '#' + self.fragment + else: + return self.url +class SplitResult(_SplitResultBase, _NetlocResultMixinStr): + __slots__ = () def geturl(self): return urlunsplit(self) +class ParseResult(_ParseResultBase, _NetlocResultMixinStr): + __slots__ = () + def geturl(self): + return urlunparse(self) -class ParseResult(namedtuple('ParseResult', 'scheme netloc path params query fragment'), ResultMixin): +# Structured result objects for bytes data +class DefragResultBytes(_DefragResultBase, _ResultMixinBytes): + __slots__ = () + def geturl(self): + if self.fragment: + return self.url + b'#' + self.fragment + else: + return self.url +class SplitResultBytes(_SplitResultBase, _NetlocResultMixinBytes): __slots__ = () + def geturl(self): + return urlunsplit(self) +class ParseResultBytes(_ParseResultBase, _NetlocResultMixinBytes): + __slots__ = () def geturl(self): return urlunparse(self) +# Set up the encode/decode result pairs +def _fix_result_transcoding(): + _result_pairs = ( + (DefragResult, DefragResultBytes), + (SplitResult, SplitResultBytes), + (ParseResult, ParseResultBytes), + ) + for _decoded, _encoded in _result_pairs: + _decoded._encoded_counterpart = _encoded + _encoded._decoded_counterpart = _decoded + +_fix_result_transcoding() +del _fix_result_transcoding def urlparse(url, scheme='', allow_fragments=True): """Parse a URL into 6 components: @@ -136,13 +281,15 @@ Return a 6-tuple: (scheme, netloc, path, params, query, fragment). Note that we don't break the components up in smaller bits (e.g. netloc is a single string) and we don't expand % escapes.""" + url, scheme, _coerce_result = _coerce_args(url, scheme) tuple = urlsplit(url, scheme, allow_fragments) scheme, netloc, url, query, fragment = tuple if scheme in uses_params and ';' in url: url, params = _splitparams(url) else: params = '' - return ParseResult(scheme, netloc, url, params, query, fragment) + result = ParseResult(scheme, netloc, url, params, query, fragment) + return _coerce_result(result) def _splitparams(url): if '/' in url: @@ -167,11 +314,12 @@ Return a 5-tuple: (scheme, netloc, path, query, fragment). Note that we don't break the components up in smaller bits (e.g. netloc is a single string) and we don't expand % escapes.""" + url, scheme, _coerce_result = _coerce_args(url, scheme) allow_fragments = bool(allow_fragments) key = url, scheme, allow_fragments, type(url), type(scheme) cached = _parse_cache.get(key, None) if cached: - return cached + return _coerce_result(cached) if len(_parse_cache) >= MAX_CACHE_SIZE: # avoid runaway growth clear_cache() netloc = query = fragment = '' @@ -191,7 +339,7 @@ url, query = url.split('?', 1) v = SplitResult(scheme, netloc, url, query, fragment) _parse_cache[key] = v - return v + return _coerce_result(v) if url.endswith(':') or not url[i+1].isdigit(): for c in url[:i]: if c not in scheme_chars: @@ -209,17 +357,18 @@ url, query = url.split('?', 1) v = SplitResult(scheme, netloc, url, query, fragment) _parse_cache[key] = v - return v + return _coerce_result(v) def urlunparse(components): """Put a parsed URL back together again. This may result in a slightly different, but equivalent URL, if the URL that was parsed originally had redundant delimiters, e.g. a ? with an empty query (the draft states that these are equivalent).""" - scheme, netloc, url, params, query, fragment = components + scheme, netloc, url, params, query, fragment, _coerce_result = ( + _coerce_args(*components)) if params: url = "%s;%s" % (url, params) - return urlunsplit((scheme, netloc, url, query, fragment)) + return _coerce_result(urlunsplit((scheme, netloc, url, query, fragment))) def urlunsplit(components): """Combine the elements of a tuple as returned by urlsplit() into a @@ -227,7 +376,8 @@ This may result in a slightly different, but equivalent URL, if the URL that was parsed originally had unnecessary delimiters (for example, a ? with an empty query; the RFC states that these are equivalent).""" - scheme, netloc, url, query, fragment = components + scheme, netloc, url, query, fragment, _coerce_result = ( + _coerce_args(*components)) if netloc or (scheme and scheme in uses_netloc and url[:2] != '//'): if url and url[:1] != '/': url = '/' + url url = '//' + (netloc or '') + url @@ -237,7 +387,7 @@ url = url + '?' + query if fragment: url = url + '#' + fragment - return url + return _coerce_result(url) def urljoin(base, url, allow_fragments=True): """Join a base URL and a possibly relative URL to form an absolute @@ -246,32 +396,28 @@ return url if not url: return base + base, url, _coerce_result = _coerce_args(base, url) bscheme, bnetloc, bpath, bparams, bquery, bfragment = \ urlparse(base, '', allow_fragments) scheme, netloc, path, params, query, fragment = \ urlparse(url, bscheme, allow_fragments) if scheme != bscheme or scheme not in uses_relative: - return url + return _coerce_result(url) if scheme in uses_netloc: if netloc: - return urlunparse((scheme, netloc, path, - params, query, fragment)) + return _coerce_result(urlunparse((scheme, netloc, path, + params, query, fragment))) netloc = bnetloc if path[:1] == '/': - return urlunparse((scheme, netloc, path, - params, query, fragment)) - if not path: + return _coerce_result(urlunparse((scheme, netloc, path, + params, query, fragment))) + if not path and not params: path = bpath - if not params: - params = bparams - else: - path = path[:-1] - return urlunparse((scheme, netloc, path, - params, query, fragment)) + params = bparams if not query: query = bquery - return urlunparse((scheme, netloc, path, - params, query, fragment)) + return _coerce_result(urlunparse((scheme, netloc, path, + params, query, fragment))) segments = bpath.split('/')[:-1] + path.split('/') # XXX The stuff below is bogus in various ways... if segments[-1] == '.': @@ -293,8 +439,8 @@ segments[-1] = '' elif len(segments) >= 2 and segments[-1] == '..': segments[-2:] = [''] - return urlunparse((scheme, netloc, '/'.join(segments), - params, query, fragment)) + return _coerce_result(urlunparse((scheme, netloc, '/'.join(segments), + params, query, fragment))) def urldefrag(url): """Removes any existing fragment from URL. @@ -303,12 +449,14 @@ the URL contained no fragments, the second element is the empty string. """ + url, _coerce_result = _coerce_args(url) if '#' in url: s, n, p, a, q, frag = urlparse(url) defrag = urlunparse((s, n, p, a, q, '')) - return defrag, frag else: - return url, '' + frag = '' + defrag = url + return _coerce_result(DefragResult(defrag, frag)) def unquote_to_bytes(string): """unquote_to_bytes('abc%20def') -> b'abc def'.""" @@ -420,6 +568,7 @@ Returns a list, as G-d intended. """ + qs, _coerce_result = _coerce_args(qs) pairs = [s2 for s1 in qs.split('&') for s2 in s1.split(';')] r = [] for name_value in pairs: @@ -435,10 +584,9 @@ else: continue if len(nv[1]) or keep_blank_values: - name = unquote(nv[0].replace('+', ' ')) - value = unquote(nv[1].replace('+', ' ')) + name = _coerce_result(unquote(nv[0].replace('+', ' '))) + value = _coerce_result(unquote(nv[1].replace('+', ' '))) r.append((name, value)) - return r def unquote_plus(string, encoding='utf-8', errors='replace'): Modified: python/branches/py3k-cdecimal/Lib/urllib/request.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/urllib/request.py (original) +++ python/branches/py3k-cdecimal/Lib/urllib/request.py Sun Jan 2 13:18:37 2011 @@ -94,6 +94,7 @@ import socket import sys import time +import collections from urllib.error import URLError, HTTPError, ContentTooShortError from urllib.parse import ( @@ -274,8 +275,9 @@ def __init__(self): client_version = "Python-urllib/%s" % __version__ self.addheaders = [('User-agent', client_version)] - # manage the individual handlers + # self.handlers is retained only for backward compatibility self.handlers = [] + # manage the individual handlers self.handle_open = {} self.handle_error = {} self.process_response = {} @@ -325,8 +327,6 @@ added = True if added: - # the handlers must work in an specific order, the order - # is specified in a Handler attribute bisect.insort(self.handlers, handler) handler.add_parent(self) @@ -1053,8 +1053,16 @@ 'Content-type', 'application/x-www-form-urlencoded') if not request.has_header('Content-length'): - request.add_unredirected_header( - 'Content-length', '%d' % len(data)) + try: + mv = memoryview(data) + except TypeError: + if isinstance(data, collections.Iterable): + raise ValueError("Content-Length should be specified \ + for iterable data of type %r %r" % (type(data), + data)) + else: + request.add_unredirected_header( + 'Content-length', '%d' % (len(mv) * mv.itemsize)) sel_host = host if request.has_proxy(): Modified: python/branches/py3k-cdecimal/Lib/wave.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/wave.py (original) +++ python/branches/py3k-cdecimal/Lib/wave.py Sun Jan 2 13:18:37 2011 @@ -467,11 +467,11 @@ self._datalength = self._nframes * self._nchannels * self._sampwidth self._form_length_pos = self._file.tell() self._file.write(struct.pack('' % (self.text,) def __hash__(self): return hash(self.text) def __le__(self, other): @@ -1066,7 +1068,7 @@ def register_namespace(prefix, uri): if re.match("ns\d+$", prefix): raise ValueError("Prefix format reserved for internal use") - for k, v in _namespace_map.items(): + for k, v in list(_namespace_map.items()): if k == uri or v == prefix: del _namespace_map[k] _namespace_map[uri] = prefix Modified: python/branches/py3k-cdecimal/Lib/xmlrpc/client.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/xmlrpc/client.py (original) +++ python/branches/py3k-cdecimal/Lib/xmlrpc/client.py Sun Jan 2 13:18:37 2011 @@ -1297,8 +1297,12 @@ def parse_response(self, response): # read response data from httpresponse, and parse it - if response.getheader("Content-Encoding", "") == "gzip": - stream = GzipDecodedResponse(response) + # Check for new http response object, otherwise it is a file object. + if hasattr(response, 'getheader'): + if response.getheader("Content-Encoding", "") == "gzip": + stream = GzipDecodedResponse(response) + else: + stream = response else: stream = response Modified: python/branches/py3k-cdecimal/Lib/zipfile.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/zipfile.py (original) +++ python/branches/py3k-cdecimal/Lib/zipfile.py Sun Jan 2 13:18:37 2011 @@ -473,9 +473,11 @@ # Search for universal newlines or line chunks. PATTERN = re.compile(br'^(?P[^\r\n]+)|(?P\n|\r\n?)') - def __init__(self, fileobj, mode, zipinfo, decrypter=None): + def __init__(self, fileobj, mode, zipinfo, decrypter=None, + close_fileobj=False): self._fileobj = fileobj self._decrypter = decrypter + self._close_fileobj = close_fileobj self._compress_type = zipinfo.compress_type self._compress_size = zipinfo.compress_size @@ -647,6 +649,12 @@ self._offset += len(data) return data + def close(self): + try: + if self._close_fileobj: + self._fileobj.close() + finally: + super().close() class ZipFile: @@ -869,8 +877,12 @@ def setpassword(self, pwd): """Set default password for encrypted files.""" - assert isinstance(pwd, bytes) - self.pwd = pwd + if pwd and not isinstance(pwd, bytes): + raise TypeError("pwd: expected bytes, got %s" % type(pwd)) + if pwd: + self.pwd = pwd + else: + self.pwd = None def read(self, name, pwd=None): """Return file bytes (as a string) for name.""" @@ -881,6 +893,8 @@ """Return file-like object for 'name'.""" if mode not in ("r", "U", "rU"): raise RuntimeError('open() requires mode "r", "U", or "rU"') + if pwd and not isinstance(pwd, bytes): + raise TypeError("pwd: expected bytes, got %s" % type(pwd)) if not self.fp: raise RuntimeError( "Attempt to read ZIP archive that was already closed") @@ -898,8 +912,12 @@ zinfo = name else: # Get info object for name - zinfo = self.getinfo(name) - + try: + zinfo = self.getinfo(name) + except KeyError: + if not self._filePassed: + zef_file.close() + raise zef_file.seek(zinfo.header_offset, 0) # Skip the file header: @@ -912,7 +930,15 @@ if fheader[_FH_EXTRA_FIELD_LENGTH]: zef_file.read(fheader[_FH_EXTRA_FIELD_LENGTH]) - if fname != zinfo.orig_filename.encode("utf-8"): + if zinfo.flag_bits & 0x800: + # UTF-8 filename + fname_str = fname.decode("utf-8") + else: + fname_str = fname.decode("cp437") + + if fname_str != zinfo.orig_filename: + if not self._filePassed: + zef_file.close() raise BadZipFile( 'File name in directory %r and header %r differ.' % (zinfo.orig_filename, fname)) @@ -924,6 +950,8 @@ if not pwd: pwd = self.pwd if not pwd: + if not self._filePassed: + zef_file.close() raise RuntimeError("File %s is encrypted, " "password required for extraction" % name) @@ -933,8 +961,8 @@ # completely random, while the 12th contains the MSB of the CRC, # or the MSB of the file time depending on the header type # and is used to check the correctness of the password. - bytes = zef_file.read(12) - h = list(map(zd, bytes[0:12])) + header = zef_file.read(12) + h = list(map(zd, header[0:12])) if zinfo.flag_bits & 0x8: # compare against the file type from extended local headers check_byte = (zinfo._raw_time >> 8) & 0xff @@ -942,9 +970,12 @@ # compare against the CRC otherwise check_byte = (zinfo.CRC >> 24) & 0xff if h[11] != check_byte: + if not self._filePassed: + zef_file.close() raise RuntimeError("Bad password for file", name) - return ZipExtFile(zef_file, mode, zinfo, zd) + return ZipExtFile(zef_file, mode, zinfo, zd, + close_fileobj=not self._filePassed) def extract(self, member, path=None, pwd=None): """Extract a member from the archive to the current working directory, @@ -1276,6 +1307,12 @@ class PyZipFile(ZipFile): """Class to create ZIP archives with Python library files and packages.""" + def __init__(self, file, mode="r", compression=ZIP_STORED, + allowZip64=False, optimize=-1): + ZipFile.__init__(self, file, mode=mode, compression=compression, + allowZip64=allowZip64) + self._optimize = optimize + def writepy(self, pathname, basename=""): """Add all files from "pathname" to the ZIP archive. @@ -1348,44 +1385,63 @@ archive name, compiling if necessary. For example, given /python/lib/string, return (/python/lib/string.pyc, string). """ + def _compile(file, optimize=-1): + import py_compile + if self.debug: + print("Compiling", file) + try: + py_compile.compile(file, doraise=True, optimize=optimize) + except py_compile.PyCompileError as error: + print(err.msg) + return False + return True + file_py = pathname + ".py" file_pyc = pathname + ".pyc" file_pyo = pathname + ".pyo" pycache_pyc = imp.cache_from_source(file_py, True) pycache_pyo = imp.cache_from_source(file_py, False) - if (os.path.isfile(file_pyo) and - os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime): - # Use .pyo file. - arcname = fname = file_pyo - elif (os.path.isfile(file_pyc) and - os.stat(file_pyc).st_mtime >= os.stat(file_py).st_mtime): - # Use .pyc file. - arcname = fname = file_pyc - elif (os.path.isfile(pycache_pyc) and - os.stat(pycache_pyc).st_mtime >= os.stat(file_py).st_mtime): - # Use the __pycache__/*.pyc file, but write it to the legacy pyc - # file name in the archive. - fname = pycache_pyc - arcname = file_pyc - elif (os.path.isfile(pycache_pyo) and - os.stat(pycache_pyo).st_mtime >= os.stat(file_py).st_mtime): - # Use the __pycache__/*.pyo file, but write it to the legacy pyo - # file name in the archive. - fname = pycache_pyo - arcname = file_pyo + if self._optimize == -1: + # legacy mode: use whatever file is present + if (os.path.isfile(file_pyo) and + os.stat(file_pyo).st_mtime >= os.stat(file_py).st_mtime): + # Use .pyo file. + arcname = fname = file_pyo + elif (os.path.isfile(file_pyc) and + os.stat(file_pyc).st_mtime >= os.stat(file_py).st_mtime): + # Use .pyc file. + arcname = fname = file_pyc + elif (os.path.isfile(pycache_pyc) and + os.stat(pycache_pyc).st_mtime >= os.stat(file_py).st_mtime): + # Use the __pycache__/*.pyc file, but write it to the legacy pyc + # file name in the archive. + fname = pycache_pyc + arcname = file_pyc + elif (os.path.isfile(pycache_pyo) and + os.stat(pycache_pyo).st_mtime >= os.stat(file_py).st_mtime): + # Use the __pycache__/*.pyo file, but write it to the legacy pyo + # file name in the archive. + fname = pycache_pyo + arcname = file_pyo + else: + # Compile py into PEP 3147 pyc file. + if _compile(file_py): + fname = (pycache_pyc if __debug__ else pycache_pyo) + arcname = (file_pyc if __debug__ else file_pyo) + else: + fname = arcname = file_py else: - # Compile py into PEP 3147 pyc file. - import py_compile - if self.debug: - print("Compiling", file_py) - try: - py_compile.compile(file_py, doraise=True) - except py_compile.PyCompileError as error: - print(err.msg) - fname = file_py + # new mode: use given optimization level + if self._optimize == 0: + fname = pycache_pyc + arcname = file_pyc else: - fname = (pycache_pyc if __debug__ else pycache_pyo) - arcname = (file_pyc if __debug__ else file_pyo) + fname = pycache_pyo + arcname = file_pyo + if not (os.path.isfile(fname) and + os.stat(fname).st_mtime >= os.stat(file_py).st_mtime): + if not _compile(file_py, optimize=self._optimize): + fname = arcname = file_py archivename = os.path.split(arcname)[1] if basename: archivename = "%s/%s" % (basename, archivename) Modified: python/branches/py3k-cdecimal/Mac/BuildScript/build-installer.py ============================================================================== --- python/branches/py3k-cdecimal/Mac/BuildScript/build-installer.py (original) +++ python/branches/py3k-cdecimal/Mac/BuildScript/build-installer.py Sun Jan 2 13:18:37 2011 @@ -418,15 +418,16 @@ # to install a newer patch level. for framework in ['Tcl', 'Tk']: - fw = dict(lower=framework.lower(), - upper=framework.upper(), - cap=framework.capitalize()) - fwpth = "Library/Frameworks/%(cap)s.framework/%(lower)sConfig.sh" % fw - sysfw = os.path.join('/System', fwpth) + #fw = dict(lower=framework.lower(), + # upper=framework.upper(), + # cap=framework.capitalize()) + #fwpth = "Library/Frameworks/%(cap)s.framework/%(lower)sConfig.sh" % fw + fwpth = 'Library/Frameworks/Tcl.framework/Versions/Current' + sysfw = os.path.join(SDKPATH, 'System', fwpth) libfw = os.path.join('/', fwpth) usrfw = os.path.join(os.getenv('HOME'), fwpth) - version = "%(upper)s_VERSION" % fw - if getTclTkVersion(libfw, version) != getTclTkVersion(sysfw, version): + #version = "%(upper)s_VERSION" % fw + if os.readlink(libfw) != os.readlink(sysfw): fatal("Version of %s must match %s" % (libfw, sysfw) ) if os.path.exists(usrfw): fatal("Please rename %s to avoid possible dynamic load issues." @@ -825,12 +826,29 @@ os.chmod(p, stat.S_IMODE(st.st_mode) | stat.S_IWGRP) os.chown(p, -1, gid) + LDVERSION=None + VERSION=None + ABIFLAGS=None + + with open(os.path.join(buildDir, 'Makefile')) as fp: + for ln in fp: + if ln.startswith('VERSION='): + VERSION=ln.split()[1] + if ln.startswith('ABIFLAGS='): + ABIFLAGS=ln.split()[1] + + if ln.startswith('LDVERSION='): + LDVERSION=ln.split()[1] + + LDVERSION = LDVERSION.replace('$(VERSION)', VERSION) + LDVERSION = LDVERSION.replace('$(ABIFLAGS)', ABIFLAGS) + # We added some directories to the search path during the configure # phase. Remove those because those directories won't be there on # the end-users system. path =os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework', 'Versions', version, 'lib', 'python%s'%(version,), - 'config', 'Makefile') + 'config-' + LDVERSION, 'Makefile') fp = open(path, 'r') data = fp.read() fp.close() Modified: python/branches/py3k-cdecimal/Mac/Makefile.in ============================================================================== --- python/branches/py3k-cdecimal/Mac/Makefile.in (original) +++ python/branches/py3k-cdecimal/Mac/Makefile.in Sun Jan 2 13:18:37 2011 @@ -202,10 +202,6 @@ installextras: $(srcdir)/Extras.ReadMe.txt $(srcdir)/Extras.install.py $(INSTALL) -d "$(DESTDIR)$(PYTHONAPPSDIR)/Extras" $(INSTALL) $(srcdir)/Extras.ReadMe.txt "$(DESTDIR)$(PYTHONAPPSDIR)/Extras/ReadMe.txt" - $(RUNSHARED) $(BUILDPYTHON) $(srcdir)/Extras.install.py $(srcdir)/../Demo \ - "$(DESTDIR)$(PYTHONAPPSDIR)/Extras/Demo" - $(RUNSHARED) $(BUILDPYTHON) $(srcdir)/Extras.install.py $(srcdir)/Demo \ - "$(DESTDIR)$(PYTHONAPPSDIR)/Extras/Demo.Mac" checkapplepython: $(srcdir)/Tools/fixapplepython23.py Modified: python/branches/py3k-cdecimal/Mac/README ============================================================================== --- python/branches/py3k-cdecimal/Mac/README (original) +++ python/branches/py3k-cdecimal/Mac/README Sun Jan 2 13:18:37 2011 @@ -188,8 +188,8 @@ framework itself, the Mac subtree, the applications and the unix tools. There is an extra target frameworkinstallextras that is not part of the -normal frameworkinstall which installs the Demo and Tools directories -into "/Applications/MacPython ", this is useful for binary +normal frameworkinstall which installs the Tools directory into +"/Applications/MacPython ", this is useful for binary distributions. What do all these programs do? Modified: python/branches/py3k-cdecimal/Makefile.pre.in ============================================================================== --- python/branches/py3k-cdecimal/Makefile.pre.in (original) +++ python/branches/py3k-cdecimal/Makefile.pre.in Sun Jan 2 13:18:37 2011 @@ -108,9 +108,8 @@ # Detailed destination directories BINLIBDEST= $(LIBDIR)/python$(VERSION) LIBDEST= $(SCRIPTDIR)/python$(VERSION) -INCLUDEPY= $(INCLUDEDIR)/python$(VERSION) -CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(VERSION) -LIBP= $(LIBDIR)/python$(VERSION) +INCLUDEPY= $(INCLUDEDIR)/python$(LDVERSION) +CONFINCLUDEPY= $(CONFINCLUDEDIR)/python$(LDVERSION) # Symbols used for using shared libraries SO= @SO@ @@ -155,7 +154,7 @@ SRCDIRS= @SRCDIRS@ # Other subdirectories -SUBDIRSTOO= Include Lib Misc Demo +SUBDIRSTOO= Include Lib Misc # Files and directories to be distributed CONFIGFILES= configure configure.in acconfig.h pyconfig.h.in Makefile.pre.in @@ -167,6 +166,7 @@ LIBRARY= @LIBRARY@ LDLIBRARY= @LDLIBRARY@ BLDLIBRARY= @BLDLIBRARY@ +PY3LIBRARY= @PY3LIBRARY@ DLLLIBRARY= @DLLLIBRARY@ LDLIBRARYDIR= @LDLIBRARYDIR@ INSTSONAME= @INSTSONAME@ @@ -421,7 +421,7 @@ # Build the interpreter -$(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY) +$(BUILDPYTHON): Modules/python.o $(LIBRARY) $(LDLIBRARY) $(PY3LIBRARY) $(LINKCC) $(PY_LDFLAGS) $(LINKFORSHARED) -o $@ Modules/python.o $(BLDLIBRARY) $(LIBS) $(MODLIBS) $(SYSLIBS) $(LDLAST) platform: $(BUILDPYTHON) @@ -455,6 +455,9 @@ $(BLDSHARED) -o $@ $(LIBRARY_OBJS) $(MODLIBS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \ fi +libpython3.so: libpython$(LDVERSION).so + $(BLDSHARED) -o $@ -Wl,-hl$@ $^ + libpython$(VERSION).dylib: $(LIBRARY_OBJS) $(CC) -dynamiclib -Wl,-single_module $(PY_LDFLAGS) -undefined dynamic_lookup -Wl,-install_name,$(prefix)/lib/libpython$(VERSION).dylib -Wl,-compatibility_version,$(VERSION) -Wl,-current_version,$(VERSION) -o $@ $(LIBRARY_OBJS) $(SHLIBS) $(LIBC) $(LIBM) $(LDLAST); \ @@ -499,7 +502,6 @@ $(PYTHONFRAMEWORKDIR)/Versions/$(VERSION)/Resources/Info.plist $(LN) -fsn $(VERSION) $(PYTHONFRAMEWORKDIR)/Versions/Current $(LN) -fsn Versions/Current/$(PYTHONFRAMEWORK) $(PYTHONFRAMEWORKDIR)/$(PYTHONFRAMEWORK) - $(LN) -fsn Versions/Current/Headers $(PYTHONFRAMEWORKDIR)/Headers $(LN) -fsn Versions/Current/Resources $(PYTHONFRAMEWORKDIR)/Resources # This rule builds the Cygwin Python DLL and import library if configured @@ -579,7 +581,7 @@ $(GRAMMAR_H) $(GRAMMAR_C): Parser/pgen.stamp Parser/pgen.stamp: $(PGEN) $(GRAMMAR_INPUT) -@$(INSTALL) -d Include - -$(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C) + $(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C) -touch Parser/pgen.stamp $(PGEN): $(PGENOBJS) @@ -642,6 +644,9 @@ $(BYTESTR_DEPS) \ $(srcdir)/Objects/stringlib/formatter.h +Objects/typeobject.o: $(srcdir)/Objects/typeslots.inc +$(srcdir)/Objects/typeslots.inc: $(srcdir)/Include/typeslots.h $(srcdir)/Objects/typeslots.py + $(PYTHON) $(srcdir)/Objects/typeslots.py < $(srcdir)/Include/typeslots.h > $(srcdir)/Objects/typeslots.inc ############################################################################ # Header files @@ -834,7 +839,13 @@ else true; \ fi; \ done - $(INSTALL_PROGRAM) $(BUILDPYTHON) $(DESTDIR)$(BINDIR)/python$(VERSION)$(EXE) + $(INSTALL_PROGRAM) $(BUILDPYTHON) $(DESTDIR)$(BINDIR)/python$(LDVERSION)$(EXE) + -if test "$(VERSION)" != "$(LDVERSION)"; then \ + if test -f $(DESTDIR)$(BINDIR)/$(PYTHON)$(VERSION)$(EXE) -o -h $(DESTDIR)$(BINDIR)/$(PYTHON)$(VERSION)$(EXE); \ + then rm -f $(DESTDIR)$(BINDIR)/python$(VERSION)$(EXE); \ + fi; \ + (cd $(DESTDIR)$(BINDIR); $(LN) python$(LDVERSION)$(EXE) python$(VERSION)$(EXE)); \ + fi if test -f $(LDLIBRARY); then \ if test -n "$(DLLLIBRARY)" ; then \ $(INSTALL_SHARED) $(DLLLIBRARY) $(DESTDIR)$(BINDIR); \ @@ -844,6 +855,9 @@ (cd $(DESTDIR)$(LIBDIR); $(LN) -sf $(INSTSONAME) $(LDLIBRARY)) \ fi \ fi; \ + if test -n "$(PY3LIBRARY)"; then \ + $(INSTALL_SHARED) $(PY3LIBRARY) $(DESTDIR)$(LIBDIR)/$(PY3LIBRARY); \ + fi; \ else true; \ fi @@ -853,10 +867,22 @@ else true; \ fi (cd $(DESTDIR)$(BINDIR); $(LN) python$(VERSION)$(EXE) $(PYTHON)3$(EXE)) + -if test "$(VERSION)" != "$(LDVERSION)"; then \ + rm -f $(DESTDIR)$(BINDIR)/python$(VERSION)-config; \ + (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(LDVERSION)-config python$(VERSION)-config); \ + rm -f $(DESTDIR)$(LIBPC)/python-$(LDVERSION).pc; \ + (cd $(DESTDIR)$(LIBPC); $(LN) -s python-$(VERSION).pc python-$(LDVERSION).pc); \ + fi -rm -f $(DESTDIR)$(BINDIR)/python3-config (cd $(DESTDIR)$(BINDIR); $(LN) -s python$(VERSION)-config python3-config) -rm -f $(DESTDIR)$(LIBPC)/python3.pc (cd $(DESTDIR)$(LIBPC); $(LN) -s python-$(VERSION).pc python3.pc) + -rm -f $(DESTDIR)$(BINDIR)/idle3 + (cd $(DESTDIR)$(BINDIR); $(LN) -s idle$(VERSION) idle3) + -rm -f $(DESTDIR)$(BINDIR)/pydoc3 + (cd $(DESTDIR)$(BINDIR); $(LN) -s pydoc$(VERSION) pydoc3) + -rm -f $(DESTDIR)$(BINDIR)/2to3 + (cd $(DESTDIR)$(BINDIR); $(LN) -s 2to3-$(VERSION) 2to3) # Install the manual page maninstall: @@ -879,11 +905,11 @@ LIBSUBDIRS= tkinter tkinter/test tkinter/test/test_tkinter \ tkinter/test/test_ttk site-packages test \ test/mpdecimal \ - test/decimaltestdata test/xmltestdata \ + test/decimaltestdata test/xmltestdata test/subprocessdata \ test/tracedmodules test/encoded_modules \ concurrent concurrent/futures encodings \ email email/mime email/test email/test/data \ - html json json/tests http dbm xmlrpc \ + html json test/json_tests http dbm xmlrpc \ sqlite3 sqlite3/test \ logging csv wsgiref urllib \ lib2to3 lib2to3/fixes lib2to3/pgen2 lib2to3/tests \ @@ -987,7 +1013,7 @@ python-config: $(srcdir)/Misc/python-config.in # Substitution happens here, as the completely-expanded BINDIR # is not available in configure - sed -e "s, at EXENAME@,$(BINDIR)/python$(VERSION)$(EXE)," < $(srcdir)/Misc/python-config.in >python-config + sed -e "s, at EXENAME@,$(BINDIR)/python$(LDVERSION)$(EXE)," < $(srcdir)/Misc/python-config.in >python-config # Install the include files INCLDIRSTOMAKE=$(INCLUDEDIR) $(CONFINCLUDEDIR) $(INCLUDEPY) $(CONFINCLUDEPY) @@ -1009,13 +1035,13 @@ # Install the library and miscellaneous stuff needed for extending/embedding # This goes into $(exec_prefix) -LIBPL= $(LIBP)/config +LIBPL= $(LIBDEST)/config-$(LDVERSION) # pkgconfig directory LIBPC= $(LIBDIR)/pkgconfig libainstall: all python-config - @for i in $(LIBDIR) $(LIBP) $(LIBPL) $(LIBPC); \ + @for i in $(LIBDIR) $(LIBPL) $(LIBPC); \ do \ if test ! -d $(DESTDIR)$$i; then \ echo "Creating directory $$i"; \ @@ -1045,7 +1071,7 @@ $(INSTALL_DATA) Misc/python.pc $(DESTDIR)$(LIBPC)/python-$(VERSION).pc $(INSTALL_SCRIPT) $(srcdir)/Modules/makesetup $(DESTDIR)$(LIBPL)/makesetup $(INSTALL_SCRIPT) $(srcdir)/install-sh $(DESTDIR)$(LIBPL)/install-sh - $(INSTALL_SCRIPT) python-config $(DESTDIR)$(BINDIR)/python$(VERSION)-config + $(INSTALL_SCRIPT) python-config $(DESTDIR)$(BINDIR)/python$(LDVERSION)-config rm python-config @if [ -s Modules/python.exp -a \ "`echo $(MACHDEP) | sed 's/^\(...\).*/\1/'`" = "aix" ]; then \ @@ -1103,7 +1129,7 @@ else true; \ fi; \ done - $(LN) -fsn include/python$(VERSION) $(DESTDIR)$(prefix)/Headers + $(LN) -fsn include/python$(LDVERSION) $(DESTDIR)$(prefix)/Headers sed 's/%VERSION%/'"`$(RUNSHARED) ./$(BUILDPYTHON) -c 'import platform; print(platform.python_version())'`"'/g' < $(RESSRCDIR)/Info.plist > $(DESTDIR)$(prefix)/Resources/Info.plist $(LN) -fsn $(VERSION) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/Versions/Current $(LN) -fsn Versions/Current/$(PYTHONFRAMEWORK) $(DESTDIR)$(PYTHONFRAMEWORKINSTALLDIR)/$(PYTHONFRAMEWORK) @@ -1115,8 +1141,8 @@ # Install a number of symlinks to keep software that expects a normal unix # install (which includes python-config) happy. frameworkinstallmaclib: - ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config/libpython$(VERSION).a" - ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config/libpython$(VERSION).dylib" + ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).a" + ln -fs "../../../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/python$(VERSION)/config-$(LDVERSION)/libpython$(VERSION).dylib" ln -fs "../$(PYTHONFRAMEWORK)" "$(DESTDIR)$(prefix)/lib/libpython$(VERSION).dylib" # This installs the IDE, the Launcher and other apps into /Applications @@ -1130,7 +1156,7 @@ frameworkaltinstallunixtools: cd Mac && $(MAKE) altinstallunixtools DESTDIR="$(DESTDIR)" -# This installs the Demos and Tools into the applications directory. +# This installs the Tools into the applications directory. # It is not part of a normal frameworkinstall frameworkinstallextras: cd Mac && $(MAKE) installextras DESTDIR="$(DESTDIR)" @@ -1298,3 +1324,6 @@ .PHONY: gdbhooks # IF YOU PUT ANYTHING HERE IT WILL GO AWAY +# Local Variables: +# mode: makefile +# End: Modified: python/branches/py3k-cdecimal/Misc/ACKS ============================================================================== --- python/branches/py3k-cdecimal/Misc/ACKS (original) +++ python/branches/py3k-cdecimal/Misc/ACKS Sun Jan 2 13:18:37 2011 @@ -12,12 +12,14 @@ and the list is in rough alphabetical order by last names. David Abrahams +Ron Adam Jim Ahlstrom Farhan Ahmad Matthew Ahrens Nir Aides Yaniv Aknin Jyrki Alakuijala +Ray Allen Billy G. Allie Kevin Altis Joe Amenta @@ -76,6 +78,7 @@ Steven Bethard Stephen Bevan Ron Bickers +Adrian von Bidder David Binger Dominic Binks Philippe Biondi @@ -318,6 +321,7 @@ Hans de Graaff Eddy De Greef Duncan Grisby +Eric Groo Dag Gruneau Michael Guravage Lars Gust??bel @@ -394,6 +398,7 @@ Fredrik H????rd Mihai Ibanescu Lars Immisch +Bobby Impollonia Meador Inge Tony Ingraldi John Interrante @@ -449,6 +454,7 @@ Steve Kirsch Sebastian Kirsche Ron Klatchko +Reid Kleckner Bastian Kleineidam Bob Kline Matthias Klose @@ -457,6 +463,7 @@ Pat Knight Greg Kochanski Damon Kohler +Vlad Korolev Joseph Koshy Maksim Kozyarchuk Stefan Krah @@ -469,6 +476,7 @@ Ivan Krsti?? Andrew Kuchling Vladimir Kushnir +Ross Lagerwall Cameron Laird Jean-Baptiste "Jiba" Lamy Torsten Landschoff @@ -499,6 +507,7 @@ Christopher Tur Lesniewski-Laas Mark Levinson William Lewis +Xuanji Li Robert van Liere Ross Light Shawn Ligocki @@ -536,6 +545,7 @@ Doug Marien Alex Martelli Anthony Martin +Owen Martin S??bastien Martini Roger Masse Nick Mathewson @@ -724,6 +734,7 @@ George Sakkis Rich Salz Kevin Samborn +Adrian Sampson Ilya Sandler Mark Sapiro Ty Sarna @@ -733,6 +744,7 @@ Andreas Schawo Neil Schemenauer David Scherer +Bob Schmertz Gregor Schmid Ralf Schmitt Michael Schneider @@ -820,6 +832,7 @@ Tobias Thelen James Thomas Robin Thomas +Jeremy Thurgood Eric Tiedemann Tracy Tims Oren Tirosh @@ -868,6 +881,7 @@ Charles Waldman Richard Walker Larry Wall +Kevin Walzer Rodrigo Steinmuller Wanderley Greg Ward Barry Warsaw Modified: python/branches/py3k-cdecimal/Misc/NEWS ============================================================================== --- python/branches/py3k-cdecimal/Misc/NEWS (original) +++ python/branches/py3k-cdecimal/Misc/NEWS Sun Jan 2 13:18:37 2011 @@ -2,35 +2,389 @@ Python News +++++++++++ +What's New in Python 3.2 Release Candidate 1 +============================================ + +Core and Builtins +----------------- + +- Issue #10780: PyErr_SetFromWindowsErrWithFilename() and + PyErr_SetExcFromWindowsErrWithFilename() decode the filename from the + filesystem encoding instead of UTF-8. + +- Issue #10779: PyErr_WarnExplicit() decodes the filename from the filesystem + encoding instead of UTF-8. + +- Add sys.flags attribute for the new -q command-line option. + +Library +------- + +- Issue #10801: In zipfile, support different encodings for the header and + the filenames. + +- Issue #6285: IDLE no longer crashes on missing help file; patch by Scott + David Daniels. + +- Fix collections.OrderedDict.setdefault() so that it works in + subclasses that define __missing__(). + +- Issue #10786: unittest.TextTestRunner default stream no longer bound at + import time. `sys.stderr` now looked up at instantiation time. Fix + contributed by Mark Roddy. + +- Issue #10753: Characters ';','=' and ',' in the PATH_INFO environment + variable won't be quoted when the URI is constructed by the wsgiref.util 's + request_uri method. According to RFC 3986, these characters can be a part of + params in PATH component of URI and need not be quoted. + +- Issue #10738: Fix webbrowser.Opera.raise_opts. + +- Issue #9824: SimpleCookie now encodes , and ; in values to cater to how + browsers actually parse cookies. + +- Issue #9333: os.symlink now available regardless of user privileges. + The function now raises OSError on Windows >=6.0 when the user is unable + to create symbolic links. XP and 2003 still raise NotImplementedError. + +- Issue #10783: struct.pack() no longer implicitly encodes unicode to UTF-8. + +- Issue #10730: Add SVG mime types to mimetypes module. + +- Issue #10768: Make the Tkinter ScrolledText widget work again. + +- Issue #10777: Fix "dictionary changed size during iteration" bug in + ElementTree register_namespace(). + +- Issue #10626: test_logging now preserves logger disabled states. + +- Issue #10774: test_logging now removes temp files created during tests. + +- Issue #5258/#10642: if site.py encounters a .pth file that generates an error, + it now prints the filename, line number, and traceback to stderr and skips + the rest of that individual file, instead of stopping processing entirely. + +- Issue #10763: subprocess.communicate() closes stdout and stderr if both are + pipes (bug specific to Windows). + +- Issue #1693546: fix email.message RFC 2231 parameter encoding to be in better + compliance (no "s around encoded values). + +- Improved the diff message in the unittest module's assertCountEqual(). + +- Issue #1155362: email.utils.parsedate_tz now handles a missing space before + the '-' of a timezone field as well as before a '+'. + +- Issue #4871: The zipfile module now gives a more useful error message if + an attempt is made to use a string to specify the archive password. + +- Issue #10750: The ``raw`` attribute of buffered IO objects is now read-only. + +- Deprecated assertDictContainsSubset() in the unittest module. + +Build +----- + +- Issue #10679: The "idle", "pydoc" and "2to3" scripts are now installed with + a version-specific suffix on "make altinstall". + +Tools/Demos +----------- + +- Issue #7962: The Demo directory is gone. Most of the old and unmaintained + demos have been removed, others integrated in documentation or a new + Tools/demo subdirectory. + + +What's New in Python 3.2 Beta 2? +================================ + +*Release date: 19-Dec-2010* + +Core and Builtins +----------------- + +- Issue #8844: Regular and recursive lock acquisitions can now be interrupted + by signals on platforms using pthreads. Patch by Reid Kleckner. + +- Issue #4236: PyModule_Create2 now checks the import machinery directly + rather than the Py_IsInitialized flag, avoiding a Fatal Python + error in certain circumstances when an import is done in __del__. + +- Issue #5587: add a repr to dict_proxy objects. Patch by David Stanek and + Daniel Urban. + +Library +------- + +- Issue #3243: Support iterable bodies in httplib. Patch Contributions by + Xuanji Li and Chris AtLee. + +- Issue #10611: SystemExit exception will no longer kill a unittest run. + +- Issue #9857: It is now possible to skip a test in a setUp, tearDown or clean + up function. + +- Issue #10573: use actual/expected consistently in unittest methods. + The order of the args of assertCountEqual is also changed. + +- Issue #9286: email.utils.parseaddr no longer concatenates blank-separated + words in the local part of email addresses, thereby preserving the input. + +- Issue #6791: Limit header line length (to 65535 bytes) in http.client + and http.server, to avoid denial of services from the other party. + +- Issue #10404: Use ctl-button-1 on OSX for the context menu in Idle. + +- Issue #9907: Fix tab handling on OSX when using editline by calling + rl_initialize first, then setting our custom defaults, then reading .editrc. + +- Issue #4188: Avoid creating dummy thread objects when logging operations + from the threading module (with the internal verbose flag activated). + +- Issue #10711: Remove HTTP 0.9 support from http.client. The ``strict`` + parameter to HTTPConnection and friends is deprecated. + +- Issue #9721: Fix the behavior of urljoin when the relative url starts with a + ';' character. Patch by Wes Chow. + +- Issue #10714: Limit length of incoming request in http.server to 65536 bytes + for security reasons. Initial patch by Ross Lagerwall. + +- Issue #9558: Fix distutils.command.build_ext with VS 8.0. + +- Issue #10667: Fast path for collections.Counter(). + +- Issue #10695: passing the port as a string value to telnetlib no longer + causes debug mode to fail. + +- Issue #1078919: add_header now automatically RFC2231 encodes parameters + that contain non-ascii values. + +- Issue #10188 (partial resolution): tempfile.TemporaryDirectory emits + a warning on sys.stderr rather than throwing a misleading exception + if cleanup fails due to nulling out of modules during shutdown. + Also avoids an AttributeError when mkdtemp call fails and issues + a ResourceWarning on implicit cleanup via __del__. + +- Issue #10107: Warn about unsaved files in IDLE on OSX. + +- Issue #7213: subprocess.Popen's default for close_fds has been changed. + It is now True in most cases other than on Windows when input, output or + error handles are provided. + +- Issue #6559: subprocess.Popen has a new pass_fds parameter (actually + added in 3.2beta1) to allow specifying a specific list of file descriptors + to keep open in the child process. + +- Issue #1731717: Fixed the problem where subprocess.wait() could cause an + OSError exception when The OS had been told to ignore SIGCLD in our process + or otherwise not wait for exiting child processes. + +Tests +----- + +- Issue #775964: test_grp now skips YP/NIS entries instead of failing when + encountering them. + +Tools/Demos +----------- + +- Issue #6075: IDLE on Mac OS X now works with both Carbon AquaTk and + Cocoa AquaTk. + +- Issue #10710: ``Misc/setuid-prog.c`` is removed from the source tree. + +- Issue #10706: Remove outdated script runtests.sh. Either ``make test`` + or ``python -m test`` should be used instead. + +Build +----- + +- The Windows build now uses Tcl/Tk 8.5.9 and sqlite3 3.7.4. + +- Issue #9234: argparse supports alias names for subparsers. + + What's New in Python 3.2 Beta 1? ================================ -*Release date: XX-Dec-2010* +*Release date: 05-Dec-2010* Core and Builtins ----------------- -- Issue #10474: range().count() should return integers. +- Issue #10630: Return dict views from the dict proxy keys()/values()/items() + methods. -- Issue #10255: Fix reference leak in Py_InitializeEx(). Patch by Neil - Schemenauer. +- Issue #10596: Fix float.__mod__ to have the same behaviour as float.__divmod__ + with respect to signed zeros. -4.0 % 4.0 should be 0.0, not -0.0. -- Issue #4925: Add filename to error message when executable can't be found in - subprocess. +- Issue #1772833: Add the -q command-line option to suppress copyright and + version output in interactive mode. + +- Provide an *optimize* parameter in the built-in compile() function. + +- Fixed several corner case issues on Windows in os.stat/os.lstat related to + reparse points. + +- PEP 384 (Defining a Stable ABI) is implemented. + +- Issue #2690: Range objects support negative indices and slicing. + +- Issue #9915: Speed up sorting with a key. + +- Issue #8685: Speed up set difference ``a - b`` when source set ``a`` is much + larger than operand ``b``. Patch by Andrew Bennetts. + +- Issue #10518: Bring back the callable() builtin. + +- Issue #7094: Added alternate formatting (specified by '#') to ``__format__`` + method of float, complex, and Decimal. This allows more precise control over + when decimal points are displayed. + +- Issue #10474: range.count() should return integers. - Issue #1574217: isinstance now catches only AttributeError, rather than masking all errors. +Library +------- + +- logging: added "handler of last resort". See http://bit.ly/last-resort-handler + +- test.support: Added TestHandler and Matcher classes for better support of + assertions about logging. + +- Issue #4391: Use proper plural forms in argparse. + +- Issue #10601: sys.displayhook uses 'backslashreplace' error handler on + UnicodeEncodeError. + +- Add the "display" and "undisplay" pdb commands. + +- Issue #7245: Add a SIGINT handler in pdb that allows to break a program again + after a "continue" command. + +- Add the "interact" pdb command. + +- Issue #7905: Actually respect the keyencoding parameter to shelve.Shelf. + +- Issue #1569291: Speed up array.repeat(). + +- Provide an interface to set the optimization level of compilation in + py_compile, compileall and zipfile.PyZipFile. + +- Issue #7904: Changes to urllib.parse.urlsplit to handle schemes as defined by + RFC3986. Anything before :// is considered a scheme and is followed by an + authority (or netloc) and by '/' led path, which is optional. + +- Issue #6045: dbm.gnu databases now support get() and setdefault() methods. + +- Issue #10620: `python -m unittest` can accept file paths instead of module + names for running specific tests. + +- Issue #9424: Deprecate the `unittest.TestCase` methods `assertEquals`, + `assertNotEquals`, `assertAlmostEquals`, `assertNotAlmostEquals` and `assert_` + and replace them with the correct methods in the Python test suite. + +- Issue #10272: The ssl module now raises socket.timeout instead of a generic + SSLError on socket timeouts. + +- Issue #10528: Allow translators to reorder placeholders in localizable + messages from argparse. + +- Issue #10497: Fix incorrect use of gettext in argparse. + +- Issue #10478: Reentrant calls inside buffered IO objects (for example by + way of a signal handler) now raise a RuntimeError instead of freezing the + current process. + +- logging: Added getLogRecordFactory/setLogRecordFactory with docs and tests. + +- Issue #10549: Fix pydoc traceback when text-documenting certain classes. + +- Issue #2001: New HTML server with enhanced Web page features. Patch by Ron + Adam. + +- Issue #10360: In WeakSet, do not raise TypeErrors when testing for membership + of non-weakrefable objects. + +- Issue #940286: pydoc.Helper.help() ignores input/output init parameters. + +- Issue #1745035: Add a command size and data size limit to smtpd.py, to prevent + DoS attacks. Patch by Savio Sena. + +- Issue #4925: Add filename to error message when executable can't be found in + subprocess. + - Issue #10391: Don't dereference invalid memory in error messages in the ast module. -- Issue #9518: Extend the PyModuleDef_HEAD_INIT macro to explicitly - zero-initialize all fields, fixing compiler warnings seen when building - extension modules with gcc with "-Wmissing-field-initializers" (implied - by "-W") +- Issue #10027: st_nlink was not being set on Windows calls to os.stat or + os.lstat. Patch by Hirokazu Yamamoto. -Library -------- +- Issue #9333: Expose os.symlink only when the SeCreateSymbolicLinkPrivilege is + held by the user's account, i.e., when the function can actually be used. + +- Issue #8879: Add os.link support for Windows. + +- Issue #7911: ``unittest.TestCase.longMessage`` defaults to True for improved + failure messages by default. Patch by Mark Roddy. + +- Issue #1486713: HTMLParser now has an optional tolerant mode where it tries to + guess at the correct parsing of invalid html. + +- Issue #10554: Add context manager support to subprocess.Popen objects. + +- Issue #8989: email.utils.make_msgid now has a domain parameter that can + override the domain name used in the generated msgid. + +- Issue #9299: Add exist_ok parameter to os.makedirs to suppress the 'File + exists' exception when a target directory already exists with the specified + mode. Patch by Ray Allen. + +- Issue #9573: os.fork() now works correctly when triggered as a side effect of + a module import. + +- Issue #10464: netrc now correctly handles lines with embedded '#' characters. + +- Added itertools.accumulate(). + +- Issue #4113: Added custom ``__repr__`` method to ``functools.partial``. + Original patch by Daniel Urban. + +- Issue #10273: Rename `assertRegexpMatches` and `assertRaisesRegexp` to + `assertRegex` and `assertRaisesRegex`. + +- Issue #10535: Enable silenced warnings in unittest by default. + +- Issue #9873: The URL parsing functions in urllib.parse now accept ASCII byte + sequences as input in addition to character strings. + +- Issue #10586: The statistics API for the new functools.lru_cache has been + changed to a single cache_info() method returning a named tuple. + +- Issue #10323: itertools.islice() now consumes the minimum number of inputs + before stopping. Formerly, the final state of the underlying iterator was + undefined. + +- Issue #10565: The collections.Iterator ABC now checks for both __iter__ and + __next__. + +- Issue #10242: Fixed implementation of unittest.ItemsEqual and gave it a new + more informative name, unittest.CountEqual. + +- Issue #10561: In pdb, clear the breakpoints by the breakpoint number. + +- Issue #2986: difflib.SequenceMatcher gets a new parameter, autojunk, which can + be set to False to turn off the previously undocumented 'popularity' + heuristic. Patch by Terry Reedy and Eli Bendersky. + +- Issue #10534: in difflib, expose bjunk and bpopular sets; deprecate + undocumented and now redundant isbjunk and isbpopular methods. + +- Issue #9846: zipfile is now correctly closing underlying file objects. - Issue #10459: Update CJK character names to Unicode 6.0. @@ -47,14 +401,14 @@ output stream only when end_headers is invoked. This is a speedup and an internal optimization. Patch by endian. -- Issue #10220: Added inspect.getgeneratorstate. Initial patch by - Rodolpho Eckhardt. +- Issue #10220: Added inspect.getgeneratorstate. Initial patch by Rodolpho + Eckhardt. - Issue #10453: compileall now uses argparse instead of getopt, and thus provides clean output when called with '-h'. -- Issue #8078: Add constants for higher baud rates in the termios module. - Patch by Rodolpho Eckhardt. +- Issue #8078: Add constants for higher baud rates in the termios module. Patch + by Rodolpho Eckhardt. - Issue #10407: Fix two NameErrors in distutils. @@ -63,6 +417,20 @@ - Issue #10467: Fix BytesIO.readinto() after seeking into a position after the end of the file. +- configparser: 100% test coverage. + +- Issue #10499: configparser supports pluggable interpolation handlers. The + default classic interpolation handler is called BasicInterpolation. Another + interpolation handler added (ExtendedInterpolation) which supports the syntax + used by zc.buildout (e.g. interpolation between sections). + +- configparser: the SafeConfigParser class has been renamed to ConfigParser. + The legacy ConfigParser class has been removed but its interpolation mechanism + is still available as LegacyInterpolation. + +- configparser: Usage of RawConfigParser is now discouraged for new projects + in favor of ConfigParser(interpolation=None). + - Issue #1682942: configparser supports alternative option/value delimiters. - Issue #5412: configparser supports mapping protocol access. @@ -72,7 +440,9 @@ - Issue #9421: configparser's getint(), getfloat() and getboolean() methods accept vars and default arguments just like get() does. -- Issue #9452: configparser supports reading from strings and dictionaries. +- Issue #9452: configparser supports reading from strings and dictionaries + (thanks to the mapping protocol API, the latter can be used to copy data + between parsers). - configparser: accepted INI file structure is now customizable, including comment prefixes, name of the DEFAULT section, empty lines in multiline @@ -82,9 +452,9 @@ - Issue 9926: Wrapped TestSuite subclass does not get __call__ executed. -- Issue #9920: Skip tests for cmath.atan and cmath.atanh applied to - complex zeros on systems where the log1p function fails to respect - the sign of zero. This fixes a test failure on AIX. +- Issue #9920: Skip tests for cmath.atan and cmath.atanh applied to complex + zeros on systems where the log1p function fails to respect the sign of zero. + This fixes a test failure on AIX. - Issue #9732: Addition of getattr_static to the inspect module. @@ -98,21 +468,39 @@ - Issue #10440: Support RUSAGE_THREAD as a constant in the resource module. Patch by Robert Collins. -- Issue #10429: IMAP.starttls() stored the capabilities as bytes objects, - rather than strings. +- Issue #10429: IMAP.starttls() stored the capabilities as bytes objects, rather + than strings. C-API ----- +- Issue #10557: Added a new API function, PyUnicode_TransformDecimalToASCII(), + which transforms non-ASCII decimal digits in a Unicode string to their ASCII + equivalents. + +- Issue #9518: Extend the PyModuleDef_HEAD_INIT macro to explicitly + zero-initialize all fields, fixing compiler warnings seen when building + extension modules with gcc with "-Wmissing-field-initializers" (implied by + "-W"). + +- Issue #10255: Fix reference leak in Py_InitializeEx(). Patch by Neil + Schemenauer. + +- structseq.h is now included in Python.h. + - Loosen PyArg_ValidateKeywordArguments to allow dict subclasses. Tests ----- -- Issue #9424: Replace deprecated assert* methods in the Python test suite. +- regrtest.py once again ensures the test directory is removed from sys.path + when it is invoked directly as the __main__ module. -- Do not fail test_socket when the IP address of the local hostname - cannot be looked up. +- `python -m test` can be used to run the test suite as well as `python -m + test.regrtest`. + +- Do not fail test_socket when the IP address of the local hostname cannot be + looked up. - Issue #8886: Use context managers throughout test_zipfile. Patch by Eric Carstensen. @@ -123,6 +511,11 @@ - Issue #10325: Fix two issues in the fallback definitions for PY_ULLONG_MAX and PY_LLONG_MAX that made them unsuitable for use in preprocessor conditionals. +Documentation +------------- + +- Issue #10299: List the built-in functions in a table in functions.rst. + What's New in Python 3.2 Alpha 4? ================================= @@ -545,7 +938,7 @@ - Issue #9252: PyImport_Import no longer uses a fromlist hack to return the module that was imported, but instead gets the module from sys.modules. -- Issue #9212: The range type_items now provides index() and count() methods, to +- Issue #9213: The range type_items now provides index() and count() methods, to conform to the Sequence ABC. Patch by Daniel Urban and Daniel Stutzbach. - Issue #7994: Issue a PendingDeprecationWarning if object.__format__ is called @@ -1228,8 +1621,8 @@ - Issue #8230: Fix Lib/test/sortperf.py. -- Issue #8620: when a Cmd is fed input that reaches EOF without a final newline, - it no longer truncates the last character of the last command line. +- Issue #8620: when a cmd.Cmd() is fed input that reaches EOF without a final + newline, it no longer truncates the last character of the last command line. - Issue #5146: Handle UID THREAD command correctly in imaplib. @@ -1953,7 +2346,7 @@ - Issue #8897: Fix sunau module, use bytes to write the header. Patch written by Thomas Jollans. -- Issue #8899: time.struct_time now has class and atribute docstrings. +- Issue #8899: time.struct_time now has class and attribute docstrings. - Issue #6470: Drop UNC prefix in FixTk. Modified: python/branches/py3k-cdecimal/Misc/README ============================================================================== --- python/branches/py3k-cdecimal/Misc/README (original) +++ python/branches/py3k-cdecimal/Misc/README Sun Jan 2 13:18:37 2011 @@ -20,7 +20,6 @@ NEWS.help How to edit NEWS Porting Mini-FAQ on porting to new platforms PURIFY.README Information for Purify users -pymemcompat.h Memory interface compatibility file. python-config.in Python script template for python-config python.man UNIX man page for the python interpreter python-mode.el Emacs mode for editing Python programs @@ -31,9 +30,7 @@ README.klocwork Information about running Klocwork's K7 on Python README.OpenBSD Help for building problems on OpenBSD README.valgrind Information for Valgrind users, see valgrind-python.supp -RFD Request For Discussion about a Python newsgroup RPM (Old) tools to build RPMs -setuid-prog.c C helper program for set-uid Python scripts SpecialBuilds.txt Describes extra symbols you can set for debug builds TextMate A TextMate bundle for Python development valgrind-python.supp Valgrind suppression file, see README.valgrind Deleted: python/branches/py3k-cdecimal/Misc/RFD ============================================================================== --- python/branches/py3k-cdecimal/Misc/RFD Sun Jan 2 13:18:37 2011 +++ (empty file) @@ -1,114 +0,0 @@ -To: python-list -Subject: comp.lang.python RFD again -From: Guido.van.Rossum at cwi.nl - -I've followed the recent discussion and trimmed the blurb RFD down a bit -(and added the word "object-oriented" to the blurb). - -I don't think it's too early to *try* to create the newsgroup -- -whether we will succeed may depend on how many Python supporters there -are outside the mailing list. - -I'm personally not worried about moderation, and anyway I haven't -heard from any volunteers for moderation (and I won't volunteer -myself) so I suggest that we'll continue to ask for one unmoderated -newsgroup. - -My next action will be to post an updated FAQ (which will hint at the -upcoming RFD) to comp.lang.misc; then finalize the 1.0.0 release and -put it on the ftp site. I'll also try to get it into -comp.sources.unix or .misc. And all this before the end of January! - ---Guido van Rossum, CWI, Amsterdam -URL: - -====================================================================== - -These are the steps required (in case you don't know about the -newsgroup creation process): - -First, we need to draw up an RFD (Request For Discussion). This is a -document that tells what the purpose of the group is, and gives a case -for its creation. We post this to relevant groups (comp.lang.misc, -the mailing list, news.groups, etc.) Discussion is held on -news.groups. - -Then, after a few weeks, we run the official CFV (Call For Votes). -The votes are then collected over a period of weeks. We need 100 more -yes votes than no votes, and a 2/3 majority, to get the group. - -There are some restrictions on the vote taker: [s]he cannot actively -campaign for/against the group during the vote process. So the main -benefit to Steve instead of me running the vote is that I will be free -to campaign for its creation! - -The following is our current draft for the RFD. - -====================================================================== - -Request For Discussion: comp.lang.python - - -Purpose -------- - -The newsgroup will be for discussion on the Python computer language. -Possible topics include requests for information, general programming, -development, and bug reports. The group will be unmoderated. - - -What is Python? ---------------- - -Python is a relatively new very-high-level language developed in -Amsterdam. Python is a simple, object-oriented procedural language, -with features taken from ABC, Icon, Modula-3, and C/C++. - -Its central goal is to provide the best of both worlds: the dynamic -nature of scripting languages like Perl/TCL/REXX, but also support for -general programming found in the more traditional languages like Icon, -C, Modula,... - -Python may be FTP'd from the following sites: - - ftp.cwi.nl in directory /pub/python (its "home site", also has a FAQ) - ftp.uu.net in directory /languages/python - gatekeeper.dec.com in directory /pub/plan/python/cwi - - -Rationale ---------- - -Currently there is a mailing list with over 130 subscribers. -The activity of this list is high, and to make handling the -traffic more reasonable, a newsgroup is being proposed. We -also feel that comp.lang.misc would not be a suitable forum -for this volume of discussion on a particular language. - - -Charter -------- - -Comp.lang.python is an unmoderated newsgroup which will serve -as a forum for discussing the Python computer language. The -group will serve both those who just program in Python and -those who work on developing the language. Topics that -may be discussed include: - - - announcements of new versions of the language and - applications written in Python. - - - discussion on the internals of the Python language. - - - general information about the language. - - - discussion on programming in Python. - - -Discussion ----------- - -Any objections to this RFD will be considered and, if determined -to be appropriate, will be incorporated. The discussion period -will be for a period of 21 days after which the first CFV will be -issued. Modified: python/branches/py3k-cdecimal/Misc/RPM/python-3.2.spec ============================================================================== --- python/branches/py3k-cdecimal/Misc/RPM/python-3.2.spec (original) +++ python/branches/py3k-cdecimal/Misc/RPM/python-3.2.spec Sun Jan 2 13:18:37 2011 @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.2a4 +%define version 3.2b2 %define libvers 3.2 #--end constants-- %define release 1pydotorg Modified: python/branches/py3k-cdecimal/Misc/SpecialBuilds.txt ============================================================================== --- python/branches/py3k-cdecimal/Misc/SpecialBuilds.txt (original) +++ python/branches/py3k-cdecimal/Misc/SpecialBuilds.txt Sun Jan 2 13:18:37 2011 @@ -1,17 +1,20 @@ -This file describes some special Python build types enabled via -compile-time preprocessor defines. +This file describes some special Python build types enabled via compile-time +preprocessor defines. -It is best to define these options in the EXTRA_CFLAGS make variable; +IMPORTANT: if you want to build a debug-enabled Python, it is recommended that +you use ``./configure --with-pydebug``, rather than the options listed here. + +However, if you wish to define some of these options individually, it is best +to define them in the EXTRA_CFLAGS make variable; ``make EXTRA_CFLAGS="-DPy_REF_DEBUG"``. ---------------------------------------------------------------------------- -Py_REF_DEBUG introduced in 1.4 - named REF_DEBUG before 1.4 - -Turn on aggregate reference counting. This arranges that extern -_Py_RefTotal hold a count of all references, the sum of ob_refcnt across -all objects. In a debug-mode build, this is where the "8288" comes from -in + +Py_REF_DEBUG +------------ + +Turn on aggregate reference counting. This arranges that extern _Py_RefTotal +hold a count of all references, the sum of ob_refcnt across all objects. In a +debug-mode build, this is where the "8288" comes from in >>> 23 23 @@ -19,75 +22,72 @@ >>> Note that if this count increases when you're not storing away new objects, -there's probably a leak. Remember, though, that in interactive mode the -special name "_" holds a reference to the last result displayed! +there's probably a leak. Remember, though, that in interactive mode the special +name "_" holds a reference to the last result displayed! -Py_REF_DEBUG also checks after every decref to verify that the refcount -hasn't gone negative, and causes an immediate fatal error if it has. +Py_REF_DEBUG also checks after every decref to verify that the refcount hasn't +gone negative, and causes an immediate fatal error if it has. Special gimmicks: sys.gettotalrefcount() Return current total of all refcounts. - Available under Py_REF_DEBUG in Python 2.3. - Before 2.3, Py_TRACE_REFS was required to enable this function. ---------------------------------------------------------------------------- -Py_TRACE_REFS introduced in 1.4 - named TRACE_REFS before 1.4 - -Turn on heavy reference debugging. This is major surgery. Every PyObject -grows two more pointers, to maintain a doubly-linked list of all live -heap-allocated objects. Most built-in type objects are not in this list, -as they're statically allocated. Starting in Python 2.3, if COUNT_ALLOCS -(see below) is also defined, a static type object T does appear in this -list if at least one object of type T has been created. + + +Py_TRACE_REFS +------------- + +Turn on heavy reference debugging. This is major surgery. Every PyObject grows +two more pointers, to maintain a doubly-linked list of all live heap-allocated +objects. Most built-in type objects are not in this list, as they're statically +allocated. Starting in Python 2.3, if COUNT_ALLOCS (see below) is also defined, +a static type object T does appear in this list if at least one object of type T +has been created. Note that because the fundamental PyObject layout changes, Python modules -compiled with Py_TRACE_REFS are incompatible with modules compiled without -it. +compiled with Py_TRACE_REFS are incompatible with modules compiled without it. Py_TRACE_REFS implies Py_REF_DEBUG. Special gimmicks: sys.getobjects(max[, type]) - Return list of the (no more than) max most-recently allocated objects, - most recently allocated first in the list, least-recently allocated - last in the list. max=0 means no limit on list length. - If an optional type object is passed, the list is also restricted to - objects of that type. - The return list itself, and some temp objects created just to call - sys.getobjects(), are excluded from the return list. Note that the - list returned is just another object, though, so may appear in the - return list the next time you call getobjects(); note that every - object in the list is kept alive too, simply by virtue of being in - the list. - -envar PYTHONDUMPREFS - If this envar exists, Py_Finalize() arranges to print a list of - all still-live heap objects. This is printed twice, in different - formats, before and after Py_Finalize has cleaned up everything it - can clean up. The first output block produces the repr() of each - object so is more informative; however, a lot of stuff destined to - die is still alive then. The second output block is much harder - to work with (repr() can't be invoked anymore -- the interpreter - has been torn down too far), but doesn't list any objects that will - die. The tool script combinerefs.py can be run over this to combine - the info from both output blocks. The second output block, and + Return list of the (no more than) max most-recently allocated objects, most + recently allocated first in the list, least-recently allocated last in the + list. max=0 means no limit on list length. If an optional type object is + passed, the list is also restricted to objects of that type. The return + list itself, and some temp objects created just to call sys.getobjects(), + are excluded from the return list. Note that the list returned is just + another object, though, so may appear in the return list the next time you + call getobjects(); note that every object in the list is kept alive too, + simply by virtue of being in the list. + +envvar PYTHONDUMPREFS + If this envvar exists, Py_Finalize() arranges to print a list of all + still-live heap objects. This is printed twice, in different formats, + before and after Py_Finalize has cleaned up everything it can clean up. The + first output block produces the repr() of each object so is more + informative; however, a lot of stuff destined to die is still alive then. + The second output block is much harder to work with (repr() can't be invoked + anymore -- the interpreter has been torn down too far), but doesn't list any + objects that will die. The tool script combinerefs.py can be run over this + to combine the info from both output blocks. The second output block, and combinerefs.py, were new in Python 2.3b1. ---------------------------------------------------------------------------- -PYMALLOC_DEBUG introduced in 2.3 + + +PYMALLOC_DEBUG +-------------- When pymalloc is enabled (WITH_PYMALLOC is defined), calls to the PyObject_ -memory routines are handled by Python's own small-object allocator, while -calls to the PyMem_ memory routines are directed to the system malloc/ -realloc/free. If PYMALLOC_DEBUG is also defined, calls to both PyObject_ -and PyMem_ memory routines are directed to a special debugging mode of -Python's small-object allocator. - -This mode fills dynamically allocated memory blocks with special, -recognizable bit patterns, and adds debugging info on each end of -dynamically allocated memory blocks. The special bit patterns are: +memory routines are handled by Python's own small-object allocator, while calls +to the PyMem_ memory routines are directed to the system malloc/ realloc/free. +If PYMALLOC_DEBUG is also defined, calls to both PyObject_ and PyMem_ memory +routines are directed to a special debugging mode of Python's small-object +allocator. + +This mode fills dynamically allocated memory blocks with special, recognizable +bit patterns, and adds debugging info on each end of dynamically allocated +memory blocks. The special bit patterns are: #define CLEANBYTE 0xCB /* clean (newly allocated) memory */ #define DEADBYTE 0xDB /* dead (newly freed) memory */ @@ -96,73 +96,70 @@ Strings of these bytes are unlikely to be valid addresses, floats, or 7-bit ASCII strings. -Let S = sizeof(size_t). 2*S bytes are added at each end of each block of N -bytes requested. The memory layout is like so, where p represents the -address returned by a malloc-like or realloc-like function (p[i:j] means -the slice of bytes from *(p+i) inclusive up to *(p+j) exclusive; note that -the treatment of negative indices differs from a Python slice): +Let S = sizeof(size_t). 2*S bytes are added at each end of each block of N bytes +requested. The memory layout is like so, where p represents the address +returned by a malloc-like or realloc-like function (p[i:j] means the slice of +bytes from *(p+i) inclusive up to *(p+j) exclusive; note that the treatment of +negative indices differs from a Python slice): p[-2*S:-S] - Number of bytes originally asked for. This is a size_t, big-endian - (easier to read in a memory dump). + Number of bytes originally asked for. This is a size_t, big-endian (easier + to read in a memory dump). p[-S:0] Copies of FORBIDDENBYTE. Used to catch under- writes and reads. p[0:N] The requested memory, filled with copies of CLEANBYTE, used to catch - reference to uninitialized memory. - When a realloc-like function is called requesting a larger memory - block, the new excess bytes are also filled with CLEANBYTE. - When a free-like function is called, these are overwritten with - DEADBYTE, to catch reference to freed memory. When a realloc- - like function is called requesting a smaller memory block, the excess - old bytes are also filled with DEADBYTE. + reference to uninitialized memory. When a realloc-like function is called + requesting a larger memory block, the new excess bytes are also filled with + CLEANBYTE. When a free-like function is called, these are overwritten with + DEADBYTE, to catch reference to freed memory. When a realloc- like function + is called requesting a smaller memory block, the excess old bytes are also + filled with DEADBYTE. p[N:N+S] Copies of FORBIDDENBYTE. Used to catch over- writes and reads. p[N+S:N+2*S] A serial number, incremented by 1 on each call to a malloc-like or - realloc-like function. - Big-endian size_t. - If "bad memory" is detected later, the serial number gives an - excellent way to set a breakpoint on the next run, to capture the - instant at which this block was passed out. The static function - bumpserialno() in obmalloc.c is the only place the serial number - is incremented, and exists so you can set such a breakpoint easily. - -A realloc-like or free-like function first checks that the FORBIDDENBYTEs -at each end are intact. If they've been altered, diagnostic output is -written to stderr, and the program is aborted via Py_FatalError(). The -other main failure mode is provoking a memory error when a program -reads up one of the special bit patterns and tries to use it as an address. -If you get in a debugger then and look at the object, you're likely -to see that it's entirely filled with 0xDB (meaning freed memory is -getting used) or 0xCB (meaning uninitialized memory is getting used). + realloc-like function. Big-endian size_t. If "bad memory" is detected + later, the serial number gives an excellent way to set a breakpoint on the + next run, to capture the instant at which this block was passed out. The + static function bumpserialno() in obmalloc.c is the only place the serial + number is incremented, and exists so you can set such a breakpoint easily. + +A realloc-like or free-like function first checks that the FORBIDDENBYTEs at +each end are intact. If they've been altered, diagnostic output is written to +stderr, and the program is aborted via Py_FatalError(). The other main failure +mode is provoking a memory error when a program reads up one of the special bit +patterns and tries to use it as an address. If you get in a debugger then and +look at the object, you're likely to see that it's entirely filled with 0xDB +(meaning freed memory is getting used) or 0xCB (meaning uninitialized memory is +getting used). Note that PYMALLOC_DEBUG requires WITH_PYMALLOC. Special gimmicks: -envar PYTHONMALLOCSTATS - If this envar exists, a report of pymalloc summary statistics is - printed to stderr whenever a new arena is allocated, and also - by Py_Finalize(). +envvar PYTHONMALLOCSTATS + If this envvar exists, a report of pymalloc summary statistics is printed to + stderr whenever a new arena is allocated, and also by Py_Finalize(). Changed in 2.5: The number of extra bytes allocated is 4*sizeof(size_t). Before it was 16 on all boxes, reflecting that Python couldn't make use of allocations >= 2**32 bytes even on 64-bit boxes before 2.5. ---------------------------------------------------------------------------- -Py_DEBUG introduced in 1.5 - named DEBUG before 1.5 + + +Py_DEBUG +-------- This is what is generally meant by "a debug build" of Python. -Py_DEBUG implies LLTRACE, Py_REF_DEBUG, Py_TRACE_REFS, and -PYMALLOC_DEBUG (if WITH_PYMALLOC is enabled). In addition, C -assert()s are enabled (via the C way: by not defining NDEBUG), and -some routines do additional sanity checks inside "#ifdef Py_DEBUG" -blocks. ---------------------------------------------------------------------------- -COUNT_ALLOCS introduced in 0.9.9 - partly broken in 2.2 and 2.2.1 +Py_DEBUG implies LLTRACE, Py_REF_DEBUG, Py_TRACE_REFS, and PYMALLOC_DEBUG (if +WITH_PYMALLOC is enabled). In addition, C assert()s are enabled (via the C way: +by not defining NDEBUG), and some routines do additional sanity checks inside +"#ifdef Py_DEBUG" blocks. + + +COUNT_ALLOCS +------------ Each type object grows three new members: @@ -178,84 +175,85 @@ */ int tp_maxalloc; -Allocation and deallocation code keeps these counts up to date. -Py_Finalize() displays a summary of the info returned by sys.getcounts() -(see below), along with assorted other special allocation counts (like -the number of tuple allocations satisfied by a tuple free-list, the number -of 1-character strings allocated, etc). +Allocation and deallocation code keeps these counts up to date. Py_Finalize() +displays a summary of the info returned by sys.getcounts() (see below), along +with assorted other special allocation counts (like the number of tuple +allocations satisfied by a tuple free-list, the number of 1-character strings +allocated, etc). Before Python 2.2, type objects were immortal, and the COUNT_ALLOCS -implementation relies on that. As of Python 2.2, heap-allocated type/ -class objects can go away. COUNT_ALLOCS can blow up in 2.2 and 2.2.1 -because of this; this was fixed in 2.2.2. Use of COUNT_ALLOCS makes -all heap-allocated type objects immortal, except for those for which no -object of that type is ever allocated. +implementation relies on that. As of Python 2.2, heap-allocated type/ class +objects can go away. COUNT_ALLOCS can blow up in 2.2 and 2.2.1 because of this; +this was fixed in 2.2.2. Use of COUNT_ALLOCS makes all heap-allocated type +objects immortal, except for those for which no object of that type is ever +allocated. Starting with Python 2.3, If Py_TRACE_REFS is also defined, COUNT_ALLOCS -arranges to ensure that the type object for each allocated object -appears in the doubly-linked list of all objects maintained by -Py_TRACE_REFS. +arranges to ensure that the type object for each allocated object appears in the +doubly-linked list of all objects maintained by Py_TRACE_REFS. Special gimmicks: sys.getcounts() - Return a list of 4-tuples, one entry for each type object for which - at least one object of that type was allocated. Each tuple is of - the form: + Return a list of 4-tuples, one entry for each type object for which at least + one object of that type was allocated. Each tuple is of the form: (tp_name, tp_allocs, tp_frees, tp_maxalloc) - Each distinct type object gets a distinct entry in this list, even - if two or more type objects have the same tp_name (in which case - there's no way to distinguish them by looking at this list). The - list is ordered by time of first object allocation: the type object - for which the first allocation of an object of that type occurred - most recently is at the front of the list. ---------------------------------------------------------------------------- -LLTRACE introduced well before 1.0 + Each distinct type object gets a distinct entry in this list, even if two or + more type objects have the same tp_name (in which case there's no way to + distinguish them by looking at this list). The list is ordered by time of + first object allocation: the type object for which the first allocation of + an object of that type occurred most recently is at the front of the list. + + +LLTRACE +------- Compile in support for Low Level TRACE-ing of the main interpreter loop. -When this preprocessor symbol is defined, before PyEval_EvalFrame -(eval_frame in 2.3 and 2.2, eval_code2 before that) executes a frame's code -it checks the frame's global namespace for a variable "__lltrace__". If -such a variable is found, mounds of information about what the interpreter -is doing are sprayed to stdout, such as every opcode and opcode argument -and values pushed onto and popped off the value stack. +When this preprocessor symbol is defined, before PyEval_EvalFrame (eval_frame in +2.3 and 2.2, eval_code2 before that) executes a frame's code it checks the +frame's global namespace for a variable "__lltrace__". If such a variable is +found, mounds of information about what the interpreter is doing are sprayed to +stdout, such as every opcode and opcode argument and values pushed onto and +popped off the value stack. Not useful very often, but very useful when needed. ---------------------------------------------------------------------------- -CALL_PROFILE introduced for Python 2.3 + +CALL_PROFILE +------------ Count the number of function calls executed. -When this symbol is defined, the ceval mainloop and helper functions -count the number of function calls made. It keeps detailed statistics -about what kind of object was called and whether the call hit any of -the special fast paths in the code. +When this symbol is defined, the ceval mainloop and helper functions count the +number of function calls made. It keeps detailed statistics about what kind of +object was called and whether the call hit any of the special fast paths in the +code. + ---------------------------------------------------------------------------- -WITH_TSC introduced for Python 2.4 +WITH_TSC +-------- -Super-lowlevel profiling of the interpreter. When enabled, the sys -module grows a new function: +Super-lowlevel profiling of the interpreter. When enabled, the sys module grows +a new function: settscdump(bool) - If true, tell the Python interpreter to dump VM measurements to - stderr. If false, turn off dump. The measurements are based on the - processor's time-stamp counter. - -This build option requires a small amount of platform specific code. -Currently this code is present for linux/x86 and any PowerPC platform -that uses GCC (i.e. OS X and linux/ppc). - -On the PowerPC the rate at which the time base register is incremented -is not defined by the architecture specification, so you'll need to -find the manual for your specific processor. For the 750CX, 750CXe -and 750FX (all sold as the G3) we find: + If true, tell the Python interpreter to dump VM measurements to stderr. If + false, turn off dump. The measurements are based on the processor's + time-stamp counter. + +This build option requires a small amount of platform specific code. Currently +this code is present for linux/x86 and any PowerPC platform that uses GCC +(i.e. OS X and linux/ppc). + +On the PowerPC the rate at which the time base register is incremented is not +defined by the architecture specification, so you'll need to find the manual for +your specific processor. For the 750CX, 750CXe and 750FX (all sold as the G3) +we find: - The time base counter is clocked at a frequency that is - one-fourth that of the bus clock. + The time base counter is clocked at a frequency that is one-fourth that of + the bus clock. This build is enabled by the --with-tsc flag to configure. Deleted: python/branches/py3k-cdecimal/Misc/pymemcompat.h ============================================================================== --- python/branches/py3k-cdecimal/Misc/pymemcompat.h Sun Jan 2 13:18:37 2011 +++ (empty file) @@ -1,85 +0,0 @@ -/* The idea of this file is that you bundle it with your extension, - #include it, program to Python 2.3's memory API and have your - extension build with any version of Python from 1.5.2 through to - 2.3 (and hopefully beyond). */ - -#ifndef Py_PYMEMCOMPAT_H -#define Py_PYMEMCOMPAT_H - -#include "Python.h" - -/* There are three "families" of memory API: the "raw memory", "object - memory" and "object" families. (This is ignoring the matter of the - cycle collector, about which more is said below). - - Raw Memory: - - PyMem_Malloc, PyMem_Realloc, PyMem_Free - - Object Memory: - - PyObject_Malloc, PyObject_Realloc, PyObject_Free - - Object: - - PyObject_New, PyObject_NewVar, PyObject_Del - - The raw memory and object memory allocators both mimic the - malloc/realloc/free interface from ANSI C, but the object memory - allocator can (and, since 2.3, does by default) use a different - allocation strategy biased towards lots of "small" allocations. - - The object family is used for allocating Python objects, and the - initializers take care of some basic initialization (setting the - refcount to 1 and filling out the ob_type field) as well as having - a somewhat different interface. - - Do not mix the families! E.g. do not allocate memory with - PyMem_Malloc and free it with PyObject_Free. You may get away with - it quite a lot of the time, but there *are* scenarios where this - will break. You Have Been Warned. - - Also, in many versions of Python there are an insane amount of - memory interfaces to choose from. Use the ones described above. */ - -#if PY_VERSION_HEX < 0x01060000 -/* raw memory interface already present */ - -/* there is no object memory interface in 1.5.2 */ -#define PyObject_Malloc PyMem_Malloc -#define PyObject_Realloc PyMem_Realloc -#define PyObject_Free PyMem_Free - -/* the object interface is there, but the names have changed */ -#define PyObject_New PyObject_NEW -#define PyObject_NewVar PyObject_NEW_VAR -#define PyObject_Del PyMem_Free -#endif - -/* If your object is a container you probably want to support the - cycle collector, which was new in Python 2.0. - - Unfortunately, the interface to the collector that was present in - Python 2.0 and 2.1 proved to be tricky to use, and so changed in - 2.2 -- in a way that can't easily be papered over with macros. - - This file contains macros that let you program to the 2.2 GC API. - Your module will compile against any Python since version 1.5.2, - but the type will only participate in the GC in versions 2.2 and - up. Some work is still necessary on your part to only fill out the - tp_traverse and tp_clear fields when they exist and set tp_flags - appropriately. - - It is possible to support both the 2.0 and 2.2 GC APIs, but it's - not pretty and this comment block is too narrow to contain a - description of what's required... */ - -#if PY_VERSION_HEX < 0x020200B1 -#define PyObject_GC_New PyObject_New -#define PyObject_GC_NewVar PyObject_NewVar -#define PyObject_GC_Del PyObject_Del -#define PyObject_GC_Track(op) -#define PyObject_GC_UnTrack(op) -#endif - -#endif /* !Py_PYMEMCOMPAT_H */ Modified: python/branches/py3k-cdecimal/Misc/python-wing4.wpr ============================================================================== --- python/branches/py3k-cdecimal/Misc/python-wing4.wpr (original) +++ python/branches/py3k-cdecimal/Misc/python-wing4.wpr Sun Jan 2 13:18:37 2011 @@ -5,8 +5,10 @@ ################################################################## [project attributes] proj.directory-list = [{'dirloc': loc('..'), - 'excludes': [u'Lib/__pycache__', + 'excludes': [u'Lib/unittest/test/__pycache__', + u'Lib/__pycache__', u'Doc/build', + u'Lib/unittest/__pycache__', u'build'], 'filter': '*', 'include_hidden': False, Modified: python/branches/py3k-cdecimal/Misc/python.man ============================================================================== --- python/branches/py3k-cdecimal/Misc/python.man (original) +++ python/branches/py3k-cdecimal/Misc/python.man Sun Jan 2 13:18:37 2011 @@ -26,6 +26,9 @@ .B \-m .I module-name ] +[ +.B \-q +] .br [ .B \-O @@ -145,6 +148,10 @@ .B \-O0 Discard docstrings in addition to the \fB-O\fP optimizations. .TP +.B \-q +Do not print the version and copyright messages. These messages are +also suppressed in non-interactive mode. +.TP .BI "\-Q " argument Division control; see PEP 238. The argument must be one of "old" (the default, int/int and long/long return an int or long), "new" (new Modified: python/branches/py3k-cdecimal/Misc/python.pc.in ============================================================================== --- python/branches/py3k-cdecimal/Misc/python.pc.in (original) +++ python/branches/py3k-cdecimal/Misc/python.pc.in Sun Jan 2 13:18:37 2011 @@ -1,3 +1,4 @@ +# See: man pkg-config prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ @@ -9,5 +10,4 @@ Version: @VERSION@ Libs.private: @LIBS@ Libs: -L${libdir} -lpython at VERSION@@ABIFLAGS@ -Cflags: -I${includedir}/python at VERSION@ - +Cflags: -I${includedir}/python at VERSION@@ABIFLAGS@ Deleted: python/branches/py3k-cdecimal/Misc/setuid-prog.c ============================================================================== --- python/branches/py3k-cdecimal/Misc/setuid-prog.c Sun Jan 2 13:18:37 2011 +++ (empty file) @@ -1,176 +0,0 @@ -/* - Template for a setuid program that calls a script. - - The script should be in an unwritable directory and should itself - be unwritable. In fact all parent directories up to the root - should be unwritable. The script must not be setuid, that's what - this program is for. - - This is a template program. You need to fill in the name of the - script that must be executed. This is done by changing the - definition of FULL_PATH below. - - There are also some rules that should be adhered to when writing - the script itself. - - The first and most important rule is to never, ever trust that the - user of the program will behave properly. Program defensively. - Check your arguments for reasonableness. If the user is allowed to - create files, check the names of the files. If the program depends - on argv[0] for the action it should perform, check it. - - Assuming the script is a Bourne shell script, the first line of the - script should be - #!/bin/sh - - The - is important, don't omit it. If you're using esh, the first - line should be - #!/usr/local/bin/esh -f - and for ksh, the first line should be - #!/usr/local/bin/ksh -p - The script should then set the variable IFS to the string - consisting of , , and . After this (*not* - before!), the PATH variable should be set to a reasonable value and - exported. Do not expect the PATH to have a reasonable value, so do - not trust the old value of PATH. You should then set the umask of - the program by calling - umask 077 # or 022 if you want the files to be readable - If you plan to change directories, you should either unset CDPATH - or set it to a good value. Setting CDPATH to just ``.'' (dot) is a - good idea. - If, for some reason, you want to use csh, the first line should be - #!/bin/csh -fb - You should then set the path variable to something reasonable, - without trusting the inherited path. Here too, you should set the - umask using the command - umask 077 # or 022 if you want the files to be readable -*/ - -#include -#include -#include -#include -#include -#include - -/* CONFIGURATION SECTION */ - -#ifndef FULL_PATH /* so that this can be specified from the Makefile */ -/* Uncomment the following line: -#define FULL_PATH "/full/path/of/script" -* Then comment out the #error line. */ -#error "You must define FULL_PATH somewhere" -#endif -#ifndef UMASK -#define UMASK 077 -#endif - -/* END OF CONFIGURATION SECTION */ - -#if defined(__STDC__) && defined(__sgi) -#define environ _environ -#endif - -/* don't change def_IFS */ -char def_IFS[] = "IFS= \t\n"; -/* you may want to change def_PATH, but you should really change it in */ -/* your script */ -#ifdef __sgi -char def_PATH[] = "PATH=/usr/bsd:/usr/bin:/bin:/usr/local/bin:/usr/sbin"; -#else -char def_PATH[] = "PATH=/usr/ucb:/usr/bin:/bin:/usr/local/bin"; -#endif -/* don't change def_CDPATH */ -char def_CDPATH[] = "CDPATH=."; -/* don't change def_ENV */ -char def_ENV[] = "ENV=:"; - -/* - This function changes all environment variables that start with LD_ - into variables that start with XD_. This is important since we - don't want the script that is executed to use any funny shared - libraries. - - The other changes to the environment are, strictly speaking, not - needed here. They can safely be done in the script. They are done - here because we don't trust the script writer (just like the script - writer shouldn't trust the user of the script). - If IFS is set in the environment, set it to space,tab,newline. - If CDPATH is set in the environment, set it to ``.''. - Set PATH to a reasonable default. -*/ -void -clean_environ(void) -{ - char **p; - extern char **environ; - - for (p = environ; *p; p++) { - if (strncmp(*p, "LD_", 3) == 0) - **p = 'X'; - else if (strncmp(*p, "_RLD", 4) == 0) - **p = 'X'; - else if (strncmp(*p, "PYTHON", 6) == 0) - **p = 'X'; - else if (strncmp(*p, "IFS=", 4) == 0) - *p = def_IFS; - else if (strncmp(*p, "CDPATH=", 7) == 0) - *p = def_CDPATH; - else if (strncmp(*p, "ENV=", 4) == 0) - *p = def_ENV; - } - putenv(def_PATH); -} - -int -main(int argc, char **argv) -{ - struct stat statb; - gid_t egid = getegid(); - uid_t euid = geteuid(); - - /* - Sanity check #1. - This check should be made compile-time, but that's not possible. - If you're sure that you specified a full path name for FULL_PATH, - you can omit this check. - */ - if (FULL_PATH[0] != '/') { - fprintf(stderr, "%s: %s is not a full path name\n", argv[0], - FULL_PATH); - fprintf(stderr, "You can only use this wrapper if you\n"); - fprintf(stderr, "compile it with an absolute path.\n"); - exit(1); - } - - /* - Sanity check #2. - Check that the owner of the script is equal to either the - effective uid or the super user. - */ - if (stat(FULL_PATH, &statb) < 0) { - perror("stat"); - exit(1); - } - if (statb.st_uid != 0 && statb.st_uid != euid) { - fprintf(stderr, "%s: %s has the wrong owner\n", argv[0], - FULL_PATH); - fprintf(stderr, "The script should be owned by root,\n"); - fprintf(stderr, "and shouldn't be writable by anyone.\n"); - exit(1); - } - - if (setregid(egid, egid) < 0) - perror("setregid"); - if (setreuid(euid, euid) < 0) - perror("setreuid"); - - clean_environ(); - - umask(UMASK); - - while (**argv == '-') /* don't let argv[0] start with '-' */ - (*argv)++; - execv(FULL_PATH, argv); - fprintf(stderr, "%s: could not execute the script\n", argv[0]); - exit(1); -} Modified: python/branches/py3k-cdecimal/Modules/_collectionsmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_collectionsmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/_collectionsmodule.c Sun Jan 2 13:18:37 2011 @@ -1518,6 +1518,68 @@ PyObject_GC_Del, /* tp_free */ }; +/* helper function for Counter *********************************************/ + +PyDoc_STRVAR(_count_elements_doc, +"_count_elements(mapping, iterable) -> None\n\ +\n\ +Count elements in the iterable, updating the mappping"); + +static PyObject * +_count_elements(PyObject *self, PyObject *args) +{ + PyObject *it, *iterable, *mapping, *oldval; + PyObject *newval = NULL; + PyObject *key = NULL; + PyObject *one = NULL; + + if (!PyArg_UnpackTuple(args, "_count_elements", 2, 2, &mapping, &iterable)) + return NULL; + + if (!PyDict_Check(mapping)) { + PyErr_SetString(PyExc_TypeError, + "Expected mapping argument to be a dictionary"); + return NULL; + } + + it = PyObject_GetIter(iterable); + if (it == NULL) + return NULL; + one = PyLong_FromLong(1); + if (one == NULL) { + Py_DECREF(it); + return NULL; + } + while (1) { + key = PyIter_Next(it); + if (key == NULL) { + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + break; + } + oldval = PyDict_GetItem(mapping, key); + if (oldval == NULL) { + if (PyDict_SetItem(mapping, key, one) == -1) + break; + } else { + newval = PyNumber_Add(oldval, one); + if (newval == NULL) + break; + if (PyDict_SetItem(mapping, key, newval) == -1) + break; + Py_CLEAR(newval); + } + Py_DECREF(key); + } + Py_DECREF(it); + Py_XDECREF(key); + Py_XDECREF(newval); + Py_DECREF(one); + if (PyErr_Occurred()) + return NULL; + Py_RETURN_NONE; +} + /* module level code ********************************************************/ PyDoc_STRVAR(module_doc, @@ -1526,13 +1588,17 @@ - defaultdict: dict subclass with a default value factory\n\ "); +static struct PyMethodDef module_functions[] = { + {"_count_elements", _count_elements, METH_VARARGS, _count_elements_doc}, + {NULL, NULL} /* sentinel */ +}; static struct PyModuleDef _collectionsmodule = { PyModuleDef_HEAD_INIT, "_collections", module_doc, -1, - NULL, + module_functions, NULL, NULL, NULL, Modified: python/branches/py3k-cdecimal/Modules/_ctypes/_ctypes.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_ctypes/_ctypes.c (original) +++ python/branches/py3k-cdecimal/Modules/_ctypes/_ctypes.c Sun Jan 2 13:18:37 2011 @@ -1155,7 +1155,7 @@ result = -1; goto done; } - result = PyUnicode_AsWideChar((PyUnicodeObject *)value, + result = PyUnicode_AsWideChar(value, (wchar_t *)self->b_ptr, self->b_size/sizeof(wchar_t)); if (result >= 0 && (size_t)result < self->b_size/sizeof(wchar_t)) @@ -4174,7 +4174,7 @@ PyObject *np; Py_ssize_t start, stop, step, slicelen, cur, i; - if (PySlice_GetIndicesEx((PySliceObject *)item, + if (PySlice_GetIndicesEx(item, self->b_length, &start, &stop, &step, &slicelen) < 0) { return NULL; @@ -4308,7 +4308,7 @@ else if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelen, otherlen, i, cur; - if (PySlice_GetIndicesEx((PySliceObject *)item, + if (PySlice_GetIndicesEx(item, self->b_length, &start, &stop, &step, &slicelen) < 0) { return -1; Modified: python/branches/py3k-cdecimal/Modules/_ctypes/cfield.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_ctypes/cfield.c (original) +++ python/branches/py3k-cdecimal/Modules/_ctypes/cfield.c Sun Jan 2 13:18:37 2011 @@ -1214,7 +1214,7 @@ } else Py_INCREF(value); - len = PyUnicode_AsWideChar((PyUnicodeObject *)value, chars, 2); + len = PyUnicode_AsWideChar(value, chars, 2); if (len != 1) { Py_DECREF(value); PyErr_SetString(PyExc_TypeError, @@ -1292,7 +1292,7 @@ } else if (size < length-1) /* copy terminating NUL character if there is space */ size += 1; - PyUnicode_AsWideChar((PyUnicodeObject *)value, (wchar_t *)ptr, size); + PyUnicode_AsWideChar(value, (wchar_t *)ptr, size); return value; } Modified: python/branches/py3k-cdecimal/Modules/_datetimemodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_datetimemodule.c (original) +++ python/branches/py3k-cdecimal/Modules/_datetimemodule.c Sun Jan 2 13:18:37 2011 @@ -3,7 +3,6 @@ */ #include "Python.h" -#include "modsupport.h" #include "structmember.h" #include @@ -1258,7 +1257,8 @@ assert(PyUnicode_Check(Zreplacement)); ptoappend = _PyUnicode_AsStringAndSize(Zreplacement, &ntoappend); - ntoappend = Py_SIZE(Zreplacement); + if (ptoappend == NULL) + goto Done; } else if (ch == 'f') { /* format microseconds */ Modified: python/branches/py3k-cdecimal/Modules/_elementtree.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_elementtree.c (original) +++ python/branches/py3k-cdecimal/Modules/_elementtree.c Sun Jan 2 13:18:37 2011 @@ -1272,7 +1272,7 @@ if (!self->extra) return PyList_New(0); - if (PySlice_GetIndicesEx((PySliceObject *)item, + if (PySlice_GetIndicesEx(item, self->extra->length, &start, &stop, &step, &slicelen) < 0) { return NULL; @@ -1331,7 +1331,7 @@ if (!self->extra) element_new_extra(self, NULL); - if (PySlice_GetIndicesEx((PySliceObject *)item, + if (PySlice_GetIndicesEx(item, self->extra->length, &start, &stop, &step, &slicelen) < 0) { return -1; @@ -1483,6 +1483,9 @@ if (PyUnicode_Check(nameobj)) name = _PyUnicode_AsString(nameobj); + + if (name == NULL) + return NULL; /* handle common attributes first */ if (strcmp(name, "tag") == 0) { @@ -2139,7 +2142,7 @@ PyObject *position; char buffer[256]; - sprintf(buffer, "%s: line %d, column %d", message, line, column); + sprintf(buffer, "%.100s: line %d, column %d", message, line, column); error = PyObject_CallFunction(elementtree_parseerror_obj, "s", buffer); if (!error) @@ -2194,8 +2197,8 @@ Py_XDECREF(res); } else if (!PyErr_Occurred()) { /* Report the first error, not the last */ - char message[128]; - sprintf(message, "undefined entity &%.100s;", _PyUnicode_AsString(key)); + char message[128] = "undefined entity "; + strncat(message, data_in, data_len < 100?data_len:100); expat_set_error( message, EXPAT(GetErrorLineNumber)(self->parser), @@ -2796,29 +2799,25 @@ static PyObject* xmlparser_getattro(XMLParserObject* self, PyObject* nameobj) { - PyObject* res; - char *name = ""; - - if (PyUnicode_Check(nameobj)) - name = _PyUnicode_AsString(nameobj); - - PyErr_Clear(); - - if (strcmp(name, "entity") == 0) - res = self->entity; - else if (strcmp(name, "target") == 0) - res = self->target; - else if (strcmp(name, "version") == 0) { - char buffer[100]; - sprintf(buffer, "Expat %d.%d.%d", XML_MAJOR_VERSION, + if (PyUnicode_Check(nameobj)) { + PyObject* res; + if (PyUnicode_CompareWithASCIIString(nameobj, "entity") == 0) + res = self->entity; + else if (PyUnicode_CompareWithASCIIString(nameobj, "target") == 0) + res = self->target; + else if (PyUnicode_CompareWithASCIIString(nameobj, "version") == 0) { + return PyUnicode_FromFormat( + "Expat %d.%d.%d", XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION); - return PyUnicode_DecodeUTF8(buffer, strlen(buffer), "strict"); - } else { - return PyObject_GenericGetAttr((PyObject*) self, nameobj); - } + } + else + goto generic; - Py_INCREF(res); - return res; + Py_INCREF(res); + return res; + } + generic: + return PyObject_GenericGetAttr((PyObject*) self, nameobj); } static PyTypeObject XMLParser_Type = { Modified: python/branches/py3k-cdecimal/Modules/_functoolsmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_functoolsmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/_functoolsmodule.c Sun Jan 2 13:18:37 2011 @@ -196,6 +196,48 @@ {NULL} /* Sentinel */ }; +static PyObject * +partial_repr(partialobject *pto) +{ + PyObject *result; + PyObject *arglist; + PyObject *tmp; + Py_ssize_t i, n; + + arglist = PyUnicode_FromString(""); + if (arglist == NULL) { + return NULL; + } + /* Pack positional arguments */ + assert (PyTuple_Check(pto->args)); + n = PyTuple_GET_SIZE(pto->args); + for (i = 0; i < n; i++) { + tmp = PyUnicode_FromFormat("%U, %R", arglist, + PyTuple_GET_ITEM(pto->args, i)); + Py_DECREF(arglist); + if (tmp == NULL) + return NULL; + arglist = tmp; + } + /* Pack keyword arguments */ + assert (pto->kw == Py_None || PyDict_Check(pto->kw)); + if (pto->kw != Py_None) { + PyObject *key, *value; + for (i = 0; PyDict_Next(pto->kw, &i, &key, &value);) { + tmp = PyUnicode_FromFormat("%U, %U=%R", arglist, + key, value); + Py_DECREF(arglist); + if (tmp == NULL) + return NULL; + arglist = tmp; + } + } + result = PyUnicode_FromFormat("%s(%R%U)", Py_TYPE(pto)->tp_name, + pto->fn, arglist); + Py_DECREF(arglist); + return result; +} + /* Pickle strategy: __reduce__ by itself doesn't support getting kwargs in the unpickle operation so we define a __setstate__ that replaces all the information @@ -254,7 +296,7 @@ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - 0, /* tp_repr */ + (reprfunc)partial_repr, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ Modified: python/branches/py3k-cdecimal/Modules/_gdbmmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_gdbmmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/_gdbmmodule.c Sun Jan 2 13:18:37 2011 @@ -135,6 +135,28 @@ return v; } +PyDoc_STRVAR(dbm_get__doc__, +"get(key[, default]) -> value\n\ +Get the value for key, or default if not present; if not given,\n\ +default is None."); + +static PyObject * +dbm_get(dbmobject *dp, PyObject *args) +{ + PyObject *v, *res; + PyObject *def = Py_None; + + if (!PyArg_UnpackTuple(args, "get", 1, 2, &v, &def)) + return NULL; + res = dbm_subscript(dp, v); + if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) { + PyErr_Clear(); + Py_INCREF(def); + return def; + } + return res; +} + static int dbm_ass_sub(dbmobject *dp, PyObject *v, PyObject *w) { @@ -176,6 +198,29 @@ return 0; } +PyDoc_STRVAR(dbm_setdefault__doc__, +"setdefault(key[, default]) -> value\n\ +Get value for key, or set it to default and return default if not present;\n\ +if not given, default is None."); + +static PyObject * +dbm_setdefault(dbmobject *dp, PyObject *args) +{ + PyObject *v, *res; + PyObject *def = Py_None; + + if (!PyArg_UnpackTuple(args, "setdefault", 1, 2, &v, &def)) + return NULL; + res = dbm_subscript(dp, v); + if (res == NULL && PyErr_ExceptionMatches(PyExc_KeyError)) { + PyErr_Clear(); + if (dbm_ass_sub(dp, v, def) < 0) + return NULL; + return dbm_subscript(dp, v); + } + return res; +} + static PyMappingMethods dbm_as_mapping = { (lenfunc)dbm_length, /*mp_length*/ (binaryfunc)dbm_subscript, /*mp_subscript*/ @@ -378,6 +423,8 @@ {"nextkey", (PyCFunction)dbm_nextkey, METH_VARARGS, dbm_nextkey__doc__}, {"reorganize",(PyCFunction)dbm_reorganize,METH_NOARGS, dbm_reorganize__doc__}, {"sync", (PyCFunction)dbm_sync, METH_NOARGS, dbm_sync__doc__}, + {"get", (PyCFunction)dbm_get, METH_VARARGS, dbm_get__doc__}, + {"setdefault",(PyCFunction)dbm_setdefault,METH_VARARGS, dbm_setdefault__doc__}, {NULL, NULL} /* sentinel */ }; Modified: python/branches/py3k-cdecimal/Modules/_io/bufferedio.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_io/bufferedio.c (original) +++ python/branches/py3k-cdecimal/Modules/_io/bufferedio.c Sun Jan 2 13:18:37 2011 @@ -225,6 +225,7 @@ #ifdef WITH_THREAD PyThread_type_lock lock; + volatile long owner; #endif Py_ssize_t buffer_size; @@ -260,17 +261,34 @@ /* These macros protect the buffered object against concurrent operations. */ #ifdef WITH_THREAD -#define ENTER_BUFFERED(self) \ - if (!PyThread_acquire_lock(self->lock, 0)) { \ - Py_BEGIN_ALLOW_THREADS \ - PyThread_acquire_lock(self->lock, 1); \ - Py_END_ALLOW_THREADS \ + +static int +_enter_buffered_busy(buffered *self) +{ + if (self->owner == PyThread_get_thread_ident()) { + PyErr_Format(PyExc_RuntimeError, + "reentrant call inside %R", self); + return 0; } + Py_BEGIN_ALLOW_THREADS + PyThread_acquire_lock(self->lock, 1); + Py_END_ALLOW_THREADS + return 1; +} + +#define ENTER_BUFFERED(self) \ + ( (PyThread_acquire_lock(self->lock, 0) ? \ + 1 : _enter_buffered_busy(self)) \ + && (self->owner = PyThread_get_thread_ident(), 1) ) #define LEAVE_BUFFERED(self) \ - PyThread_release_lock(self->lock); + do { \ + self->owner = 0; \ + PyThread_release_lock(self->lock); \ + } while(0); + #else -#define ENTER_BUFFERED(self) +#define ENTER_BUFFERED(self) 1 #define LEAVE_BUFFERED(self) #endif @@ -444,7 +462,8 @@ int r; CHECK_INITIALIZED(self) - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) + return NULL; r = buffered_closed(self); if (r < 0) @@ -465,7 +484,8 @@ /* flush() will most probably re-take the lock, so drop it first */ LEAVE_BUFFERED(self) res = PyObject_CallMethodObjArgs((PyObject *)self, _PyIO_str_flush, NULL); - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) + return NULL; if (res == NULL) { goto end; } @@ -679,6 +699,7 @@ PyErr_SetString(PyExc_RuntimeError, "can't allocate read lock"); return -1; } + self->owner = 0; #endif /* Find out whether buffer_size is a power of 2 */ /* XXX is this optimization useful? */ @@ -705,7 +726,8 @@ CHECK_INITIALIZED(self) CHECK_CLOSED(self, "flush of closed file") - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) + return NULL; res = _bufferedwriter_flush_unlocked(self, 0); if (res != NULL && self->readable) { /* Rewind the raw stream so that its position corresponds to @@ -732,7 +754,8 @@ return NULL; } - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) + return NULL; if (self->writable) { res = _bufferedwriter_flush_unlocked(self, 1); @@ -767,7 +790,8 @@ if (n == -1) { /* The number of bytes is unspecified, read until the end of stream */ - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) + return NULL; res = _bufferedreader_read_all(self); LEAVE_BUFFERED(self) } @@ -775,7 +799,8 @@ res = _bufferedreader_read_fast(self, n); if (res == Py_None) { Py_DECREF(res); - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) + return NULL; res = _bufferedreader_read_generic(self, n); LEAVE_BUFFERED(self) } @@ -803,7 +828,8 @@ if (n == 0) return PyBytes_FromStringAndSize(NULL, 0); - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) + return NULL; if (self->writable) { res = _bufferedwriter_flush_unlocked(self, 1); @@ -859,7 +885,8 @@ /* TODO: use raw.readinto() instead! */ if (self->writable) { - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) + return NULL; res = _bufferedwriter_flush_unlocked(self, 0); LEAVE_BUFFERED(self) if (res == NULL) @@ -903,7 +930,8 @@ goto end_unlocked; } - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) + goto end_unlocked; /* Now we try to get some more from the raw stream */ if (self->writable) { @@ -1053,7 +1081,8 @@ } } - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) + return NULL; /* Fallback: invoke raw seek() method and clear buffer */ if (self->writable) { @@ -1091,7 +1120,8 @@ return NULL; } - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) + return NULL; if (self->writable) { res = _bufferedwriter_flush_unlocked(self, 0); @@ -1511,7 +1541,7 @@ }; static PyMemberDef bufferedreader_members[] = { - {"raw", T_OBJECT, offsetof(buffered, raw), 0}, + {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, {NULL} }; @@ -1748,7 +1778,10 @@ return NULL; } - ENTER_BUFFERED(self) + if (!ENTER_BUFFERED(self)) { + PyBuffer_Release(&buf); + return NULL; + } /* Fast path: the data to write can be fully buffered. */ if (!VALID_READ_BUFFER(self) && !VALID_WRITE_BUFFER(self)) { @@ -1893,7 +1926,7 @@ }; static PyMemberDef bufferedwriter_members[] = { - {"raw", T_OBJECT, offsetof(buffered, raw), 0}, + {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, {NULL} }; @@ -2287,7 +2320,7 @@ }; static PyMemberDef bufferedrandom_members[] = { - {"raw", T_OBJECT, offsetof(buffered, raw), 0}, + {"raw", T_OBJECT, offsetof(buffered, raw), READONLY}, {NULL} }; Modified: python/branches/py3k-cdecimal/Modules/_lsprof.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_lsprof.c (original) +++ python/branches/py3k-cdecimal/Modules/_lsprof.c Sun Jan 2 13:18:37 2011 @@ -1,7 +1,5 @@ #include "Python.h" -#include "compile.h" #include "frameobject.h" -#include "structseq.h" #include "rotatingtree.h" #if !defined(HAVE_LONG_LONG) @@ -180,7 +178,16 @@ PyObject *mod = fn->m_module; const char *modname; if (mod && PyUnicode_Check(mod)) { + /* XXX: The following will truncate module names with embedded + * null-characters. It is unlikely that this can happen in + * practice and the concequences are not serious enough to + * introduce extra checks here. + */ modname = _PyUnicode_AsString(mod); + if (modname == NULL) { + modname = ""; + PyErr_Clear(); + } } else if (mod && PyModule_Check(mod)) { modname = PyModule_GetName(mod); Modified: python/branches/py3k-cdecimal/Modules/_posixsubprocess.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_posixsubprocess.c (original) +++ python/branches/py3k-cdecimal/Modules/_posixsubprocess.c Sun Jan 2 13:18:37 2011 @@ -1,6 +1,10 @@ /* Authors: Gregory P. Smith & Jeffrey Yasskin */ #include "Python.h" +#ifdef HAVE_PIPE2 +#define _GNU_SOURCE +#endif #include +#include #define POSIX_CALL(call) if ((call) == -1) goto error @@ -42,13 +46,14 @@ int errread, int errwrite, int errpipe_read, int errpipe_write, int close_fds, int restore_signals, - int call_setsid, + int call_setsid, Py_ssize_t num_fds_to_keep, + PyObject *py_fds_to_keep, PyObject *preexec_fn, PyObject *preexec_fn_args_tuple) { int i, saved_errno, fd_num; PyObject *result; - const char* err_msg; + const char* err_msg = ""; /* Buffer large enough to hold a hex integer. We can't malloc. */ char hex_errno[sizeof(saved_errno)*2+1]; @@ -91,11 +96,28 @@ /* close() is intentionally not checked for errors here as we are closing */ /* a large range of fds, some of which may be invalid. */ if (close_fds) { - for (fd_num = 3; fd_num < errpipe_write; ++fd_num) { - close(fd_num); - } - for (fd_num = errpipe_write+1; fd_num < max_fd; ++fd_num) { - close(fd_num); + Py_ssize_t keep_seq_idx; + int start_fd = 3; + for (keep_seq_idx = 0; keep_seq_idx < num_fds_to_keep; ++keep_seq_idx) { + PyObject* py_keep_fd = PySequence_Fast_GET_ITEM(py_fds_to_keep, + keep_seq_idx); + int keep_fd = PyLong_AsLong(py_keep_fd); + if (keep_fd < 0) { /* Negative number, overflow or not a Long. */ + err_msg = "bad value in fds_to_keep."; + errno = 0; /* We don't want to report an OSError. */ + goto error; + } + if (keep_fd < start_fd) + continue; + for (fd_num = start_fd; fd_num < keep_fd; ++fd_num) { + close(fd_num); + } + start_fd = keep_fd + 1; + } + if (start_fd <= max_fd) { + for (fd_num = start_fd; fd_num < max_fd; ++fd_num) { + close(fd_num); + } } } @@ -170,7 +192,7 @@ subprocess_fork_exec(PyObject* self, PyObject *args) { PyObject *gc_module = NULL; - PyObject *executable_list, *py_close_fds; + PyObject *executable_list, *py_close_fds, *py_fds_to_keep; PyObject *env_list, *preexec_fn; PyObject *process_args, *converted_args = NULL, *fast_args = NULL; PyObject *preexec_fn_args_tuple = NULL; @@ -182,11 +204,11 @@ pid_t pid; int need_to_reenable_gc = 0; char *const *exec_array, *const *argv = NULL, *const *envp = NULL; - Py_ssize_t arg_num; + Py_ssize_t arg_num, num_fds_to_keep; if (!PyArg_ParseTuple( - args, "OOOOOiiiiiiiiiiO:fork_exec", - &process_args, &executable_list, &py_close_fds, + args, "OOOOOOiiiiiiiiiiO:fork_exec", + &process_args, &executable_list, &py_close_fds, &py_fds_to_keep, &cwd_obj, &env_list, &p2cread, &p2cwrite, &c2pread, &c2pwrite, &errread, &errwrite, &errpipe_read, &errpipe_write, @@ -198,6 +220,11 @@ PyErr_SetString(PyExc_ValueError, "errpipe_write must be >= 3"); return NULL; } + num_fds_to_keep = PySequence_Length(py_fds_to_keep); + if (num_fds_to_keep < 0) { + PyErr_SetString(PyExc_ValueError, "bad fds_to_keep"); + return NULL; + } /* We need to call gc.disable() when we'll be calling preexec_fn */ if (preexec_fn != Py_None) { @@ -298,6 +325,7 @@ p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, close_fds, restore_signals, call_setsid, + num_fds_to_keep, py_fds_to_keep, preexec_fn, preexec_fn_args_tuple); _exit(255); return NULL; /* Dead code to avoid a potential compiler warning. */ @@ -374,6 +402,45 @@ Raises: Only on an error in the parent process.\n\ "); +PyDoc_STRVAR(subprocess_cloexec_pipe_doc, +"cloexec_pipe() -> (read_end, write_end)\n\n\ +Create a pipe whose ends have the cloexec flag set."); + +static PyObject * +subprocess_cloexec_pipe(PyObject *self, PyObject *noargs) +{ + int fds[2]; + int res; +#ifdef HAVE_PIPE2 + Py_BEGIN_ALLOW_THREADS + res = pipe2(fds, O_CLOEXEC); + Py_END_ALLOW_THREADS +#else + /* We hold the GIL which offers some protection from other code calling + * fork() before the CLOEXEC flags have been set but we can't guarantee + * anything without pipe2(). */ + long oldflags; + + res = pipe(fds); + + if (res == 0) { + oldflags = fcntl(fds[0], F_GETFD, 0); + if (oldflags < 0) res = oldflags; + } + if (res == 0) + res = fcntl(fds[0], F_SETFD, oldflags | FD_CLOEXEC); + + if (res == 0) { + oldflags = fcntl(fds[1], F_GETFD, 0); + if (oldflags < 0) res = oldflags; + } + if (res == 0) + res = fcntl(fds[1], F_SETFD, oldflags | FD_CLOEXEC); +#endif + if (res != 0) + return PyErr_SetFromErrno(PyExc_OSError); + return Py_BuildValue("(ii)", fds[0], fds[1]); +} /* module level code ********************************************************/ @@ -383,6 +450,7 @@ static PyMethodDef module_methods[] = { {"fork_exec", subprocess_fork_exec, METH_VARARGS, subprocess_fork_exec_doc}, + {"cloexec_pipe", subprocess_cloexec_pipe, METH_NOARGS, subprocess_cloexec_pipe_doc}, {NULL, NULL} /* sentinel */ }; Modified: python/branches/py3k-cdecimal/Modules/_ssl.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_ssl.c (original) +++ python/branches/py3k-cdecimal/Modules/_ssl.c Sun Jan 2 13:18:37 2011 @@ -370,7 +370,7 @@ sockstate = SOCKET_OPERATION_OK; } if (sockstate == SOCKET_HAS_TIMED_OUT) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(PySocketModule.timeout_error, ERRSTR("The handshake operation timed out")); goto error; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { @@ -928,10 +928,10 @@ char *cipher_protocol; if (self->ssl == NULL) - return Py_None; + Py_RETURN_NONE; current = SSL_get_current_cipher(self->ssl); if (current == NULL) - return Py_None; + Py_RETURN_NONE; retval = PyTuple_New(3); if (retval == NULL) @@ -939,6 +939,7 @@ cipher_name = (char *) SSL_CIPHER_get_name(current); if (cipher_name == NULL) { + Py_INCREF(Py_None); PyTuple_SET_ITEM(retval, 0, Py_None); } else { v = PyUnicode_FromString(cipher_name); @@ -948,6 +949,7 @@ } cipher_protocol = SSL_CIPHER_get_version(current); if (cipher_protocol == NULL) { + Py_INCREF(Py_None); PyTuple_SET_ITEM(retval, 1, Py_None); } else { v = PyUnicode_FromString(cipher_protocol); @@ -1075,7 +1077,7 @@ sockstate = check_socket_and_wait_for_timeout(sock, 1); if (sockstate == SOCKET_HAS_TIMED_OUT) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(PySocketModule.timeout_error, "The write operation timed out"); goto error; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { @@ -1104,7 +1106,7 @@ sockstate = SOCKET_OPERATION_OK; } if (sockstate == SOCKET_HAS_TIMED_OUT) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(PySocketModule.timeout_error, "The write operation timed out"); goto error; } else if (sockstate == SOCKET_HAS_BEEN_CLOSED) { @@ -1211,7 +1213,7 @@ if (!count) { sockstate = check_socket_and_wait_for_timeout(sock, 0); if (sockstate == SOCKET_HAS_TIMED_OUT) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(PySocketModule.timeout_error, "The read operation timed out"); goto error; } else if (sockstate == SOCKET_TOO_LARGE_FOR_SELECT) { @@ -1245,7 +1247,7 @@ sockstate = SOCKET_OPERATION_OK; } if (sockstate == SOCKET_HAS_TIMED_OUT) { - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(PySocketModule.timeout_error, "The read operation timed out"); goto error; } else if (sockstate == SOCKET_IS_NONBLOCKING) { @@ -1340,10 +1342,10 @@ break; if (sockstate == SOCKET_HAS_TIMED_OUT) { if (ssl_err == SSL_ERROR_WANT_READ) - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(PySocketModule.timeout_error, "The read operation timed out"); else - PyErr_SetString(PySSLErrorObject, + PyErr_SetString(PySocketModule.timeout_error, "The write operation timed out"); goto error; } Modified: python/branches/py3k-cdecimal/Modules/_struct.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_struct.c (original) +++ python/branches/py3k-cdecimal/Modules/_struct.c Sun Jan 2 13:18:37 2011 @@ -6,7 +6,6 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" -#include "structseq.h" #include "structmember.h" #include @@ -463,14 +462,9 @@ static int np_char(char *p, PyObject *v, const formatdef *f) { - if (PyUnicode_Check(v)) { - v = _PyUnicode_AsDefaultEncodedString(v, NULL); - if (v == NULL) - return -1; - } if (!PyBytes_Check(v) || PyBytes_Size(v) != 1) { PyErr_SetString(StructError, - "char format requires bytes or string of length 1"); + "char format requires a bytes object of length 1"); return -1; } *p = *PyBytes_AsString(v); @@ -1346,7 +1340,7 @@ if (!PyBytes_Check(o_format)) { Py_DECREF(o_format); PyErr_Format(PyExc_TypeError, - "Struct() argument 1 must be bytes, not %.200s", + "Struct() argument 1 must be a bytes object, not %.200s", Py_TYPE(o_format)->tp_name); return -1; } @@ -1424,7 +1418,7 @@ return NULL; if (vbuf.len != soself->s_size) { PyErr_Format(StructError, - "unpack requires a bytes argument of length %zd", + "unpack requires a bytes object of length %zd", soself->s_size); PyBuffer_Release(&vbuf); return NULL; @@ -1504,15 +1498,10 @@ if (e->format == 's') { int isstring; void *p; - if (PyUnicode_Check(v)) { - v = _PyUnicode_AsDefaultEncodedString(v, NULL); - if (v == NULL) - return -1; - } isstring = PyBytes_Check(v); if (!isstring && !PyByteArray_Check(v)) { PyErr_SetString(StructError, - "argument for 's' must be a bytes or string"); + "argument for 's' must be a bytes object"); return -1; } if (isstring) { @@ -1530,15 +1519,10 @@ } else if (e->format == 'p') { int isstring; void *p; - if (PyUnicode_Check(v)) { - v = _PyUnicode_AsDefaultEncodedString(v, NULL); - if (v == NULL) - return -1; - } isstring = PyBytes_Check(v); if (!isstring && !PyByteArray_Check(v)) { PyErr_SetString(StructError, - "argument for 'p' must be a bytes or string"); + "argument for 'p' must be a bytes object"); return -1; } if (isstring) { @@ -1692,7 +1676,7 @@ {NULL, NULL} /* sentinel */ }; -PyDoc_STRVAR(s__doc__, +PyDoc_STRVAR(s__doc__, "Struct(fmt) --> compiled struct object\n" "\n" "Return a new Struct object which writes and reads binary data according to\n" Modified: python/branches/py3k-cdecimal/Modules/_testcapimodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_testcapimodule.c (original) +++ python/branches/py3k-cdecimal/Modules/_testcapimodule.c Sun Jan 2 13:18:37 2011 @@ -1398,7 +1398,7 @@ if (buffer == NULL) return PyErr_NoMemory(); - size = PyUnicode_AsWideChar((PyUnicodeObject*)unicode, buffer, buflen); + size = PyUnicode_AsWideChar(unicode, buffer, buflen); if (size == -1) { PyMem_Free(buffer); return NULL; @@ -1741,15 +1741,16 @@ { PyObject *result; char *msg; + static const Py_UNICODE one[] = {'1', 0}; -#define CHECK_1_FORMAT(FORMAT, TYPE) \ - result = PyUnicode_FromFormat(FORMAT, (TYPE)1); \ - if (result == NULL) \ - return NULL; \ - if (strcmp(_PyUnicode_AsString(result), "1")) { \ - msg = FORMAT " failed at 1"; \ - goto Fail; \ - } \ +#define CHECK_1_FORMAT(FORMAT, TYPE) \ + result = PyUnicode_FromFormat(FORMAT, (TYPE)1); \ + if (result == NULL) \ + return NULL; \ + if (Py_UNICODE_strcmp(PyUnicode_AS_UNICODE(result), one)) { \ + msg = FORMAT " failed at 1"; \ + goto Fail; \ + } \ Py_DECREF(result) CHECK_1_FORMAT("%d", int); Modified: python/branches/py3k-cdecimal/Modules/_threadmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/_threadmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/_threadmodule.c Sun Jan 2 13:18:37 2011 @@ -40,6 +40,58 @@ PyObject_Del(self); } +/* Helper to acquire an interruptible lock with a timeout. If the lock acquire + * is interrupted, signal handlers are run, and if they raise an exception, + * PY_LOCK_INTR is returned. Otherwise, PY_LOCK_ACQUIRED or PY_LOCK_FAILURE + * are returned, depending on whether the lock can be acquired withing the + * timeout. + */ +static PyLockStatus +acquire_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) +{ + PyLockStatus r; + _PyTime_timeval curtime; + _PyTime_timeval endtime; + + if (microseconds > 0) { + _PyTime_gettimeofday(&endtime); + endtime.tv_sec += microseconds / (1000 * 1000); + endtime.tv_usec += microseconds % (1000 * 1000); + } + + + do { + Py_BEGIN_ALLOW_THREADS + r = PyThread_acquire_lock_timed(lock, microseconds, 1); + Py_END_ALLOW_THREADS + + if (r == PY_LOCK_INTR) { + /* Run signal handlers if we were interrupted. Propagate + * exceptions from signal handlers, such as KeyboardInterrupt, by + * passing up PY_LOCK_INTR. */ + if (Py_MakePendingCalls() < 0) { + return PY_LOCK_INTR; + } + + /* If we're using a timeout, recompute the timeout after processing + * signals, since those can take time. */ + if (microseconds >= 0) { + _PyTime_gettimeofday(&curtime); + microseconds = ((endtime.tv_sec - curtime.tv_sec) * 1000000 + + (endtime.tv_usec - curtime.tv_usec)); + + /* Check for negative values, since those mean block forever. + */ + if (microseconds <= 0) { + r = PY_LOCK_FAILURE; + } + } + } + } while (r == PY_LOCK_INTR); /* Retry if we were interrupted. */ + + return r; +} + static PyObject * lock_PyThread_acquire_lock(lockobject *self, PyObject *args, PyObject *kwds) { @@ -47,7 +99,7 @@ int blocking = 1; double timeout = -1; PY_TIMEOUT_T microseconds; - int r; + PyLockStatus r; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|id:acquire", kwlist, &blocking, &timeout)) @@ -77,11 +129,12 @@ microseconds = (PY_TIMEOUT_T) timeout; } - Py_BEGIN_ALLOW_THREADS - r = PyThread_acquire_lock_timed(self->lock_lock, microseconds); - Py_END_ALLOW_THREADS + r = acquire_timed(self->lock_lock, microseconds); + if (r == PY_LOCK_INTR) { + return NULL; + } - return PyBool_FromLong(r); + return PyBool_FromLong(r == PY_LOCK_ACQUIRED); } PyDoc_STRVAR(acquire_doc, @@ -93,7 +146,7 @@ the lock, and return None once the lock is acquired.\n\ With an argument, this will only block if the argument is true,\n\ and the return value reflects whether the lock is acquired.\n\ -The blocking operation is not interruptible."); +The blocking operation is interruptible."); static PyObject * lock_PyThread_release_lock(lockobject *self) @@ -218,7 +271,7 @@ double timeout = -1; PY_TIMEOUT_T microseconds; long tid; - int r = 1; + PyLockStatus r = PY_LOCK_ACQUIRED; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|id:acquire", kwlist, &blocking, &timeout)) @@ -265,17 +318,18 @@ if (microseconds == 0) { Py_RETURN_FALSE; } - Py_BEGIN_ALLOW_THREADS - r = PyThread_acquire_lock_timed(self->rlock_lock, microseconds); - Py_END_ALLOW_THREADS + r = acquire_timed(self->rlock_lock, microseconds); } - if (r) { + if (r == PY_LOCK_ACQUIRED) { assert(self->rlock_count == 0); self->rlock_owner = tid; self->rlock_count = 1; } + else if (r == PY_LOCK_INTR) { + return NULL; + } - return PyBool_FromLong(r); + return PyBool_FromLong(r == PY_LOCK_ACQUIRED); } PyDoc_STRVAR(rlock_acquire_doc, @@ -287,7 +341,7 @@ immediately. If `blocking` is True and another thread holds\n\ the lock, the method will wait for the lock to be released,\n\ take it and then return True.\n\ -(note: the blocking operation is not interruptible.)\n\ +(note: the blocking operation is interruptible.)\n\ \n\ In all other cases, the method will return True immediately.\n\ Precisely, if the current thread already holds the lock, its\n\ Modified: python/branches/py3k-cdecimal/Modules/arraymodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/arraymodule.c (original) +++ python/branches/py3k-cdecimal/Modules/arraymodule.c Sun Jan 2 13:18:37 2011 @@ -674,11 +674,9 @@ static PyObject * array_repeat(arrayobject *a, Py_ssize_t n) { - Py_ssize_t i; Py_ssize_t size; arrayobject *np; - char *p; - Py_ssize_t nbytes; + Py_ssize_t oldbytes, newbytes; if (n < 0) n = 0; if ((Py_SIZE(a) != 0) && (n > PY_SSIZE_T_MAX / Py_SIZE(a))) { @@ -688,13 +686,23 @@ np = (arrayobject *) newarrayobject(&Arraytype, size, a->ob_descr); if (np == NULL) return NULL; - p = np->ob_item; - nbytes = Py_SIZE(a) * a->ob_descr->itemsize; - for (i = 0; i < n; i++) { - memcpy(p, a->ob_item, nbytes); - p += nbytes; + if (n == 0) + return (PyObject *)np; + oldbytes = Py_SIZE(a) * a->ob_descr->itemsize; + newbytes = oldbytes * n; + /* this follows the code in unicode_repeat */ + if (oldbytes == 1) { + memset(np->ob_item, a->ob_item[0], newbytes); + } else { + Py_ssize_t done = oldbytes; + Py_MEMCPY(np->ob_item, a->ob_item, oldbytes); + while (done < newbytes) { + Py_ssize_t ncopy = (done <= newbytes-done) ? done : newbytes-done; + Py_MEMCPY(np->ob_item+done, np->ob_item, ncopy); + done += ncopy; + } } - return (PyObject *) np; + return (PyObject *)np; } static int @@ -1448,7 +1456,7 @@ { Py_UNICODE *ustr; Py_ssize_t n; - char typecode; + Py_UNICODE typecode; if (!PyArg_ParseTuple(args, "u#:fromunicode", &ustr, &n)) return NULL; @@ -1483,7 +1491,7 @@ static PyObject * array_tounicode(arrayobject *self, PyObject *unused) { - char typecode; + Py_UNICODE typecode; typecode = self->ob_descr->typecode; if ((typecode != 'u')) { PyErr_SetString(PyExc_ValueError, @@ -2002,8 +2010,8 @@ static PyObject * array_get_typecode(arrayobject *a, void *closure) { - char tc = a->ob_descr->typecode; - return PyUnicode_FromStringAndSize(&tc, 1); + Py_UNICODE tc = a->ob_descr->typecode; + return PyUnicode_FromUnicode(&tc, 1); } static PyObject * @@ -2075,21 +2083,21 @@ static PyObject * array_repr(arrayobject *a) { - char typecode; + Py_UNICODE typecode; PyObject *s, *v = NULL; Py_ssize_t len; len = Py_SIZE(a); typecode = a->ob_descr->typecode; if (len == 0) { - return PyUnicode_FromFormat("array('%c')", typecode); + return PyUnicode_FromFormat("array('%c')", (int)typecode); } if ((typecode == 'u')) v = array_tounicode(a, NULL); else v = array_tolist(a, NULL); - s = PyUnicode_FromFormat("array('%c', %R)", typecode, v); + s = PyUnicode_FromFormat("array('%c', %R)", (int)typecode, v); Py_DECREF(v); return s; } @@ -2112,7 +2120,7 @@ arrayobject* ar; int itemsize = self->ob_descr->itemsize; - if (PySlice_GetIndicesEx((PySliceObject*)item, Py_SIZE(self), + if (PySlice_GetIndicesEx(item, Py_SIZE(self), &start, &stop, &step, &slicelength) < 0) { return NULL; } @@ -2183,7 +2191,7 @@ return (*self->ob_descr->setitem)(self, i, value); } else if (PySlice_Check(item)) { - if (PySlice_GetIndicesEx((PySliceObject *)item, + if (PySlice_GetIndicesEx(item, Py_SIZE(self), &start, &stop, &step, &slicelength) < 0) { return -1; Modified: python/branches/py3k-cdecimal/Modules/getpath.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/getpath.c (original) +++ python/branches/py3k-cdecimal/Modules/getpath.c Sun Jan 2 13:18:37 2011 @@ -361,7 +361,7 @@ decoded = PyUnicode_DecodeUTF8(buf, n, "surrogateescape"); if (decoded != NULL) { Py_ssize_t k; - k = PyUnicode_AsWideChar((PyUnicodeObject*)decoded, + k = PyUnicode_AsWideChar(decoded, rel_builddir_path, MAXPATHLEN); Py_DECREF(decoded); if (k >= 0) { Modified: python/branches/py3k-cdecimal/Modules/grpmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/grpmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/grpmodule.c Sun Jan 2 13:18:37 2011 @@ -2,7 +2,6 @@ /* UNIX group file access module */ #include "Python.h" -#include "structseq.h" #include #include @@ -160,7 +159,9 @@ name is not valid, raise KeyError."}, {"getgrall", grp_getgrall, METH_NOARGS, "getgrall() -> list of tuples\n\ -Return a list of all available group entries, in arbitrary order."}, +Return a list of all available group entries, in arbitrary order.\n\ +An entry whose name starts with '+' or '-' represents an instruction\n\ +to use YP/NIS and may not be accessible via getgrnam or getgrgid."}, {NULL, NULL} /* sentinel */ }; Modified: python/branches/py3k-cdecimal/Modules/itertoolsmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/itertoolsmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/itertoolsmodule.c Sun Jan 2 13:18:37 2011 @@ -1215,6 +1215,7 @@ { PyObject *item; PyObject *it = lz->it; + Py_ssize_t stop = lz->stop; Py_ssize_t oldnext; PyObject *(*iternext)(PyObject *); @@ -1226,7 +1227,7 @@ Py_DECREF(item); lz->cnt++; } - if (lz->stop != -1 && lz->cnt >= lz->stop) + if (stop != -1 && lz->cnt >= stop) return NULL; item = iternext(it); if (item == NULL) @@ -1234,8 +1235,8 @@ lz->cnt++; oldnext = lz->next; lz->next += lz->step; - if (lz->next < oldnext) /* Check for overflow */ - lz->next = lz->stop; + if (lz->next < oldnext || (stop != -1 && lz->next > stop)) + lz->next = stop; return item; } @@ -2583,6 +2584,138 @@ PyObject_GC_Del, /* tp_free */ }; +/* accumulate object ************************************************************/ + +typedef struct { + PyObject_HEAD + PyObject *total; + PyObject *it; +} accumulateobject; + +static PyTypeObject accumulate_type; + +static PyObject * +accumulate_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + static char *kwargs[] = {"iterable", NULL}; + PyObject *iterable; + PyObject *it; + accumulateobject *lz; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:accumulate", kwargs, &iterable)) + return NULL; + + /* Get iterator. */ + it = PyObject_GetIter(iterable); + if (it == NULL) + return NULL; + + /* create accumulateobject structure */ + lz = (accumulateobject *)type->tp_alloc(type, 0); + if (lz == NULL) { + Py_DECREF(it); + return NULL; + } + + lz->total = NULL; + lz->it = it; + return (PyObject *)lz; +} + +static void +accumulate_dealloc(accumulateobject *lz) +{ + PyObject_GC_UnTrack(lz); + Py_XDECREF(lz->total); + Py_XDECREF(lz->it); + Py_TYPE(lz)->tp_free(lz); +} + +static int +accumulate_traverse(accumulateobject *lz, visitproc visit, void *arg) +{ + Py_VISIT(lz->it); + Py_VISIT(lz->total); + return 0; +} + +static PyObject * +accumulate_next(accumulateobject *lz) +{ + PyObject *val, *oldtotal, *newtotal; + + val = PyIter_Next(lz->it); + if (val == NULL) + return NULL; + + if (lz->total == NULL) { + Py_INCREF(val); + lz->total = val; + return lz->total; + } + + newtotal = PyNumber_Add(lz->total, val); + Py_DECREF(val); + if (newtotal == NULL) + return NULL; + + oldtotal = lz->total; + lz->total = newtotal; + Py_DECREF(oldtotal); + + Py_INCREF(newtotal); + return newtotal; +} + +PyDoc_STRVAR(accumulate_doc, +"accumulate(iterable) --> accumulate object\n\ +\n\ +Return series of accumulated sums."); + +static PyTypeObject accumulate_type = { + PyVarObject_HEAD_INIT(NULL, 0) + "itertools.accumulate", /* tp_name */ + sizeof(accumulateobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)accumulate_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + accumulate_doc, /* tp_doc */ + (traverseproc)accumulate_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)accumulate_next, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + accumulate_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ +}; + /* compress object ************************************************************/ @@ -3495,6 +3628,7 @@ repeat(elem [,n]) --> elem, elem, elem, ... endlessly or up to n times\n\ \n\ Iterators terminating on the shortest input sequence:\n\ +accumulate(p, start=0) --> p0, p0+p1, p0+p1+p2\n\ chain(p, q, ...) --> p0, p1, ... plast, q0, q1, ... \n\ compress(data, selectors) --> (d[0] if s[0]), (d[1] if s[1]), ...\n\ dropwhile(pred, seq) --> seq[n], seq[n+1], starting when pred fails\n\ @@ -3540,6 +3674,7 @@ PyObject *m; char *name; PyTypeObject *typelist[] = { + &accumulate_type, &combinations_type, &cwr_type, &cycle_type, Modified: python/branches/py3k-cdecimal/Modules/main.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/main.c (original) +++ python/branches/py3k-cdecimal/Modules/main.c Sun Jan 2 13:18:37 2011 @@ -2,7 +2,6 @@ #include "Python.h" #include "osdefs.h" -#include "import.h" #include @@ -47,7 +46,7 @@ static int orig_argc; /* command line options */ -#define BASE_OPTS L"bBc:dEhiJm:OsStuvVW:xX:?" +#define BASE_OPTS L"bBc:dEhiJm:OqsStuvVW:xX:?" #define PROGRAM_OPTS BASE_OPTS @@ -72,6 +71,7 @@ -m mod : run library module as a script (terminates option list)\n\ -O : optimize generated bytecode slightly; also PYTHONOPTIMIZE=x\n\ -OO : remove doc-strings in addition to the -O optimizations\n\ +-q : don't print version and copyright messages on interactive startup\n\ -s : don't add user site directory to sys.path; also PYTHONNOUSERSITE\n\ -S : don't imply 'import site' on initialization\n\ "; @@ -425,6 +425,10 @@ PySys_AddXOption(_PyOS_optarg); break; + case 'q': + Py_QuietFlag++; + break; + /* This space reserved for other options */ default: @@ -589,8 +593,9 @@ #endif Py_Initialize(); - if (Py_VerboseFlag || - (command == NULL && filename == NULL && module == NULL && stdin_is_interactive)) { + if (!Py_QuietFlag && (Py_VerboseFlag || + (command == NULL && filename == NULL && + module == NULL && stdin_is_interactive))) { fprintf(stderr, "Python %s on %s\n", Py_GetVersion(), Py_GetPlatform()); if (!Py_NoSiteFlag) Modified: python/branches/py3k-cdecimal/Modules/mmapmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/mmapmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/mmapmodule.c Sun Jan 2 13:18:37 2011 @@ -762,7 +762,7 @@ else if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelen; - if (PySlice_GetIndicesEx((PySliceObject *)item, self->size, + if (PySlice_GetIndicesEx(item, self->size, &start, &stop, &step, &slicelen) < 0) { return NULL; } @@ -888,7 +888,7 @@ Py_ssize_t start, stop, step, slicelen; Py_buffer vbuf; - if (PySlice_GetIndicesEx((PySliceObject *)item, + if (PySlice_GetIndicesEx(item, self->size, &start, &stop, &step, &slicelen) < 0) { return -1; Modified: python/branches/py3k-cdecimal/Modules/parsermodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/parsermodule.c (original) +++ python/branches/py3k-cdecimal/Modules/parsermodule.c Sun Jan 2 13:18:37 2011 @@ -34,10 +34,8 @@ #include "grammar.h" #include "parsetok.h" /* ISTERMINAL() / ISNONTERMINAL() */ -#include "compile.h" #undef Yield #include "ast.h" -#include "pyarena.h" extern grammar _PyParser_Grammar; /* From graminit.c */ @@ -794,6 +792,11 @@ } } temp_str = _PyUnicode_AsStringAndSize(temp, &len); + if (temp_str == NULL) { + Py_DECREF(temp); + Py_XDECREF(elem); + return 0; + } strn = (char *)PyObject_MALLOC(len + 1); if (strn != NULL) (void) memcpy(strn, temp_str, len + 1); @@ -872,6 +875,8 @@ encoding = PySequence_GetItem(tuple, 2); /* tuple isn't borrowed anymore here, need to DECREF */ tuple = PySequence_GetSlice(tuple, 0, 2); + if (tuple == NULL) + return NULL; } res = PyNode_New(num); if (res != NULL) { @@ -883,6 +888,12 @@ Py_ssize_t len; const char *temp; temp = _PyUnicode_AsStringAndSize(encoding, &len); + if (temp == NULL) { + Py_DECREF(res); + Py_DECREF(encoding); + Py_DECREF(tuple); + return NULL; + } res->n_str = (char *)PyObject_MALLOC(len + 1); if (res->n_str != NULL && temp != NULL) (void) memcpy(res->n_str, temp, len + 1); Modified: python/branches/py3k-cdecimal/Modules/posixmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/posixmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/posixmodule.c Sun Jan 2 13:18:37 2011 @@ -28,7 +28,6 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" -#include "structseq.h" #if defined(__VMS) # include @@ -278,6 +277,10 @@ #include #include /* for ShellExecute() */ #include /* for UNLEN */ +#ifdef SE_CREATE_SYMBOLIC_LINK_NAME /* Available starting with Vista */ +#define HAVE_SYMLINK +static int win32_can_symlink = 0; +#endif #endif /* _MSC_VER */ #if defined(PYCC_VACPP) && defined(PYOS_OS2) @@ -437,6 +440,98 @@ #define _PyVerify_fd_dup2(A, B) (1) #endif +#ifdef MS_WINDOWS +/* The following structure was copied from + http://msdn.microsoft.com/en-us/library/ms791514.aspx as the required + include doesn't seem to be present in the Windows SDK (at least as included + with Visual Studio Express). */ +typedef struct _REPARSE_DATA_BUFFER { + ULONG ReparseTag; + USHORT ReparseDataLength; + USHORT Reserved; + union { + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + ULONG Flags; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + + struct { + USHORT SubstituteNameOffset; + USHORT SubstituteNameLength; + USHORT PrintNameOffset; + USHORT PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + + struct { + UCHAR DataBuffer[1]; + } GenericReparseBuffer; + }; +} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; + +#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER,\ + GenericReparseBuffer) +#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 ) + +static int +win32_read_link(HANDLE reparse_point_handle, ULONG *reparse_tag, wchar_t **target_path) +{ + char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer; + DWORD n_bytes_returned; + const wchar_t *ptr; + wchar_t *buf; + size_t len; + + if (0 == DeviceIoControl( + reparse_point_handle, + FSCTL_GET_REPARSE_POINT, + NULL, 0, /* in buffer */ + target_buffer, sizeof(target_buffer), + &n_bytes_returned, + NULL)) /* we're not using OVERLAPPED_IO */ + return -1; + + if (reparse_tag) + *reparse_tag = rdb->ReparseTag; + + if (target_path) { + switch (rdb->ReparseTag) { + case IO_REPARSE_TAG_SYMLINK: + /* XXX: Maybe should use SubstituteName? */ + ptr = rdb->SymbolicLinkReparseBuffer.PathBuffer + + rdb->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR); + len = rdb->SymbolicLinkReparseBuffer.PrintNameLength/sizeof(WCHAR); + break; + case IO_REPARSE_TAG_MOUNT_POINT: + ptr = rdb->MountPointReparseBuffer.PathBuffer + + rdb->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR); + len = rdb->MountPointReparseBuffer.SubstituteNameLength/sizeof(WCHAR); + break; + default: + SetLastError(ERROR_REPARSE_TAG_MISMATCH); /* XXX: Proper error code? */ + return -1; + } + buf = (wchar_t *)malloc(sizeof(wchar_t)*(len+1)); + if (!buf) { + SetLastError(ERROR_OUTOFMEMORY); + return -1; + } + wcsncpy(buf, ptr, len); + buf[len] = L'\0'; + if (wcsncmp(buf, L"\\??\\", 4) == 0) + buf[1] = L'\\'; + *target_path = buf; + } + + return 0; +} +#endif /* MS_WINDOWS */ + /* Return a dictionary corresponding to the POSIX environment table */ #ifdef WITH_NEXT_FRAMEWORK /* On Darwin/MacOSX a shared library or framework has no access to @@ -934,7 +1029,7 @@ } static int -attribute_data_to_stat(WIN32_FILE_ATTRIBUTE_DATA *info, struct win32_stat *result) +attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct win32_stat *result) { memset(result, 0, sizeof(*result)); result->st_mode = attributes_to_mode(info->dwFileAttributes); @@ -942,12 +1037,20 @@ FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec); FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); + result->st_nlink = info->nNumberOfLinks; + result->st_ino = (((__int64)info->nFileIndexHigh)<<32) + info->nFileIndexLow; + if (reparse_tag == IO_REPARSE_TAG_SYMLINK) { + /* first clear the S_IFMT bits */ + result->st_mode ^= (result->st_mode & 0170000); + /* now set the bits that make this a symlink */ + result->st_mode |= 0120000; + } return 0; } static BOOL -attributes_from_dir(LPCSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad) +attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag) { HANDLE hFindFile; WIN32_FIND_DATAA FileData; @@ -955,17 +1058,22 @@ if (hFindFile == INVALID_HANDLE_VALUE) return FALSE; FindClose(hFindFile); - pfad->dwFileAttributes = FileData.dwFileAttributes; - pfad->ftCreationTime = FileData.ftCreationTime; - pfad->ftLastAccessTime = FileData.ftLastAccessTime; - pfad->ftLastWriteTime = FileData.ftLastWriteTime; - pfad->nFileSizeHigh = FileData.nFileSizeHigh; - pfad->nFileSizeLow = FileData.nFileSizeLow; + memset(info, 0, sizeof(*info)); + *reparse_tag = 0; + info->dwFileAttributes = FileData.dwFileAttributes; + info->ftCreationTime = FileData.ftCreationTime; + info->ftLastAccessTime = FileData.ftLastAccessTime; + info->ftLastWriteTime = FileData.ftLastWriteTime; + info->nFileSizeHigh = FileData.nFileSizeHigh; + info->nFileSizeLow = FileData.nFileSizeLow; +/* info->nNumberOfLinks = 1; */ + if (FileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + *reparse_tag = FileData.dwReserved0; return TRUE; } static BOOL -attributes_from_dir_w(LPCWSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad) +attributes_from_dir_w(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag) { HANDLE hFindFile; WIN32_FIND_DATAW FileData; @@ -973,178 +1081,40 @@ if (hFindFile == INVALID_HANDLE_VALUE) return FALSE; FindClose(hFindFile); - pfad->dwFileAttributes = FileData.dwFileAttributes; - pfad->ftCreationTime = FileData.ftCreationTime; - pfad->ftLastAccessTime = FileData.ftLastAccessTime; - pfad->ftLastWriteTime = FileData.ftLastWriteTime; - pfad->nFileSizeHigh = FileData.nFileSizeHigh; - pfad->nFileSizeLow = FileData.nFileSizeLow; + memset(info, 0, sizeof(*info)); + *reparse_tag = 0; + info->dwFileAttributes = FileData.dwFileAttributes; + info->ftCreationTime = FileData.ftCreationTime; + info->ftLastAccessTime = FileData.ftLastAccessTime; + info->ftLastWriteTime = FileData.ftLastWriteTime; + info->nFileSizeHigh = FileData.nFileSizeHigh; + info->nFileSizeLow = FileData.nFileSizeLow; +/* info->nNumberOfLinks = 1; */ + if (FileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + *reparse_tag = FileData.dwReserved0; return TRUE; } -/* About the following functions: win32_lstat, win32_lstat_w, win32_stat, - win32_stat_w - - In Posix, stat automatically traverses symlinks and returns the stat - structure for the target. In Windows, the equivalent GetFileAttributes by - default does not traverse symlinks and instead returns attributes for - the symlink. - - Therefore, win32_lstat will get the attributes traditionally, and - win32_stat will first explicitly resolve the symlink target and then will - call win32_lstat on that result. - - The _w represent Unicode equivalents of the aformentioned ANSI functions. */ - -static int -win32_lstat(const char* path, struct win32_stat *result) -{ - WIN32_FILE_ATTRIBUTE_DATA info; - int code; - char *dot; - WIN32_FIND_DATAA find_data; - HANDLE find_data_handle; - if (!GetFileAttributesExA(path, GetFileExInfoStandard, &info)) { - if (GetLastError() != ERROR_SHARING_VIOLATION) { - /* Protocol violation: we explicitly clear errno, instead of - setting it to a POSIX error. Callers should use GetLastError. */ - errno = 0; - return -1; - } else { - /* Could not get attributes on open file. Fall back to - reading the directory. */ - if (!attributes_from_dir(path, &info)) { - /* Very strange. This should not fail now */ - errno = 0; - return -1; - } - } - } - - code = attribute_data_to_stat(&info, result); - if (code != 0) - return code; - - /* Get WIN32_FIND_DATA structure for the path to determine if - it is a symlink */ - if(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - find_data_handle = FindFirstFileA(path, &find_data); - if(find_data_handle != INVALID_HANDLE_VALUE) { - if(find_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) { - /* first clear the S_IFMT bits */ - result->st_mode ^= (result->st_mode & 0170000); - /* now set the bits that make this a symlink */ - result->st_mode |= 0120000; - } - FindClose(find_data_handle); - } - } - - /* Set S_IFEXEC if it is an .exe, .bat, ... */ - dot = strrchr(path, '.'); - if (dot) { - if (stricmp(dot, ".bat") == 0 || stricmp(dot, ".cmd") == 0 || - stricmp(dot, ".exe") == 0 || stricmp(dot, ".com") == 0) - result->st_mode |= 0111; - } - return code; -} - -static int -win32_lstat_w(const wchar_t* path, struct win32_stat *result) -{ - int code; - const wchar_t *dot; - WIN32_FILE_ATTRIBUTE_DATA info; - WIN32_FIND_DATAW find_data; - HANDLE find_data_handle; - if (!GetFileAttributesExW(path, GetFileExInfoStandard, &info)) { - if (GetLastError() != ERROR_SHARING_VIOLATION) { - /* Protocol violation: we explicitly clear errno, instead of - setting it to a POSIX error. Callers should use GetLastError. */ - errno = 0; - return -1; - } else { - /* Could not get attributes on open file. Fall back to reading - the directory. */ - if (!attributes_from_dir_w(path, &info)) { - /* Very strange. This should not fail now */ - errno = 0; - return -1; - } - } - } - code = attribute_data_to_stat(&info, result); - if (code < 0) - return code; - - /* Get WIN32_FIND_DATA structure for the path to determine if - it is a symlink */ - if(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { - find_data_handle = FindFirstFileW(path, &find_data); - if(find_data_handle != INVALID_HANDLE_VALUE) { - if(find_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK) { - /* first clear the S_IFMT bits */ - result->st_mode ^= (result->st_mode & 0170000); - /* now set the bits that make this a symlink */ - result->st_mode |= 0120000; - } - FindClose(find_data_handle); - } - } - - /* Set IFEXEC if it is an .exe, .bat, ... */ - dot = wcsrchr(path, '.'); - if (dot) { - if (_wcsicmp(dot, L".bat") == 0 || _wcsicmp(dot, L".cmd") == 0 || - _wcsicmp(dot, L".exe") == 0 || _wcsicmp(dot, L".com") == 0) - result->st_mode |= 0111; - } - return code; -} +#ifndef SYMLOOP_MAX +#define SYMLOOP_MAX ( 88 ) +#endif -/* Grab GetFinalPathNameByHandle dynamically from kernel32 */ -static int has_GetFinalPathNameByHandle = 0; -static DWORD (CALLBACK *Py_GetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD, - DWORD); -static DWORD (CALLBACK *Py_GetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD, - DWORD); static int -check_GetFinalPathNameByHandle() -{ - HINSTANCE hKernel32; - /* only recheck */ - if (!has_GetFinalPathNameByHandle) - { - hKernel32 = GetModuleHandle("KERNEL32"); - *(FARPROC*)&Py_GetFinalPathNameByHandleA = GetProcAddress(hKernel32, - "GetFinalPathNameByHandleA"); - *(FARPROC*)&Py_GetFinalPathNameByHandleW = GetProcAddress(hKernel32, - "GetFinalPathNameByHandleW"); - has_GetFinalPathNameByHandle = Py_GetFinalPathNameByHandleA && - Py_GetFinalPathNameByHandleW; - } - return has_GetFinalPathNameByHandle; -} +win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, BOOL traverse, int depth); static int -win32_stat(const char* path, struct win32_stat *result) +win32_xstat_impl(const char *path, struct win32_stat *result, BOOL traverse, int depth) { - /* Traverse the symlink to the target using - GetFinalPathNameByHandle() - */ int code; HANDLE hFile; - int buf_size; - char *target_path; - int result_length; - WIN32_FILE_ATTRIBUTE_DATA info; - - if(!check_GetFinalPathNameByHandle()) { - /* if the OS doesn't have GetFinalPathNameByHandle, it doesn't - have symlinks, so just fall back to the traditional behavior - found in lstat. */ - return win32_lstat(path, result); + BY_HANDLE_FILE_INFORMATION info; + ULONG reparse_tag = 0; + wchar_t *target_path; + const char *dot; + + if (depth > SYMLOOP_MAX) { + SetLastError(ERROR_CANT_RESOLVE_FILENAME); /* XXX: ELOOP? */ + return -1; } hFile = CreateFileA( @@ -1154,75 +1124,70 @@ NULL, /* security attributes */ OPEN_EXISTING, /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */ - FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT, NULL); - - if(hFile == INVALID_HANDLE_VALUE) { + + if (hFile == INVALID_HANDLE_VALUE) { /* Either the target doesn't exist, or we don't have access to get a handle to it. If the former, we need to return an error. If the latter, we can use attributes_from_dir. */ - if (GetLastError() != ERROR_SHARING_VIOLATION) { - /* Protocol violation: we explicitly clear errno, instead of - setting it to a POSIX error. Callers should use GetLastError. */ - errno = 0; + if (GetLastError() != ERROR_SHARING_VIOLATION) return -1; - } else { - /* Could not get attributes on open file. Fall back to - reading the directory. */ - if (!attributes_from_dir(path, &info)) { - /* Very strange. This should not fail now */ - errno = 0; + /* Could not get attributes on open file. Fall back to + reading the directory. */ + if (!attributes_from_dir(path, &info, &reparse_tag)) + /* Very strange. This should not fail now */ + return -1; + if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + if (traverse) { + /* Should traverse, but could not open reparse point handle */ + SetLastError(ERROR_SHARING_VIOLATION); return -1; } } - code = attribute_data_to_stat(&info, result); + } else { + if (!GetFileInformationByHandle(hFile, &info)) { + CloseHandle(hFile); + return -1;; + } + if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + code = win32_read_link(hFile, &reparse_tag, traverse ? &target_path : NULL); + CloseHandle(hFile); + if (code < 0) + return code; + if (traverse) { + code = win32_xstat_impl_w(target_path, result, traverse, depth + 1); + free(target_path); + return code; + } + } else + CloseHandle(hFile); } - else { - /* We have a good handle to the target, use it to determine the target - path name (then we'll call lstat on it). */ - buf_size = Py_GetFinalPathNameByHandleA(hFile, 0, 0, VOLUME_NAME_DOS); - if(!buf_size) return -1; - /* Due to a slight discrepancy between GetFinalPathNameByHandleA - and GetFinalPathNameByHandleW, we must allocate one more byte - than reported. */ - target_path = (char *)malloc((buf_size+2)*sizeof(char)); - result_length = Py_GetFinalPathNameByHandleA(hFile, target_path, - buf_size+1, VOLUME_NAME_DOS); + attribute_data_to_stat(&info, reparse_tag, result); - if(!result_length) { - free(target_path); - return -1; - } - - if(!CloseHandle(hFile)) { - free(target_path); - return -1; - } - - target_path[result_length] = 0; - code = win32_lstat(target_path, result); - free(target_path); + /* Set S_IEXEC if it is an .exe, .bat, ... */ + dot = strrchr(path, '.'); + if (dot) { + if (stricmp(dot, ".bat") == 0 || stricmp(dot, ".cmd") == 0 || + stricmp(dot, ".exe") == 0 || stricmp(dot, ".com") == 0) + result->st_mode |= 0111; } - - return code; + return 0; } -static int -win32_stat_w(const wchar_t* path, struct win32_stat *result) +static int +win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, BOOL traverse, int depth) { - /* Traverse the symlink to the target using GetFinalPathNameByHandle() */ int code; HANDLE hFile; - int buf_size; - wchar_t *target_path; - int result_length; - WIN32_FILE_ATTRIBUTE_DATA info; - - if(!check_GetFinalPathNameByHandle()) { - /* If the OS doesn't have GetFinalPathNameByHandle, it doesn't have - symlinks, so just fall back to the traditional behavior found - in lstat. */ - return win32_lstat_w(path, result); + BY_HANDLE_FILE_INFORMATION info; + ULONG reparse_tag = 0; + wchar_t *target_path; + const wchar_t *dot; + + if (depth > SYMLOOP_MAX) { + SetLastError(ERROR_CANT_RESOLVE_FILENAME); /* XXX: ELOOP? */ + return -1; } hFile = CreateFileW( @@ -1232,58 +1197,115 @@ NULL, /* security attributes */ OPEN_EXISTING, /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */ - FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT, NULL); - if(hFile == INVALID_HANDLE_VALUE) { + if (hFile == INVALID_HANDLE_VALUE) { /* Either the target doesn't exist, or we don't have access to get a handle to it. If the former, we need to return an error. If the latter, we can use attributes_from_dir. */ - if (GetLastError() != ERROR_SHARING_VIOLATION) { - /* Protocol violation: we explicitly clear errno, instead of - setting it to a POSIX error. Callers should use GetLastError. */ - errno = 0; + if (GetLastError() != ERROR_SHARING_VIOLATION) return -1; - } else { - /* Could not get attributes on open file. Fall back to - reading the directory. */ - if (!attributes_from_dir_w(path, &info)) { - /* Very strange. This should not fail now */ - errno = 0; + /* Could not get attributes on open file. Fall back to + reading the directory. */ + if (!attributes_from_dir_w(path, &info, &reparse_tag)) + /* Very strange. This should not fail now */ + return -1; + if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + if (traverse) { + /* Should traverse, but could not open reparse point handle */ + SetLastError(ERROR_SHARING_VIOLATION); return -1; } } - code = attribute_data_to_stat(&info, result); + } else { + if (!GetFileInformationByHandle(hFile, &info)) { + CloseHandle(hFile); + return -1;; + } + if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) { + code = win32_read_link(hFile, &reparse_tag, traverse ? &target_path : NULL); + CloseHandle(hFile); + if (code < 0) + return code; + if (traverse) { + code = win32_xstat_impl_w(target_path, result, traverse, depth + 1); + free(target_path); + return code; + } + } else + CloseHandle(hFile); } - else { - /* We have a good handle to the target, use it to determine the target - path name (then we'll call lstat on it). */ - buf_size = Py_GetFinalPathNameByHandleW(hFile, 0, 0, VOLUME_NAME_DOS); - if(!buf_size) - return -1; + attribute_data_to_stat(&info, reparse_tag, result); - target_path = (wchar_t *)malloc((buf_size+1)*sizeof(wchar_t)); - result_length = Py_GetFinalPathNameByHandleW(hFile, target_path, - buf_size, VOLUME_NAME_DOS); - - if(!result_length) { - free(target_path); - return -1; - } + /* Set S_IEXEC if it is an .exe, .bat, ... */ + dot = wcsrchr(path, '.'); + if (dot) { + if (_wcsicmp(dot, L".bat") == 0 || _wcsicmp(dot, L".cmd") == 0 || + _wcsicmp(dot, L".exe") == 0 || _wcsicmp(dot, L".com") == 0) + result->st_mode |= 0111; + } + return 0; +} - if(!CloseHandle(hFile)) { - free(target_path); - return -1; - } +static int +win32_xstat(const char *path, struct win32_stat *result, BOOL traverse) +{ + /* Protocol violation: we explicitly clear errno, instead of + setting it to a POSIX error. Callers should use GetLastError. */ + int code = win32_xstat_impl(path, result, traverse, 0); + errno = 0; + return code; +} - target_path[result_length] = 0; - code = win32_lstat_w(target_path, result); - free(target_path); - } - +static int +win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse) +{ + /* Protocol violation: we explicitly clear errno, instead of + setting it to a POSIX error. Callers should use GetLastError. */ + int code = win32_xstat_impl_w(path, result, traverse, 0); + errno = 0; return code; } +/* About the following functions: win32_lstat, win32_lstat_w, win32_stat, + win32_stat_w + + In Posix, stat automatically traverses symlinks and returns the stat + structure for the target. In Windows, the equivalent GetFileAttributes by + default does not traverse symlinks and instead returns attributes for + the symlink. + + Therefore, win32_lstat will get the attributes traditionally, and + win32_stat will first explicitly resolve the symlink target and then will + call win32_lstat on that result. + + The _w represent Unicode equivalents of the aformentioned ANSI functions. */ + +static int +win32_lstat(const char* path, struct win32_stat *result) +{ + return win32_xstat(path, result, FALSE); +} + +static int +win32_lstat_w(const wchar_t* path, struct win32_stat *result) +{ + return win32_xstat_w(path, result, FALSE); +} + +static int +win32_stat(const char* path, struct win32_stat *result) +{ + return win32_xstat(path, result, TRUE); +} + +static int +win32_stat_w(const wchar_t* path, struct win32_stat *result) +{ + return win32_xstat_w(path, result, TRUE); +} + static int win32_fstat(int file_number, struct win32_stat *result) { @@ -1309,7 +1331,7 @@ if (type == FILE_TYPE_UNKNOWN) { DWORD error = GetLastError(); if (error != 0) { - return -1; + return -1; } /* else: valid but unknown file */ } @@ -1326,17 +1348,8 @@ return -1; } - /* similar to stat() */ - result->st_mode = attributes_to_mode(info.dwFileAttributes); - result->st_size = (((__int64)info.nFileSizeHigh)<<32) + info.nFileSizeLow; - FILE_TIME_to_time_t_nsec(&info.ftCreationTime, &result->st_ctime, - &result->st_ctime_nsec); - FILE_TIME_to_time_t_nsec(&info.ftLastWriteTime, &result->st_mtime, - &result->st_mtime_nsec); - FILE_TIME_to_time_t_nsec(&info.ftLastAccessTime, &result->st_atime, - &result->st_atime_nsec); + attribute_data_to_stat(&info, 0, result); /* specific to fstat() */ - result->st_nlink = info.nNumberOfLinks; result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow; return 0; } @@ -2057,7 +2070,7 @@ static PyObject * posix_fsync(PyObject *self, PyObject *fdobj) { - return posix_fildes(fdobj, fsync); + return posix_fildes(fdobj, fsync); } #endif /* HAVE_FSYNC */ @@ -2075,7 +2088,7 @@ static PyObject * posix_fdatasync(PyObject *self, PyObject *fdobj) { - return posix_fildes(fdobj, fdatasync); + return posix_fildes(fdobj, fdatasync); } #endif /* HAVE_FDATASYNC */ @@ -2247,6 +2260,54 @@ } #endif /* HAVE_LINK */ +#ifdef MS_WINDOWS +PyDoc_STRVAR(win32_link__doc__, +"link(src, dst)\n\n\ +Create a hard link to a file."); + +static PyObject * +win32_link(PyObject *self, PyObject *args) +{ + PyObject *osrc, *odst; + char *src, *dst; + BOOL rslt; + + PyUnicodeObject *usrc, *udst; + if (PyArg_ParseTuple(args, "UU:link", &usrc, &udst)) { + Py_BEGIN_ALLOW_THREADS + rslt = CreateHardLinkW(PyUnicode_AS_UNICODE(udst), + PyUnicode_AS_UNICODE(usrc), NULL); + Py_END_ALLOW_THREADS + + if (rslt == 0) + return win32_error("link", NULL); + + Py_RETURN_NONE; + } + + /* Narrow strings also valid. */ + PyErr_Clear(); + + if (!PyArg_ParseTuple(args, "O&O&:link", PyUnicode_FSConverter, &osrc, + PyUnicode_FSConverter, &odst)) + return NULL; + + src = PyBytes_AsString(osrc); + dst = PyBytes_AsString(odst); + + Py_BEGIN_ALLOW_THREADS + rslt = CreateHardLinkA(dst, src, NULL); + Py_END_ALLOW_THREADS + + Py_DECREF(osrc); + Py_DECREF(odst); + if (rslt == 0) + return win32_error("link", NULL); + + Py_RETURN_NONE; +} +#endif /* MS_WINDOWS */ + PyDoc_STRVAR(posix_listdir__doc__, "listdir([path]) -> list_of_strings\n\n\ @@ -2371,6 +2432,7 @@ } strcpy(namebuf, PyBytes_AsString(opath)); len = PyObject_Size(opath); + Py_DECREF(opath); if (len > 0) { char ch = namebuf[len-1]; if (ch != SEP && ch != ALTSEP && ch != ':') @@ -2526,7 +2588,7 @@ if (!PyArg_ParseTuple(args, "|O&:listdir", PyUnicode_FSConverter, &oname)) return NULL; if (oname == NULL) { /* Default arg: "." */ - oname = PyBytes_FromString("."); + oname = PyBytes_FromString("."); } name = PyBytes_AsString(oname); Py_BEGIN_ALLOW_THREADS @@ -2644,6 +2706,30 @@ return PyBytes_FromString(outbuf); } /* end of posix__getfullpathname */ +/* Grab GetFinalPathNameByHandle dynamically from kernel32 */ +static int has_GetFinalPathNameByHandle = 0; +static DWORD (CALLBACK *Py_GetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD, + DWORD); +static DWORD (CALLBACK *Py_GetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD, + DWORD); +static int +check_GetFinalPathNameByHandle() +{ + HINSTANCE hKernel32; + /* only recheck */ + if (!has_GetFinalPathNameByHandle) + { + hKernel32 = GetModuleHandle("KERNEL32"); + *(FARPROC*)&Py_GetFinalPathNameByHandleA = GetProcAddress(hKernel32, + "GetFinalPathNameByHandleA"); + *(FARPROC*)&Py_GetFinalPathNameByHandleW = GetProcAddress(hKernel32, + "GetFinalPathNameByHandleW"); + has_GetFinalPathNameByHandle = Py_GetFinalPathNameByHandleA && + Py_GetFinalPathNameByHandleW; + } + return has_GetFinalPathNameByHandle; +} + /* A helper function for samepath on windows */ static PyObject * posix__getfinalpathname(PyObject *self, PyObject *args) @@ -2718,14 +2804,12 @@ if (!PyArg_ParseTuple(args, "i:_getfileinformation", &fd)) return NULL; - if (!_PyVerify_fd(fd)) { - PyErr_SetString(PyExc_ValueError, "received invalid file descriptor"); - return NULL; - } + if (!_PyVerify_fd(fd)) + return posix_error(); hFile = (HANDLE)_get_osfhandle(fd); if (hFile == INVALID_HANDLE_VALUE) - return win32_error("_getfileinformation", NULL); + return posix_error(); if (!GetFileInformationByHandle(hFile, &info)) return win32_error("_getfileinformation", NULL); @@ -3141,7 +3225,7 @@ !SystemTimeToFileTime(&now, &atime)) { win32_error("utime", NULL); goto done; - } + } } else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) { PyErr_SetString(PyExc_TypeError, @@ -4209,9 +4293,9 @@ for (i = 0; i < n; ++i) { PyObject *o = PyLong_FromLong((long)alt_grouplist[i]); if (o == NULL) { - Py_DECREF(result); - result = NULL; - break; + Py_DECREF(result); + result = NULL; + break; } PyList_SET_ITEM(result, i, o); } @@ -5026,7 +5110,7 @@ #endif /* HAVE_READLINK */ -#ifdef HAVE_SYMLINK +#if defined(HAVE_SYMLINK) && !defined(MS_WINDOWS) PyDoc_STRVAR(posix_symlink__doc__, "symlink(src, dst)\n\n\ Create a symbolic link pointing to src named dst."); @@ -5044,43 +5128,6 @@ "readlink(path) -> path\n\n\ Return a string representing the path to which the symbolic link points."); -/* The following structure was copied from - http://msdn.microsoft.com/en-us/library/ms791514.aspx as the required - include doesn't seem to be present in the Windows SDK (at least as included - with Visual Studio Express). */ -typedef struct _REPARSE_DATA_BUFFER { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union { - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - - struct { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - }; -} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; - -#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER,\ - GenericReparseBuffer) - -#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 ) - /* Windows readlink implementation */ static PyObject * win_readlink(PyObject *self, PyObject *args) @@ -5151,7 +5198,7 @@ #endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */ -#if !defined(HAVE_SYMLINK) && defined(MS_WINDOWS) +#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS) /* Grab CreateSymbolicLinkW dynamically from kernel32 */ static int has_CreateSymbolicLinkW = 0; @@ -5197,6 +5244,10 @@ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i:symlink", kwlist, &src, &dest, &target_is_directory)) return NULL; + + if (win32_can_symlink == 0) + return PyErr_Format(PyExc_OSError, "symbolic link privilege not held"); + if (!convert_to_unicode(&src)) { return NULL; } if (!convert_to_unicode(&dest)) { Py_DECREF(src); @@ -5229,7 +5280,7 @@ Py_INCREF(Py_None); return Py_None; } -#endif /* !defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */ +#endif /* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */ #ifdef HAVE_TIMES #if defined(PYCC_VACPP) && defined(PYOS_OS2) @@ -5610,8 +5661,10 @@ buffer = PyBytes_FromStringAndSize((char *)NULL, size); if (buffer == NULL) return NULL; - if (!_PyVerify_fd(fd)) + if (!_PyVerify_fd(fd)) { + Py_DECREF(buffer); return posix_error(); + } Py_BEGIN_ALLOW_THREADS n = read(fd, PyBytes_AS_STRING(buffer), size); Py_END_ALLOW_THREADS @@ -5638,12 +5691,14 @@ if (!PyArg_ParseTuple(args, "iy*:write", &fd, &pbuf)) return NULL; - if (!_PyVerify_fd(fd)) + if (!_PyVerify_fd(fd)) { + PyBuffer_Release(&pbuf); return posix_error(); + } Py_BEGIN_ALLOW_THREADS size = write(fd, pbuf.buf, (size_t)pbuf.len); Py_END_ALLOW_THREADS - PyBuffer_Release(&pbuf); + PyBuffer_Release(&pbuf); if (size < 0) return posix_error(); return PyLong_FromSsize_t(size); @@ -6348,38 +6403,38 @@ size_t tablesize) { if (PyLong_Check(arg)) { - *valuep = PyLong_AS_LONG(arg); - return 1; + *valuep = PyLong_AS_LONG(arg); + return 1; } else { - /* look up the value in the table using a binary search */ - size_t lo = 0; - size_t mid; - size_t hi = tablesize; - int cmp; - const char *confname; - if (!PyUnicode_Check(arg)) { - PyErr_SetString(PyExc_TypeError, - "configuration names must be strings or integers"); - return 0; - } - confname = _PyUnicode_AsString(arg); - if (confname == NULL) - return 0; - while (lo < hi) { - mid = (lo + hi) / 2; - cmp = strcmp(confname, table[mid].name); - if (cmp < 0) - hi = mid; - else if (cmp > 0) - lo = mid + 1; - else { - *valuep = table[mid].value; - return 1; + /* look up the value in the table using a binary search */ + size_t lo = 0; + size_t mid; + size_t hi = tablesize; + int cmp; + const char *confname; + if (!PyUnicode_Check(arg)) { + PyErr_SetString(PyExc_TypeError, + "configuration names must be strings or integers"); + return 0; } - } - PyErr_SetString(PyExc_ValueError, "unrecognized configuration name"); - return 0; + confname = _PyUnicode_AsString(arg); + if (confname == NULL) + return 0; + while (lo < hi) { + mid = (lo + hi) / 2; + cmp = strcmp(confname, table[mid].name); + if (cmp < 0) + hi = mid; + else if (cmp > 0) + lo = mid + 1; + else { + *valuep = table[mid].value; + return 1; + } + } + PyErr_SetString(PyExc_ValueError, "unrecognized configuration name"); + return 0; } } @@ -6495,14 +6550,14 @@ if (PyArg_ParseTuple(args, "iO&:fpathconf", &fd, conv_path_confname, &name)) { - long limit; + long limit; - errno = 0; - limit = fpathconf(fd, name); - if (limit == -1 && errno != 0) - posix_error(); - else - result = PyLong_FromLong(limit); + errno = 0; + limit = fpathconf(fd, name); + if (limit == -1 && errno != 0) + posix_error(); + else + result = PyLong_FromLong(limit); } return result; } @@ -6530,10 +6585,10 @@ limit = pathconf(path, name); if (limit == -1 && errno != 0) { if (errno == EINVAL) - /* could be a path or name problem */ - posix_error(); + /* could be a path or name problem */ + posix_error(); else - posix_error_with_filename(path); + posix_error_with_filename(path); } else result = PyLong_FromLong(limit); @@ -6714,7 +6769,7 @@ PyObject *result = NULL; int name; char buffer[255]; - int len; + int len; if (!PyArg_ParseTuple(args, "O&:confstr", conv_confstr_confname, &name)) return NULL; @@ -7329,21 +7384,21 @@ sizeof(posix_constants_pathconf) / sizeof(struct constdef), "pathconf_names", module)) - return -1; + return -1; #endif #ifdef HAVE_CONFSTR if (setup_confname_table(posix_constants_confstr, sizeof(posix_constants_confstr) / sizeof(struct constdef), "confstr_names", module)) - return -1; + return -1; #endif #ifdef HAVE_SYSCONF if (setup_confname_table(posix_constants_sysconf, sizeof(posix_constants_sysconf) / sizeof(struct constdef), "sysconf_names", module)) - return -1; + return -1; #endif return 0; } @@ -7456,10 +7511,10 @@ { double loadavg[3]; if (getloadavg(loadavg, 3)!=3) { - PyErr_SetString(PyExc_OSError, "Load averages are unobtainable"); - return NULL; + PyErr_SetString(PyExc_OSError, "Load averages are unobtainable"); + return NULL; } else - return Py_BuildValue("ddd", loadavg[0], loadavg[1], loadavg[2]); + return Py_BuildValue("ddd", loadavg[0], loadavg[1], loadavg[2]); } #endif @@ -7747,13 +7802,13 @@ {"rmdir", posix_rmdir, METH_VARARGS, posix_rmdir__doc__}, {"stat", posix_stat, METH_VARARGS, posix_stat__doc__}, {"stat_float_times", stat_float_times, METH_VARARGS, stat_float_times__doc__}, -#ifdef HAVE_SYMLINK +#if defined(HAVE_SYMLINK) && !defined(MS_WINDOWS) {"symlink", posix_symlink, METH_VARARGS, posix_symlink__doc__}, #endif /* HAVE_SYMLINK */ -#if !defined(HAVE_SYMLINK) && defined(MS_WINDOWS) +#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS) {"symlink", (PyCFunction)win_symlink, METH_VARARGS | METH_KEYWORDS, - win_symlink__doc__}, -#endif /* !defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */ + win_symlink__doc__}, +#endif /* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */ #ifdef HAVE_SYSTEM {"system", posix_system, METH_VARARGS, posix_system__doc__}, #endif @@ -7829,6 +7884,7 @@ #ifdef MS_WINDOWS {"startfile", win32_startfile, METH_VARARGS, win32_startfile__doc__}, {"kill", win32_kill, METH_VARARGS, win32_kill__doc__}, + {"link", win32_link, METH_VARARGS, win32_link__doc__}, #endif #ifdef HAVE_SETUID {"setuid", posix_setuid, METH_VARARGS, posix_setuid__doc__}, @@ -8066,6 +8122,35 @@ } #endif +#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS) +static int +enable_symlink() +{ + HANDLE tok; + TOKEN_PRIVILEGES tok_priv; + LUID luid; + int meth_idx = 0; + + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &tok)) + return 0; + + if (!LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid)) + return 0; + + tok_priv.PrivilegeCount = 1; + tok_priv.Privileges[0].Luid = luid; + tok_priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + if (!AdjustTokenPrivileges(tok, FALSE, &tok_priv, + sizeof(TOKEN_PRIVILEGES), + (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL)) + return 0; + + /* ERROR_NOT_ALL_ASSIGNED returned when the privilege can't be assigned. */ + return GetLastError() == ERROR_NOT_ALL_ASSIGNED ? 0 : 1; +} +#endif /* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */ + static int all_ins(PyObject *d) { @@ -8327,6 +8412,10 @@ { PyObject *m, *v; +#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS) + win32_can_symlink = enable_symlink(); +#endif + m = PyModule_Create(&posixmodule); if (m == NULL) return NULL; Modified: python/branches/py3k-cdecimal/Modules/pwdmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/pwdmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/pwdmodule.c Sun Jan 2 13:18:37 2011 @@ -2,7 +2,6 @@ /* UNIX password file access module */ #include "Python.h" -#include "structseq.h" #include #include Modified: python/branches/py3k-cdecimal/Modules/pyexpat.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/pyexpat.c (original) +++ python/branches/py3k-cdecimal/Modules/pyexpat.c Sun Jan 2 13:18:37 2011 @@ -1215,11 +1215,12 @@ } static int -handlername2int(const char *name) +handlername2int(PyObject *name) { int i; for (i = 0; handler_info[i].name != NULL; i++) { - if (strcmp(name, handler_info[i].name) == 0) { + if (PyUnicode_CompareWithASCIIString( + name, handler_info[i].name) == 0) { return i; } } @@ -1237,13 +1238,13 @@ static PyObject * xmlparse_getattro(xmlparseobject *self, PyObject *nameobj) { - char *name = ""; + Py_UNICODE *name; int handlernum = -1; - if (PyUnicode_Check(nameobj)) - name = _PyUnicode_AsString(nameobj); + if (!PyUnicode_Check(nameobj)) + goto generic; - handlernum = handlername2int(name); + handlernum = handlername2int(nameobj); if (handlernum != -1) { PyObject *result = self->handlers[handlernum]; @@ -1252,46 +1253,48 @@ Py_INCREF(result); return result; } + + name = PyUnicode_AS_UNICODE(nameobj); if (name[0] == 'E') { - if (strcmp(name, "ErrorCode") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "ErrorCode") == 0) return PyLong_FromLong((long) XML_GetErrorCode(self->itself)); - if (strcmp(name, "ErrorLineNumber") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "ErrorLineNumber") == 0) return PyLong_FromLong((long) XML_GetErrorLineNumber(self->itself)); - if (strcmp(name, "ErrorColumnNumber") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "ErrorColumnNumber") == 0) return PyLong_FromLong((long) XML_GetErrorColumnNumber(self->itself)); - if (strcmp(name, "ErrorByteIndex") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "ErrorByteIndex") == 0) return PyLong_FromLong((long) XML_GetErrorByteIndex(self->itself)); } if (name[0] == 'C') { - if (strcmp(name, "CurrentLineNumber") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "CurrentLineNumber") == 0) return PyLong_FromLong((long) XML_GetCurrentLineNumber(self->itself)); - if (strcmp(name, "CurrentColumnNumber") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "CurrentColumnNumber") == 0) return PyLong_FromLong((long) XML_GetCurrentColumnNumber(self->itself)); - if (strcmp(name, "CurrentByteIndex") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "CurrentByteIndex") == 0) return PyLong_FromLong((long) XML_GetCurrentByteIndex(self->itself)); } if (name[0] == 'b') { - if (strcmp(name, "buffer_size") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "buffer_size") == 0) return PyLong_FromLong((long) self->buffer_size); - if (strcmp(name, "buffer_text") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "buffer_text") == 0) return get_pybool(self->buffer != NULL); - if (strcmp(name, "buffer_used") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "buffer_used") == 0) return PyLong_FromLong((long) self->buffer_used); } - if (strcmp(name, "namespace_prefixes") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "namespace_prefixes") == 0) return get_pybool(self->ns_prefixes); - if (strcmp(name, "ordered_attributes") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "ordered_attributes") == 0) return get_pybool(self->ordered_attributes); - if (strcmp(name, "specified_attributes") == 0) + if (PyUnicode_CompareWithASCIIString(nameobj, "specified_attributes") == 0) return get_pybool((long) self->specified_attributes); - if (strcmp(name, "intern") == 0) { + if (PyUnicode_CompareWithASCIIString(nameobj, "intern") == 0) { if (self->intern == NULL) { Py_INCREF(Py_None); return Py_None; @@ -1301,7 +1304,7 @@ return self->intern; } } - + generic: return PyObject_GenericGetAttr((PyObject*)self, nameobj); } @@ -1352,7 +1355,7 @@ } static int -sethandler(xmlparseobject *self, const char *name, PyObject* v) +sethandler(xmlparseobject *self, PyObject *name, PyObject* v) { int handlernum = handlername2int(name); if (handlernum >= 0) { @@ -1388,14 +1391,15 @@ } static int -xmlparse_setattr(xmlparseobject *self, char *name, PyObject *v) +xmlparse_setattro(xmlparseobject *self, PyObject *name, PyObject *v) { /* Set attribute 'name' to value 'v'. v==NULL means delete */ if (v == NULL) { PyErr_SetString(PyExc_RuntimeError, "Cannot delete attribute"); return -1; } - if (strcmp(name, "buffer_text") == 0) { + assert(PyUnicode_Check(name)); + if (PyUnicode_CompareWithASCIIString(name, "buffer_text") == 0) { if (PyObject_IsTrue(v)) { if (self->buffer == NULL) { self->buffer = malloc(self->buffer_size); @@ -1414,7 +1418,7 @@ } return 0; } - if (strcmp(name, "namespace_prefixes") == 0) { + if (PyUnicode_CompareWithASCIIString(name, "namespace_prefixes") == 0) { if (PyObject_IsTrue(v)) self->ns_prefixes = 1; else @@ -1422,14 +1426,14 @@ XML_SetReturnNSTriplet(self->itself, self->ns_prefixes); return 0; } - if (strcmp(name, "ordered_attributes") == 0) { + if (PyUnicode_CompareWithASCIIString(name, "ordered_attributes") == 0) { if (PyObject_IsTrue(v)) self->ordered_attributes = 1; else self->ordered_attributes = 0; return 0; } - if (strcmp(name, "specified_attributes") == 0) { + if (PyUnicode_CompareWithASCIIString(name, "specified_attributes") == 0) { if (PyObject_IsTrue(v)) self->specified_attributes = 1; else @@ -1437,7 +1441,7 @@ return 0; } - if (strcmp(name, "buffer_size") == 0) { + if (PyUnicode_CompareWithASCIIString(name, "buffer_size") == 0) { long new_buffer_size; if (!PyLong_Check(v)) { PyErr_SetString(PyExc_TypeError, "buffer_size must be an integer"); @@ -1480,7 +1484,7 @@ return 0; } - if (strcmp(name, "CharacterDataHandler") == 0) { + if (PyUnicode_CompareWithASCIIString(name, "CharacterDataHandler") == 0) { /* If we're changing the character data handler, flush all * cached data with the old handler. Not sure there's a * "right" thing to do, though, but this probably won't @@ -1492,7 +1496,7 @@ if (sethandler(self, name, v)) { return 0; } - PyErr_SetString(PyExc_AttributeError, name); + PyErr_SetObject(PyExc_AttributeError, name); return -1; } @@ -1524,7 +1528,7 @@ (destructor)xmlparse_dealloc, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ 0, /*tp_getattr*/ - (setattrfunc)xmlparse_setattr, /*tp_setattr*/ + 0, /*tp_setattr*/ 0, /*tp_reserved*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ @@ -1534,7 +1538,7 @@ (ternaryfunc)0, /*tp_call*/ (reprfunc)0, /*tp_str*/ (getattrofunc)xmlparse_getattro, /* tp_getattro */ - 0, /* tp_setattro */ + (setattrofunc)xmlparse_setattro, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /*tp_flags*/ Xmlparsetype__doc__, /* tp_doc - Documentation string */ Modified: python/branches/py3k-cdecimal/Modules/readline.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/readline.c (original) +++ python/branches/py3k-cdecimal/Modules/readline.c Sun Jan 2 13:18:37 2011 @@ -889,6 +889,14 @@ Py_FatalError("not enough memory to save locale"); #endif +#ifdef __APPLE__ + /* the libedit readline emulation resets key bindings etc + * when calling rl_initialize. So call it upfront + */ + if (using_libedit_emulation) + rl_initialize(); +#endif /* __APPLE__ */ + using_history(); rl_readline_name = "python"; @@ -920,8 +928,13 @@ * XXX: A bug in the readline-2.2 library causes a memory leak * inside this function. Nothing we can do about it. */ - rl_initialize(); - +#ifdef __APPLE__ + if (using_libedit_emulation) + rl_read_init_file(NULL); + else +#endif /* __APPLE__ */ + rl_initialize(); + RESTORE_LOCALE(saved_locale) } Modified: python/branches/py3k-cdecimal/Modules/resource.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/resource.c (original) +++ python/branches/py3k-cdecimal/Modules/resource.c Sun Jan 2 13:18:37 2011 @@ -1,6 +1,5 @@ #include "Python.h" -#include "structseq.h" #include #include #include Modified: python/branches/py3k-cdecimal/Modules/signalmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/signalmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/signalmodule.c Sun Jan 2 13:18:37 2011 @@ -4,7 +4,6 @@ /* XXX Signals should be recorded per thread, now we have thread state. */ #include "Python.h" -#include "intrcheck.h" #ifdef MS_WINDOWS #include Modified: python/branches/py3k-cdecimal/Modules/socketmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/socketmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/socketmodule.c Sun Jan 2 13:18:37 2011 @@ -1406,9 +1406,9 @@ { struct sockaddr_hci *addr = (struct sockaddr_hci *)addr_ret; #if defined(__NetBSD__) || defined(__DragonFly__) - char *straddr = PyBytes_AS_STRING(args); + char *straddr = PyBytes_AS_STRING(args); - _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH; + _BT_HCI_MEMB(addr, family) = AF_BLUETOOTH; if (straddr == NULL) { PyErr_SetString(socket_error, "getsockaddrarg: " "wrong format"); @@ -4022,8 +4022,10 @@ pptr = pbuf; } else if (PyUnicode_Check(pobj)) { pptr = _PyUnicode_AsString(pobj); + if (pptr == NULL) + goto err; } else if (PyBytes_Check(pobj)) { - pptr = PyBytes_AsString(pobj); + pptr = PyBytes_AS_STRING(pobj); } else if (pobj == Py_None) { pptr = (char *)NULL; } else { @@ -4358,6 +4360,7 @@ PySocketModule_APIObject PySocketModuleAPI = { &sock_type, + NULL, NULL }; @@ -4425,6 +4428,7 @@ socket_error, NULL); if (socket_timeout == NULL) return NULL; + PySocketModuleAPI.timeout_error = socket_timeout; Py_INCREF(socket_timeout); PyModule_AddObject(m, "timeout", socket_timeout); Py_INCREF((PyObject *)&sock_type); Modified: python/branches/py3k-cdecimal/Modules/socketmodule.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/socketmodule.h (original) +++ python/branches/py3k-cdecimal/Modules/socketmodule.h Sun Jan 2 13:18:37 2011 @@ -196,6 +196,7 @@ typedef struct { PyTypeObject *Sock_Type; PyObject *error; + PyObject *timeout_error; } PySocketModule_APIObject; #define PySocketModule_ImportModuleAndAPI() PyCapsule_Import(PySocket_CAPSULE_NAME, 1) Modified: python/branches/py3k-cdecimal/Modules/spwdmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/spwdmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/spwdmodule.c Sun Jan 2 13:18:37 2011 @@ -4,7 +4,6 @@ /* For info also see http://www.unixpapa.com/incnote/passwd.html */ #include "Python.h" -#include "structseq.h" #include #ifdef HAVE_SHADOW_H Modified: python/branches/py3k-cdecimal/Modules/symtablemodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/symtablemodule.c (original) +++ python/branches/py3k-cdecimal/Modules/symtablemodule.c Sun Jan 2 13:18:37 2011 @@ -1,7 +1,6 @@ #include "Python.h" #include "code.h" -#include "compile.h" #include "Python-ast.h" #include "symtable.h" Modified: python/branches/py3k-cdecimal/Modules/syslogmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/syslogmodule.c (original) +++ python/branches/py3k-cdecimal/Modules/syslogmodule.c Sun Jan 2 13:18:37 2011 @@ -68,9 +68,9 @@ * is optional. */ - Py_ssize_t argv_len; + Py_ssize_t argv_len, scriptlen; PyObject *scriptobj; - char *atslash; + Py_UNICODE *atslash, *atstart; PyObject *argv = PySys_GetObject("argv"); if (argv == NULL) { @@ -90,13 +90,16 @@ if (!PyUnicode_Check(scriptobj)) { return(NULL); } - if (PyUnicode_GET_SIZE(scriptobj) == 0) { + scriptlen = PyUnicode_GET_SIZE(scriptobj); + if (scriptlen == 0) { return(NULL); } - atslash = strrchr(_PyUnicode_AsString(scriptobj), SEP); + atstart = PyUnicode_AS_UNICODE(scriptobj); + atslash = Py_UNICODE_strrchr(atstart, SEP); if (atslash) { - return(PyUnicode_FromString(atslash + 1)); + return(PyUnicode_FromUnicode(atslash + 1, + scriptlen - (atslash - atstart) - 1)); } else { Py_INCREF(scriptobj); return(scriptobj); @@ -113,6 +116,7 @@ long facility = LOG_USER; PyObject *new_S_ident_o = NULL; static char *keywords[] = {"ident", "logoption", "facility", 0}; + char *ident = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Ull:openlog", keywords, &new_S_ident_o, &logopt, &facility)) @@ -120,12 +124,12 @@ if (new_S_ident_o) { Py_INCREF(new_S_ident_o); - } + } /* get sys.argv[0] or NULL if we can't for some reason */ if (!new_S_ident_o) { new_S_ident_o = syslog_get_argv(); - } + } Py_XDECREF(S_ident_o); S_ident_o = new_S_ident_o; @@ -134,8 +138,13 @@ * make a copy, and syslog(3) later uses it. We can't garbagecollect it * If NULL, just let openlog figure it out (probably using C argv[0]). */ + if (S_ident_o) { + ident = _PyUnicode_AsString(S_ident_o); + if (ident == NULL) + return NULL; + } - openlog(S_ident_o ? _PyUnicode_AsString(S_ident_o) : NULL, logopt, facility); + openlog(ident, logopt, facility); S_log_open = 1; Py_INCREF(Py_None); Modified: python/branches/py3k-cdecimal/Modules/timemodule.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/timemodule.c (original) +++ python/branches/py3k-cdecimal/Modules/timemodule.c Sun Jan 2 13:18:37 2011 @@ -2,7 +2,6 @@ /* Time module */ #include "Python.h" -#include "structseq.h" #include "_time.h" #define TZNAME_ENCODING "utf-8" @@ -716,7 +715,7 @@ } PyDoc_STRVAR(tzset_doc, -"tzset(zone)\n\ +"tzset()\n\ \n\ Initialize, or reinitialize, the local timezone to the value stored in\n\ os.environ['TZ']. The TZ environment variable should be specified in\n\ Modified: python/branches/py3k-cdecimal/Modules/unicodedata.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/unicodedata.c (original) +++ python/branches/py3k-cdecimal/Modules/unicodedata.c Sun Jan 2 13:18:37 2011 @@ -684,10 +684,14 @@ comb = 0; while (i1 < end) { int comb1 = _getrecord_ex(*i1)->combining; - if (comb && (comb1 == 0 || comb == comb1)) { - /* Character is blocked. */ - i1++; - continue; + if (comb) { + if (comb1 == 0) + break; + if (comb >= comb1) { + /* Character is blocked. */ + i1++; + continue; + } } l = find_nfc_index(self, nfc_last, *i1); /* *i1 cannot be combined with *i. If *i1 @@ -711,6 +715,7 @@ /* Replace the original character. */ *i = code; /* Mark the second character unused. */ + assert(cskipped < 20); skipped[cskipped++] = i1; i1++; f = find_nfc_index(self, nfc_first, *i); Modified: python/branches/py3k-cdecimal/Objects/bytearrayobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/bytearrayobject.c (original) +++ python/branches/py3k-cdecimal/Objects/bytearrayobject.c Sun Jan 2 13:18:37 2011 @@ -389,7 +389,7 @@ } else if (PySlice_Check(index)) { Py_ssize_t start, stop, step, slicelength, cur, i; - if (PySlice_GetIndicesEx((PySliceObject *)index, + if (PySlice_GetIndicesEx(index, PyByteArray_GET_SIZE(self), &start, &stop, &step, &slicelength) < 0) { return NULL; @@ -573,7 +573,7 @@ } } else if (PySlice_Check(index)) { - if (PySlice_GetIndicesEx((PySliceObject *)index, + if (PySlice_GetIndicesEx(index, PyByteArray_GET_SIZE(self), &start, &stop, &step, &slicelen) < 0) { return -1; @@ -589,7 +589,7 @@ needed = 0; } else if (values == (PyObject *)self || !PyByteArray_Check(values)) { - /* Make a copy an call this function recursively */ + /* Make a copy and call this function recursively */ int err; values = PyByteArray_FromObject(values); if (values == NULL) Modified: python/branches/py3k-cdecimal/Objects/bytesobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/bytesobject.c (original) +++ python/branches/py3k-cdecimal/Objects/bytesobject.c Sun Jan 2 13:18:37 2011 @@ -911,7 +911,7 @@ char* result_buf; PyObject* result; - if (PySlice_GetIndicesEx((PySliceObject*)item, + if (PySlice_GetIndicesEx(item, PyBytes_GET_SIZE(self), &start, &stop, &step, &slicelength) < 0) { return NULL; Modified: python/branches/py3k-cdecimal/Objects/complexobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/complexobject.c (original) +++ python/branches/py3k-cdecimal/Objects/complexobject.c Sun Jan 2 13:18:37 2011 @@ -324,10 +324,11 @@ op->ob_type->tp_free(op); } - static PyObject * -complex_format(PyComplexObject *v, int precision, char format_code) +complex_repr(PyComplexObject *v) { + int precision = 0; + char format_code = 'r'; PyObject *result = NULL; Py_ssize_t len; @@ -344,6 +345,8 @@ char *tail = ""; if (v->cval.real == 0. && copysign(1.0, v->cval.real)==1.0) { + /* Real part is +0: just output the imaginary part and do not + include parens. */ re = ""; im = PyOS_double_to_string(v->cval.imag, format_code, precision, 0, NULL); @@ -352,7 +355,8 @@ goto done; } } else { - /* Format imaginary part with sign, real part without */ + /* Format imaginary part with sign, real part without. Include + parens in the result. */ pre = PyOS_double_to_string(v->cval.real, format_code, precision, 0, NULL); if (!pre) { @@ -371,7 +375,7 @@ tail = ")"; } /* Alloc the final buffer. Add one for the "j" in the format string, - and one for the trailing zero. */ + and one for the trailing zero byte. */ len = strlen(lead) + strlen(re) + strlen(im) + strlen(tail) + 2; buf = PyMem_Malloc(len); if (!buf) { @@ -388,12 +392,6 @@ return result; } -static PyObject * -complex_repr(PyComplexObject *v) -{ - return complex_format(v, 0, 'r'); -} - static Py_hash_t complex_hash(PyComplexObject *v) { @@ -766,24 +764,30 @@ char *end; double x=0.0, y=0.0, z; int got_bracket=0; - char *s_buffer = NULL; + PyObject *s_buffer = NULL; Py_ssize_t len; if (PyUnicode_Check(v)) { - s_buffer = (char *)PyMem_MALLOC(PyUnicode_GET_SIZE(v) + 1); + Py_ssize_t i, buflen = PyUnicode_GET_SIZE(v); + Py_UNICODE *bufptr; + s_buffer = PyUnicode_TransformDecimalToASCII( + PyUnicode_AS_UNICODE(v), buflen); if (s_buffer == NULL) - return PyErr_NoMemory(); - if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v), - PyUnicode_GET_SIZE(v), - s_buffer, - NULL)) + return NULL; + /* Replace non-ASCII whitespace with ' ' */ + bufptr = PyUnicode_AS_UNICODE(s_buffer); + for (i = 0; i < buflen; i++) { + Py_UNICODE ch = bufptr[i]; + if (ch > 127 && Py_UNICODE_ISSPACE(ch)) + bufptr[i] = ' '; + } + s = _PyUnicode_AsStringAndSize(s_buffer, &len); + if (s == NULL) goto error; - s = s_buffer; - len = strlen(s); } else if (PyObject_AsCharBuffer(v, &s, &len)) { PyErr_SetString(PyExc_TypeError, - "complex() arg is not a string"); + "complex() argument must be a string or a number"); return NULL; } @@ -894,16 +898,14 @@ if (s-start != len) goto parse_error; - if (s_buffer) - PyMem_FREE(s_buffer); + Py_XDECREF(s_buffer); return complex_subtype_from_doubles(type, x, y); parse_error: PyErr_SetString(PyExc_ValueError, "complex() arg is a malformed string"); error: - if (s_buffer) - PyMem_FREE(s_buffer); + Py_XDECREF(s_buffer); return NULL; } Modified: python/branches/py3k-cdecimal/Objects/descrobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/descrobject.c (original) +++ python/branches/py3k-cdecimal/Objects/descrobject.c Sun Jan 2 13:18:37 2011 @@ -710,19 +710,19 @@ static PyObject * proxy_keys(proxyobject *pp) { - return PyMapping_Keys(pp->dict); + return PyObject_CallMethod(pp->dict, "keys", NULL); } static PyObject * proxy_values(proxyobject *pp) { - return PyMapping_Values(pp->dict); + return PyObject_CallMethod(pp->dict, "values", NULL); } static PyObject * proxy_items(proxyobject *pp) { - return PyMapping_Items(pp->dict); + return PyObject_CallMethod(pp->dict, "items", NULL); } static PyObject * @@ -766,6 +766,12 @@ return PyObject_Str(pp->dict); } +static PyObject * +proxy_repr(proxyobject *pp) +{ + return PyUnicode_FromFormat("dict_proxy(%R)", pp->dict); +} + static int proxy_traverse(PyObject *self, visitproc visit, void *arg) { @@ -791,7 +797,7 @@ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - 0, /* tp_repr */ + (reprfunc)proxy_repr, /* tp_repr */ 0, /* tp_as_number */ &proxy_as_sequence, /* tp_as_sequence */ &proxy_as_mapping, /* tp_as_mapping */ @@ -1190,7 +1196,7 @@ PyErr_SetString(PyExc_AttributeError, "unreadable attribute"); return NULL; } - return PyObject_CallFunction(gs->prop_get, "(O)", obj); + return PyObject_CallFunctionObjArgs(gs->prop_get, obj, NULL); } static int @@ -1211,9 +1217,9 @@ return -1; } if (value == NULL) - res = PyObject_CallFunction(func, "(O)", obj); + res = PyObject_CallFunctionObjArgs(func, obj, NULL); else - res = PyObject_CallFunction(func, "(OO)", obj, value); + res = PyObject_CallFunctionObjArgs(func, obj, value, NULL); if (res == NULL) return -1; Py_DECREF(res); Modified: python/branches/py3k-cdecimal/Objects/floatobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/floatobject.c (original) +++ python/branches/py3k-cdecimal/Objects/floatobject.c Sun Jan 2 13:18:37 2011 @@ -5,7 +5,6 @@ for any kind of float exception without losing portability. */ #include "Python.h" -#include "structseq.h" #include #include @@ -175,22 +174,30 @@ { const char *s, *last, *end; double x; - char buffer[256]; /* for errors */ - char *s_buffer = NULL; + PyObject *s_buffer = NULL; Py_ssize_t len; PyObject *result = NULL; if (PyUnicode_Check(v)) { - s_buffer = (char *)PyMem_MALLOC(PyUnicode_GET_SIZE(v)+1); + Py_ssize_t i, buflen = PyUnicode_GET_SIZE(v); + Py_UNICODE *bufptr; + s_buffer = PyUnicode_TransformDecimalToASCII( + PyUnicode_AS_UNICODE(v), buflen); if (s_buffer == NULL) - return PyErr_NoMemory(); - if (PyUnicode_EncodeDecimal(PyUnicode_AS_UNICODE(v), - PyUnicode_GET_SIZE(v), - s_buffer, - NULL)) - goto error; - s = s_buffer; - len = strlen(s); + return NULL; + /* Replace non-ASCII whitespace with ' ' */ + bufptr = PyUnicode_AS_UNICODE(s_buffer); + for (i = 0; i < buflen; i++) { + Py_UNICODE ch = bufptr[i]; + if (ch > 127 && Py_UNICODE_ISSPACE(ch)) + bufptr[i] = ' '; + } + s = _PyUnicode_AsStringAndSize(s_buffer, &len); + if (s == NULL) { + Py_DECREF(s_buffer); + return NULL; + } + last = s + len; } else if (PyObject_AsCharBuffer(v, &s, &len)) { PyErr_SetString(PyExc_TypeError, @@ -198,29 +205,27 @@ return NULL; } last = s + len; - - while (Py_ISSPACE(*s)) + /* strip space */ + while (s < last && Py_ISSPACE(*s)) s++; + while (s < last - 1 && Py_ISSPACE(last[-1])) + last--; /* We don't care about overflow or underflow. If the platform * supports them, infinities and signed zeroes (on underflow) are * fine. */ x = PyOS_string_to_double(s, (char **)&end, NULL); - if (x == -1.0 && PyErr_Occurred()) - goto error; - while (Py_ISSPACE(*end)) - end++; - if (end == last) - result = PyFloat_FromDouble(x); - else { - PyOS_snprintf(buffer, sizeof(buffer), - "invalid literal for float(): %.200s", s); - PyErr_SetString(PyExc_ValueError, buffer); + if (end != last) { + PyErr_Format(PyExc_ValueError, + "could not convert string to float: " + "%R", v); result = NULL; } + else if (x == -1.0 && PyErr_Occurred()) + result = NULL; + else + result = PyFloat_FromDouble(x); - error: - if (s_buffer) - PyMem_FREE(s_buffer); + Py_XDECREF(s_buffer); return result; } @@ -570,13 +575,11 @@ double a,b; CONVERT_TO_DOUBLE(v, a); CONVERT_TO_DOUBLE(w, b); -#ifdef Py_NAN if (b == 0.0) { PyErr_SetString(PyExc_ZeroDivisionError, "float division by zero"); return NULL; } -#endif PyFPE_START_PROTECT("divide", return 0) a = a / b; PyFPE_END_PROTECT(a) @@ -590,19 +593,24 @@ double mod; CONVERT_TO_DOUBLE(v, vx); CONVERT_TO_DOUBLE(w, wx); -#ifdef Py_NAN if (wx == 0.0) { PyErr_SetString(PyExc_ZeroDivisionError, "float modulo"); return NULL; } -#endif PyFPE_START_PROTECT("modulo", return 0) mod = fmod(vx, wx); - /* note: checking mod*wx < 0 is incorrect -- underflows to - 0 if wx < sqrt(smallest nonzero double) */ - if (mod && ((wx < 0) != (mod < 0))) { - mod += wx; + if (mod) { + /* ensure the remainder has the same sign as the denominator */ + if ((wx < 0) != (mod < 0)) { + mod += wx; + } + } + else { + /* the remainder is zero, and in the presence of signed zeroes + fmod returns different results across platforms; ensure + it has the same sign as the denominator. */ + mod = copysign(0.0, wx); } PyFPE_END_PROTECT(mod) return PyFloat_FromDouble(mod); @@ -638,11 +646,8 @@ else { /* the remainder is zero, and in the presence of signed zeroes fmod returns different results across platforms; ensure - it has the same sign as the denominator; we'd like to do - "mod = wx * 0.0", but that may get optimized away */ - mod *= mod; /* hide "mod = +0" from optimizer */ - if (wx < 0.0) - mod = -mod; + it has the same sign as the denominator. */ + mod = copysign(0.0, wx); } /* snap quotient to nearest integral value */ if (div) { @@ -652,8 +657,7 @@ } else { /* div is zero - get the same sign as the true quotient */ - div *= div; /* hide "div = +0" from optimizers */ - floordiv = div * vx / wx; /* zero w/ sign of vx/wx */ + floordiv = copysign(0.0, vx / wx); /* zero w/ sign of vx/wx */ } PyFPE_END_PROTECT(floordiv) return Py_BuildValue("(dd)", floordiv, mod); @@ -1487,13 +1491,11 @@ "Cannot pass infinity to float.as_integer_ratio."); return NULL; } -#ifdef Py_NAN if (Py_IS_NAN(self)) { PyErr_SetString(PyExc_ValueError, "Cannot pass NaN to float.as_integer_ratio."); return NULL; } -#endif PyFPE_START_PROTECT("as_integer_ratio", goto error); float_part = frexp(self, &exponent); /* self == float_part * 2**exponent exactly */ Modified: python/branches/py3k-cdecimal/Objects/funcobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/funcobject.c (original) +++ python/branches/py3k-cdecimal/Objects/funcobject.c Sun Jan 2 13:18:37 2011 @@ -3,7 +3,6 @@ #include "Python.h" #include "code.h" -#include "eval.h" #include "structmember.h" PyObject * @@ -628,7 +627,7 @@ } result = PyEval_EvalCodeEx( - (PyCodeObject *)PyFunction_GET_CODE(func), + PyFunction_GET_CODE(func), PyFunction_GET_GLOBALS(func), (PyObject *)NULL, &PyTuple_GET_ITEM(arg, 0), PyTuple_GET_SIZE(arg), k, nk, d, nd, Modified: python/branches/py3k-cdecimal/Objects/genobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/genobject.c (original) +++ python/branches/py3k-cdecimal/Objects/genobject.c Sun Jan 2 13:18:37 2011 @@ -2,8 +2,6 @@ #include "Python.h" #include "frameobject.h" -#include "genobject.h" -#include "ceval.h" #include "structmember.h" #include "opcode.h" Modified: python/branches/py3k-cdecimal/Objects/listobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/listobject.c (original) +++ python/branches/py3k-cdecimal/Objects/listobject.c Sun Jan 2 13:18:37 2011 @@ -940,6 +940,71 @@ * pieces to this algorithm; read listsort.txt for overviews and details. */ +/* A sortslice contains a pointer to an array of keys and a pointer to + * an array of corresponding values. In other words, keys[i] + * corresponds with values[i]. If values == NULL, then the keys are + * also the values. + * + * Several convenience routines are provided here, so that keys and + * values are always moved in sync. + */ + +typedef struct { + PyObject **keys; + PyObject **values; +} sortslice; + +Py_LOCAL_INLINE(void) +sortslice_copy(sortslice *s1, Py_ssize_t i, sortslice *s2, Py_ssize_t j) +{ + s1->keys[i] = s2->keys[j]; + if (s1->values != NULL) + s1->values[i] = s2->values[j]; +} + +Py_LOCAL_INLINE(void) +sortslice_copy_incr(sortslice *dst, sortslice *src) +{ + *dst->keys++ = *src->keys++; + if (dst->values != NULL) + *dst->values++ = *src->values++; +} + +Py_LOCAL_INLINE(void) +sortslice_copy_decr(sortslice *dst, sortslice *src) +{ + *dst->keys-- = *src->keys--; + if (dst->values != NULL) + *dst->values-- = *src->values--; +} + + +Py_LOCAL_INLINE(void) +sortslice_memcpy(sortslice *s1, Py_ssize_t i, sortslice *s2, Py_ssize_t j, + Py_ssize_t n) +{ + memcpy(&s1->keys[i], &s2->keys[j], sizeof(PyObject *) * n); + if (s1->values != NULL) + memcpy(&s1->values[i], &s2->values[j], sizeof(PyObject *) * n); +} + +Py_LOCAL_INLINE(void) +sortslice_memmove(sortslice *s1, Py_ssize_t i, sortslice *s2, Py_ssize_t j, + Py_ssize_t n) +{ + memmove(&s1->keys[i], &s2->keys[j], sizeof(PyObject *) * n); + if (s1->values != NULL) + memmove(&s1->values[i], &s2->values[j], sizeof(PyObject *) * n); +} + +Py_LOCAL_INLINE(void) +sortslice_advance(sortslice *slice, Py_ssize_t n) +{ + slice->keys += n; + if (slice->values != NULL) + slice->values += n; +} + /* Comparison function: PyObject_RichCompareBool with Py_LT. * Returns -1 on error, 1 if x < y, 0 if x >= y. */ @@ -965,19 +1030,19 @@ the input (nothing is lost or duplicated). */ static int -binarysort(PyObject **lo, PyObject **hi, PyObject **start) +binarysort(sortslice lo, PyObject **hi, PyObject **start) { register Py_ssize_t k; register PyObject **l, **p, **r; register PyObject *pivot; - assert(lo <= start && start <= hi); + assert(lo.keys <= start && start <= hi); /* assert [lo, start) is sorted */ - if (lo == start) + if (lo.keys == start) ++start; for (; start < hi; ++start) { /* set l to where *start belongs */ - l = lo; + l = lo.keys; r = start; pivot = *r; /* Invariants: @@ -1004,6 +1069,15 @@ for (p = start; p > l; --p) *p = *(p-1); *l = pivot; + if (lo.values != NULL) { + Py_ssize_t offset = lo.values - lo.keys; + p = start + offset; + pivot = *p; + l += offset; + for (p = start + offset; p > l; --p) + *p = *(p-1); + *l = pivot; + } } return 0; @@ -1272,7 +1346,7 @@ * a convenient way to pass state around among the helper functions. */ struct s_slice { - PyObject **base; + sortslice base; Py_ssize_t len; }; @@ -1286,7 +1360,7 @@ /* 'a' is temp storage to help with merges. It contains room for * alloced entries. */ - PyObject **a; /* may point to temparray below */ + sortslice a; /* may point to temparray below */ Py_ssize_t alloced; /* A stack of n pending runs yet to be merged. Run #i starts at @@ -1307,11 +1381,29 @@ /* Conceptually a MergeState's constructor. */ static void -merge_init(MergeState *ms) +merge_init(MergeState *ms, int list_size, int has_keyfunc) { assert(ms != NULL); - ms->a = ms->temparray; - ms->alloced = MERGESTATE_TEMP_SIZE; + if (has_keyfunc) { + /* The temporary space for merging will need at most half the list + * size rounded up. Use the minimum possible space so we can use the + * rest of temparray for other things. In particular, if there is + * enough extra space, listsort() will use it to store the keys. + */ + ms->alloced = (list_size + 1) / 2; + + /* ms->alloced describes how many keys will be stored at + ms->temparray, but we also need to store the values. Hence, + ms->alloced is capped at half of MERGESTATE_TEMP_SIZE. */ + if (MERGESTATE_TEMP_SIZE / 2 < ms->alloced) + ms->alloced = MERGESTATE_TEMP_SIZE / 2; + ms->a.values = &ms->temparray[ms->alloced]; + } + else { + ms->alloced = MERGESTATE_TEMP_SIZE; + ms->a.values = NULL; + } + ms->a.keys = ms->temparray; ms->n = 0; ms->min_gallop = MIN_GALLOP; } @@ -1324,10 +1416,8 @@ merge_freemem(MergeState *ms) { assert(ms != NULL); - if (ms->a != ms->temparray) - PyMem_Free(ms->a); - ms->a = ms->temparray; - ms->alloced = MERGESTATE_TEMP_SIZE; + if (ms->a.keys != ms->temparray) + PyMem_Free(ms->a.keys); } /* Ensure enough temp memory for 'need' array slots is available. @@ -1336,52 +1426,60 @@ static int merge_getmem(MergeState *ms, Py_ssize_t need) { + int multiplier; + assert(ms != NULL); if (need <= ms->alloced) return 0; + + multiplier = ms->a.values != NULL ? 2 : 1; + /* Don't realloc! That can cost cycles to copy the old data, but * we don't care what's in the block. */ merge_freemem(ms); - if ((size_t)need > PY_SSIZE_T_MAX / sizeof(PyObject*)) { + if ((size_t)need > PY_SSIZE_T_MAX / sizeof(PyObject*) / multiplier) { PyErr_NoMemory(); return -1; } - ms->a = (PyObject **)PyMem_Malloc(need * sizeof(PyObject*)); - if (ms->a) { + ms->a.keys = (PyObject**)PyMem_Malloc(multiplier * need + * sizeof(PyObject *)); + if (ms->a.keys != NULL) { ms->alloced = need; + if (ms->a.values != NULL) + ms->a.values = &ms->a.keys[need]; return 0; } PyErr_NoMemory(); - merge_freemem(ms); /* reset to sane state */ return -1; } #define MERGE_GETMEM(MS, NEED) ((NEED) <= (MS)->alloced ? 0 : \ merge_getmem(MS, NEED)) -/* Merge the na elements starting at pa with the nb elements starting at pb - * in a stable way, in-place. na and nb must be > 0, and pa + na == pb. - * Must also have that *pb < *pa, that pa[na-1] belongs at the end of the - * merge, and should have na <= nb. See listsort.txt for more info. - * Return 0 if successful, -1 if error. +/* Merge the na elements starting at ssa with the nb elements starting at + * ssb.keys = ssa.keys + na in a stable way, in-place. na and nb must be > 0. + * Must also have that ssa.keys[na-1] belongs at the end of the merge, and + * should have na <= nb. See listsort.txt for more info. Return 0 if + * successful, -1 if error. */ static Py_ssize_t -merge_lo(MergeState *ms, PyObject **pa, Py_ssize_t na, - PyObject **pb, Py_ssize_t nb) +merge_lo(MergeState *ms, sortslice ssa, Py_ssize_t na, + sortslice ssb, Py_ssize_t nb) { Py_ssize_t k; - PyObject **dest; + sortslice dest; int result = -1; /* guilty until proved innocent */ Py_ssize_t min_gallop; - assert(ms && pa && pb && na > 0 && nb > 0 && pa + na == pb); + assert(ms && ssa.keys && ssb.keys && na > 0 && nb > 0); + assert(ssa.keys + na == ssb.keys); if (MERGE_GETMEM(ms, na) < 0) return -1; - memcpy(ms->a, pa, na * sizeof(PyObject*)); - dest = pa; - pa = ms->a; + sortslice_memcpy(&ms->a, 0, &ssa, 0, na); + dest = ssa; + ssa = ms->a; - *dest++ = *pb++; + sortslice_copy_incr(&dest, &ssb); --nb; if (nb == 0) goto Succeed; @@ -1398,11 +1496,11 @@ */ for (;;) { assert(na > 1 && nb > 0); - k = ISLT(*pb, *pa); + k = ISLT(ssb.keys[0], ssa.keys[0]); if (k) { if (k < 0) goto Fail; - *dest++ = *pb++; + sortslice_copy_incr(&dest, &ssb); ++bcount; acount = 0; --nb; @@ -1412,7 +1510,7 @@ break; } else { - *dest++ = *pa++; + sortslice_copy_incr(&dest, &ssa); ++acount; bcount = 0; --na; @@ -1433,14 +1531,14 @@ assert(na > 1 && nb > 0); min_gallop -= min_gallop > 1; ms->min_gallop = min_gallop; - k = gallop_right(*pb, pa, na, 0); + k = gallop_right(ssb.keys[0], ssa.keys, na, 0); acount = k; if (k) { if (k < 0) goto Fail; - memcpy(dest, pa, k * sizeof(PyObject *)); - dest += k; - pa += k; + sortslice_memcpy(&dest, 0, &ssa, 0, k); + sortslice_advance(&dest, k); + sortslice_advance(&ssa, k); na -= k; if (na == 1) goto CopyB; @@ -1451,24 +1549,24 @@ if (na == 0) goto Succeed; } - *dest++ = *pb++; + sortslice_copy_incr(&dest, &ssb); --nb; if (nb == 0) goto Succeed; - k = gallop_left(*pa, pb, nb, 0); + k = gallop_left(ssa.keys[0], ssb.keys, nb, 0); bcount = k; if (k) { if (k < 0) goto Fail; - memmove(dest, pb, k * sizeof(PyObject *)); - dest += k; - pb += k; + sortslice_memmove(&dest, 0, &ssb, 0, k); + sortslice_advance(&dest, k); + sortslice_advance(&ssb, k); nb -= k; if (nb == 0) goto Succeed; } - *dest++ = *pa++; + sortslice_copy_incr(&dest, &ssa); --na; if (na == 1) goto CopyB; @@ -1480,43 +1578,46 @@ result = 0; Fail: if (na) - memcpy(dest, pa, na * sizeof(PyObject*)); + sortslice_memcpy(&dest, 0, &ssa, 0, na); return result; CopyB: assert(na == 1 && nb > 0); - /* The last element of pa belongs at the end of the merge. */ - memmove(dest, pb, nb * sizeof(PyObject *)); - dest[nb] = *pa; + /* The last element of ssa belongs at the end of the merge. */ + sortslice_memmove(&dest, 0, &ssb, 0, nb); + sortslice_copy(&dest, nb, &ssa, 0); return 0; } -/* Merge the na elements starting at pa with the nb elements starting at pb - * in a stable way, in-place. na and nb must be > 0, and pa + na == pb. - * Must also have that *pb < *pa, that pa[na-1] belongs at the end of the - * merge, and should have na >= nb. See listsort.txt for more info. - * Return 0 if successful, -1 if error. +/* Merge the na elements starting at pa with the nb elements starting at + * ssb.keys = ssa.keys + na in a stable way, in-place. na and nb must be > 0. + * Must also have that ssa.keys[na-1] belongs at the end of the merge, and + * should have na >= nb. See listsort.txt for more info. Return 0 if + * successful, -1 if error. */ static Py_ssize_t -merge_hi(MergeState *ms, PyObject **pa, Py_ssize_t na, PyObject **pb, Py_ssize_t nb) +merge_hi(MergeState *ms, sortslice ssa, Py_ssize_t na, + sortslice ssb, Py_ssize_t nb) { Py_ssize_t k; - PyObject **dest; + sortslice dest, basea, baseb; int result = -1; /* guilty until proved innocent */ - PyObject **basea; - PyObject **baseb; Py_ssize_t min_gallop; - assert(ms && pa && pb && na > 0 && nb > 0 && pa + na == pb); + assert(ms && ssa.keys && ssb.keys && na > 0 && nb > 0); + assert(ssa.keys + na == ssb.keys); if (MERGE_GETMEM(ms, nb) < 0) return -1; - dest = pb + nb - 1; - memcpy(ms->a, pb, nb * sizeof(PyObject*)); - basea = pa; + dest = ssb; + sortslice_advance(&dest, nb-1); + sortslice_memcpy(&ms->a, 0, &ssb, 0, nb); + basea = ssa; baseb = ms->a; - pb = ms->a + nb - 1; - pa += na - 1; + ssb.keys = ms->a.keys + nb - 1; + if (ssb.values != NULL) + ssb.values = ms->a.values + nb - 1; + sortslice_advance(&ssa, na - 1); - *dest-- = *pa--; + sortslice_copy_decr(&dest, &ssa); --na; if (na == 0) goto Succeed; @@ -1533,11 +1634,11 @@ */ for (;;) { assert(na > 0 && nb > 1); - k = ISLT(*pb, *pa); + k = ISLT(ssb.keys[0], ssa.keys[0]); if (k) { if (k < 0) goto Fail; - *dest-- = *pa--; + sortslice_copy_decr(&dest, &ssa); ++acount; bcount = 0; --na; @@ -1547,7 +1648,7 @@ break; } else { - *dest-- = *pb--; + sortslice_copy_decr(&dest, &ssb); ++bcount; acount = 0; --nb; @@ -1568,33 +1669,33 @@ assert(na > 0 && nb > 1); min_gallop -= min_gallop > 1; ms->min_gallop = min_gallop; - k = gallop_right(*pb, basea, na, na-1); + k = gallop_right(ssb.keys[0], basea.keys, na, na-1); if (k < 0) goto Fail; k = na - k; acount = k; if (k) { - dest -= k; - pa -= k; - memmove(dest+1, pa+1, k * sizeof(PyObject *)); + sortslice_advance(&dest, -k); + sortslice_advance(&ssa, -k); + sortslice_memmove(&dest, 1, &ssa, 1, k); na -= k; if (na == 0) goto Succeed; } - *dest-- = *pb--; + sortslice_copy_decr(&dest, &ssb); --nb; if (nb == 1) goto CopyA; - k = gallop_left(*pa, baseb, nb, nb-1); + k = gallop_left(ssa.keys[0], baseb.keys, nb, nb-1); if (k < 0) goto Fail; k = nb - k; bcount = k; if (k) { - dest -= k; - pb -= k; - memcpy(dest+1, pb+1, k * sizeof(PyObject *)); + sortslice_advance(&dest, -k); + sortslice_advance(&ssb, -k); + sortslice_memcpy(&dest, 1, &ssb, 1, k); nb -= k; if (nb == 1) goto CopyA; @@ -1605,7 +1706,7 @@ if (nb == 0) goto Succeed; } - *dest-- = *pa--; + sortslice_copy_decr(&dest, &ssa); --na; if (na == 0) goto Succeed; @@ -1617,15 +1718,15 @@ result = 0; Fail: if (nb) - memcpy(dest-(nb-1), baseb, nb * sizeof(PyObject*)); + sortslice_memcpy(&dest, -(nb-1), &baseb, 0, nb); return result; CopyA: assert(nb == 1 && na > 0); - /* The first element of pb belongs at the front of the merge. */ - dest -= na; - pa -= na; - memmove(dest+1, pa+1, na * sizeof(PyObject *)); - *dest = *pb; + /* The first element of ssb belongs at the front of the merge. */ + sortslice_memmove(&dest, 1-na, &ssa, 1-na, na); + sortslice_advance(&dest, -na); + sortslice_advance(&ssa, -na); + sortslice_copy(&dest, 0, &ssb, 0); return 0; } @@ -1635,7 +1736,7 @@ static Py_ssize_t merge_at(MergeState *ms, Py_ssize_t i) { - PyObject **pa, **pb; + sortslice ssa, ssb; Py_ssize_t na, nb; Py_ssize_t k; @@ -1644,12 +1745,12 @@ assert(i >= 0); assert(i == ms->n - 2 || i == ms->n - 3); - pa = ms->pending[i].base; + ssa = ms->pending[i].base; na = ms->pending[i].len; - pb = ms->pending[i+1].base; + ssb = ms->pending[i+1].base; nb = ms->pending[i+1].len; assert(na > 0 && nb > 0); - assert(pa + na == pb); + assert(ssa.keys + na == ssb.keys); /* Record the length of the combined runs; if i is the 3rd-last * run now, also slide over the last run (which isn't involved @@ -1663,10 +1764,10 @@ /* Where does b start in a? Elements in a before that can be * ignored (already in place). */ - k = gallop_right(*pb, pa, na, 0); + k = gallop_right(*ssb.keys, ssa.keys, na, 0); if (k < 0) return -1; - pa += k; + sortslice_advance(&ssa, k); na -= k; if (na == 0) return 0; @@ -1674,7 +1775,7 @@ /* Where does a end in b? Elements in b after that can be * ignored (already in place). */ - nb = gallop_left(pa[na-1], pb, nb, nb-1); + nb = gallop_left(ssa.keys[na-1], ssb.keys, nb, nb-1); if (nb <= 0) return nb; @@ -1682,9 +1783,9 @@ * min(na, nb) elements. */ if (na <= nb) - return merge_lo(ms, pa, na, pb, nb); + return merge_lo(ms, ssa, na, ssb, nb); else - return merge_hi(ms, pa, na, pb, nb); + return merge_hi(ms, ssa, na, ssb, nb); } /* Examine the stack of runs waiting to be merged, merging adjacent runs @@ -1765,103 +1866,12 @@ return n + r; } -/* Special wrapper to support stable sorting using the decorate-sort-undecorate - pattern. Holds a key which is used for comparisons and the original record - which is returned during the undecorate phase. By exposing only the key - during comparisons, the underlying sort stability characteristics are left - unchanged. Also, the comparison function will only see the key instead of - a full record. */ - -typedef struct { - PyObject_HEAD - PyObject *key; - PyObject *value; -} sortwrapperobject; - -PyDoc_STRVAR(sortwrapper_doc, "Object wrapper with a custom sort key."); -static PyObject * -sortwrapper_richcompare(sortwrapperobject *, sortwrapperobject *, int); -static void -sortwrapper_dealloc(sortwrapperobject *); - -PyTypeObject PySortWrapper_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "sortwrapper", /* tp_name */ - sizeof(sortwrapperobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)sortwrapper_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - sortwrapper_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - (richcmpfunc)sortwrapper_richcompare, /* tp_richcompare */ -}; - - -static PyObject * -sortwrapper_richcompare(sortwrapperobject *a, sortwrapperobject *b, int op) -{ - if (!PyObject_TypeCheck(b, &PySortWrapper_Type)) { - PyErr_SetString(PyExc_TypeError, - "expected a sortwrapperobject"); - return NULL; - } - return PyObject_RichCompare(a->key, b->key, op); -} - static void -sortwrapper_dealloc(sortwrapperobject *so) -{ - Py_XDECREF(so->key); - Py_XDECREF(so->value); - PyObject_Del(so); -} - -/* Returns a new reference to a sortwrapper. - Consumes the references to the two underlying objects. */ - -static PyObject * -build_sortwrapper(PyObject *key, PyObject *value) -{ - sortwrapperobject *so; - - so = PyObject_New(sortwrapperobject, &PySortWrapper_Type); - if (so == NULL) - return NULL; - so->key = key; - so->value = value; - return (PyObject *)so; -} - -/* Returns a new reference to the value underlying the wrapper. */ -static PyObject * -sortwrapper_getvalue(PyObject *so) +reverse_sortslice(sortslice *s, Py_ssize_t n) { - PyObject *value; - - if (!PyObject_TypeCheck(so, &PySortWrapper_Type)) { - PyErr_SetString(PyExc_TypeError, - "expected a sortwrapperobject"); - return NULL; - } - value = ((sortwrapperobject *)so)->value; - Py_INCREF(value); - return value; + reverse_slice(s->keys, &s->keys[n]); + if (s->values != NULL) + reverse_slice(s->values, &s->values[n]); } /* An adaptive, stable, natural mergesort. See listsort.txt. @@ -1873,9 +1883,9 @@ listsort(PyListObject *self, PyObject *args, PyObject *kwds) { MergeState ms; - PyObject **lo, **hi; Py_ssize_t nremaining; Py_ssize_t minrun; + sortslice lo; Py_ssize_t saved_ob_size, saved_allocated; PyObject **saved_ob_item; PyObject **final_ob_item; @@ -1883,8 +1893,8 @@ int reverse = 0; PyObject *keyfunc = NULL; Py_ssize_t i; - PyObject *key, *value, *kvpair; static char *kwlist[] = {"key", "reverse", 0}; + PyObject **keys; assert(self != NULL); assert (PyList_Check(self)); @@ -1913,28 +1923,36 @@ self->ob_item = NULL; self->allocated = -1; /* any operation will reset it to >= 0 */ - if (keyfunc != NULL) { - for (i=0 ; i < saved_ob_size ; i++) { - value = saved_ob_item[i]; - key = PyObject_CallFunctionObjArgs(keyfunc, value, - NULL); - if (key == NULL) { - for (i=i-1 ; i>=0 ; i--) { - kvpair = saved_ob_item[i]; - value = sortwrapper_getvalue(kvpair); - saved_ob_item[i] = value; - Py_DECREF(kvpair); - } - goto dsu_fail; + if (keyfunc == NULL) { + keys = NULL; + lo.keys = saved_ob_item; + lo.values = NULL; + } + else { + if (saved_ob_size < MERGESTATE_TEMP_SIZE/2) + /* Leverage stack space we allocated but won't otherwise use */ + keys = &ms.temparray[saved_ob_size+1]; + else { + keys = PyMem_MALLOC(sizeof(PyObject *) * saved_ob_size); + if (keys == NULL) + return NULL; + } + + for (i = 0; i < saved_ob_size ; i++) { + keys[i] = PyObject_CallFunctionObjArgs(keyfunc, saved_ob_item[i], + NULL); + if (keys[i] == NULL) { + for (i=i-1 ; i>=0 ; i--) + Py_DECREF(keys[i]); + goto keyfunc_fail; } - kvpair = build_sortwrapper(key, value); - if (kvpair == NULL) - goto dsu_fail; - saved_ob_item[i] = kvpair; } + + lo.keys = keys; + lo.values = saved_ob_item; } - merge_init(&ms); + merge_init(&ms, saved_ob_size, keys != NULL); nremaining = saved_ob_size; if (nremaining < 2) @@ -1942,30 +1960,31 @@ /* Reverse sort stability achieved by initially reversing the list, applying a stable forward sort, then reversing the final result. */ - if (reverse) - reverse_slice(saved_ob_item, saved_ob_item + saved_ob_size); + if (reverse) { + if (keys != NULL) + reverse_slice(&keys[0], &keys[saved_ob_size]); + reverse_slice(&saved_ob_item[0], &saved_ob_item[saved_ob_size]); + } /* March over the array once, left to right, finding natural runs, * and extending short natural runs to minrun elements. */ - lo = saved_ob_item; - hi = lo + nremaining; minrun = merge_compute_minrun(nremaining); do { int descending; Py_ssize_t n; /* Identify next run. */ - n = count_run(lo, hi, &descending); + n = count_run(lo.keys, lo.keys + nremaining, &descending); if (n < 0) goto fail; if (descending) - reverse_slice(lo, lo + n); + reverse_sortslice(&lo, n); /* If short, extend to min(minrun, nremaining). */ if (n < minrun) { const Py_ssize_t force = nremaining <= minrun ? nremaining : minrun; - if (binarysort(lo, lo + force, lo + n) < 0) + if (binarysort(lo, lo.keys + force, lo.keys + n) < 0) goto fail; n = force; } @@ -1977,27 +1996,27 @@ if (merge_collapse(&ms) < 0) goto fail; /* Advance to find next run. */ - lo += n; + sortslice_advance(&lo, n); nremaining -= n; } while (nremaining); - assert(lo == hi); if (merge_force_collapse(&ms) < 0) goto fail; assert(ms.n == 1); - assert(ms.pending[0].base == saved_ob_item); + assert(keys == NULL + ? ms.pending[0].base.keys == saved_ob_item + : ms.pending[0].base.keys == &keys[0]); assert(ms.pending[0].len == saved_ob_size); + lo = ms.pending[0].base; succeed: result = Py_None; fail: - if (keyfunc != NULL) { - for (i=0 ; i < saved_ob_size ; i++) { - kvpair = saved_ob_item[i]; - value = sortwrapper_getvalue(kvpair); - saved_ob_item[i] = value; - Py_DECREF(kvpair); - } + if (keys != NULL) { + for (i = 0; i < saved_ob_size; i++) + Py_DECREF(keys[i]); + if (keys != &ms.temparray[saved_ob_size+1]) + PyMem_FREE(keys); } if (self->allocated != -1 && result != NULL) { @@ -2013,7 +2032,7 @@ merge_freemem(&ms); -dsu_fail: +keyfunc_fail: final_ob_item = self->ob_item; i = Py_SIZE(self); Py_SIZE(self) = saved_ob_size; @@ -2378,7 +2397,7 @@ PyObject* it; PyObject **src, **dest; - if (PySlice_GetIndicesEx((PySliceObject*)item, Py_SIZE(self), + if (PySlice_GetIndicesEx(item, Py_SIZE(self), &start, &stop, &step, &slicelength) < 0) { return NULL; } @@ -2427,7 +2446,7 @@ else if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength; - if (PySlice_GetIndicesEx((PySliceObject*)item, Py_SIZE(self), + if (PySlice_GetIndicesEx(item, Py_SIZE(self), &start, &stop, &step, &slicelength) < 0) { return -1; } @@ -2862,4 +2881,3 @@ len = 0; return PyLong_FromSsize_t(len); } - Modified: python/branches/py3k-cdecimal/Objects/longobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/longobject.c (original) +++ python/branches/py3k-cdecimal/Objects/longobject.c Sun Jan 2 13:18:37 2011 @@ -4,7 +4,6 @@ #include "Python.h" #include "longintrepr.h" -#include "structseq.h" #include #include @@ -2134,17 +2133,34 @@ PyLong_FromUnicode(Py_UNICODE *u, Py_ssize_t length, int base) { PyObject *result; - char *buffer = (char *)PyMem_MALLOC(length+1); - - if (buffer == NULL) - return NULL; - - if (PyUnicode_EncodeDecimal(u, length, buffer, NULL)) { - PyMem_FREE(buffer); + PyObject *asciidig; + char *buffer, *end; + Py_ssize_t i, buflen; + Py_UNICODE *ptr; + + asciidig = PyUnicode_TransformDecimalToASCII(u, length); + if (asciidig == NULL) + return NULL; + /* Replace non-ASCII whitespace with ' ' */ + ptr = PyUnicode_AS_UNICODE(asciidig); + for (i = 0; i < length; i++) { + Py_UNICODE ch = ptr[i]; + if (ch > 127 && Py_UNICODE_ISSPACE(ch)) + ptr[i] = ' '; + } + buffer = _PyUnicode_AsStringAndSize(asciidig, &buflen); + if (buffer == NULL) { + Py_DECREF(asciidig); return NULL; } - result = PyLong_FromString(buffer, NULL, base); - PyMem_FREE(buffer); + result = PyLong_FromString(buffer, &end, base); + if (result != NULL && end != buffer + buflen) { + PyErr_SetString(PyExc_ValueError, + "null byte in argument for int()"); + Py_DECREF(result); + result = NULL; + } + Py_DECREF(asciidig); return result; } Modified: python/branches/py3k-cdecimal/Objects/memoryobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/memoryobject.c (original) +++ python/branches/py3k-cdecimal/Objects/memoryobject.c Sun Jan 2 13:18:37 2011 @@ -599,7 +599,7 @@ else if (PySlice_Check(key)) { Py_ssize_t start, stop, step, slicelength; - if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view), + if (PySlice_GetIndicesEx(key, get_shape0(view), &start, &stop, &step, &slicelength) < 0) { return NULL; } @@ -678,7 +678,7 @@ else if (PySlice_Check(key)) { Py_ssize_t stop, step; - if (PySlice_GetIndicesEx((PySliceObject*)key, get_shape0(view), + if (PySlice_GetIndicesEx(key, get_shape0(view), &start, &stop, &step, &len) < 0) { return -1; } Modified: python/branches/py3k-cdecimal/Objects/moduleobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/moduleobject.c (original) +++ python/branches/py3k-cdecimal/Objects/moduleobject.c Sun Jan 2 13:18:37 2011 @@ -63,8 +63,9 @@ PyMethodDef *ml; const char* name; PyModuleObject *m; - if (!Py_IsInitialized()) - Py_FatalError("Interpreter not initialized (version mismatch?)"); + PyInterpreterState *interp = PyThreadState_Get()->interp; + if (interp->modules == NULL) + Py_FatalError("Python import machinery not initialized"); if (PyType_Ready(&moduledef_type) < 0) return NULL; if (module->m_base.m_index == 0) { @@ -74,7 +75,7 @@ module->m_base.m_index = max_module_number; } name = module->m_name; - if (module_api_version != PYTHON_API_VERSION) { + if (module_api_version != PYTHON_API_VERSION && module_api_version != PYTHON_ABI_VERSION) { int err; err = PyErr_WarnFormat(PyExc_RuntimeWarning, 1, "Python C API version mismatch for module %.100s: " Modified: python/branches/py3k-cdecimal/Objects/object.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/object.c (original) +++ python/branches/py3k-cdecimal/Objects/object.c Sun Jan 2 13:18:37 2011 @@ -2,7 +2,6 @@ /* Generic object operations; and implementation of None (NoObject) */ #include "Python.h" -#include "sliceobject.h" /* For PyEllipsis_Type */ #include "frameobject.h" #ifdef __cplusplus @@ -1756,7 +1755,6 @@ #endif - /* Hack to force loading of pycapsule.o */ PyTypeObject *_PyCapsule_hack = &PyCapsule_Type; @@ -1901,6 +1899,19 @@ } } +#ifndef Py_TRACE_REFS +/* For Py_LIMITED_API, we need an out-of-line version of _Py_Dealloc. + Define this here, so we can undefine the macro. */ +#undef _Py_Dealloc +PyAPI_FUNC(void) _Py_Dealloc(PyObject *); +void +_Py_Dealloc(PyObject *op) +{ + _Py_INC_TPFREES(op) _Py_COUNT_ALLOCS_COMMA + (*Py_TYPE(op)->tp_dealloc)(op); +} +#endif + #ifdef __cplusplus } #endif Modified: python/branches/py3k-cdecimal/Objects/obmalloc.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/obmalloc.c (original) +++ python/branches/py3k-cdecimal/Objects/obmalloc.c Sun Jan 2 13:18:37 2011 @@ -249,7 +249,7 @@ /* Pool for small blocks. */ struct pool_header { union { block *_padding; - uint count; } ref; /* number of allocated blocks */ + uint count; } ref; /* number of allocated blocks */ block *freeblock; /* pool's free list head */ struct pool_header *nextpool; /* next pool of this size class */ struct pool_header *prevpool; /* previous pool "" */ @@ -404,7 +404,7 @@ immediately follow a pool_header's first two members: union { block *_padding; - uint count; } ref; + uint count; } ref; block *freeblock; each of which consume sizeof(block *) bytes. So what usedpools[i+i] really @@ -709,7 +709,7 @@ #undef Py_ADDRESS_IN_RANGE #if defined(__GNUC__) && ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 1) || \ - (__GNUC__ >= 4)) + (__GNUC__ >= 4)) #define Py_NO_INLINE __attribute__((__noinline__)) #else #define Py_NO_INLINE @@ -1514,7 +1514,7 @@ if (nbytes > original_nbytes) { /* growing: mark new extra memory clean */ memset(q + original_nbytes, CLEANBYTE, - nbytes - original_nbytes); + nbytes - original_nbytes); } return q; @@ -1641,11 +1641,11 @@ fputs("FORBIDDENBYTE, as expected.\n", stderr); else { fprintf(stderr, "not all FORBIDDENBYTE (0x%02x):\n", - FORBIDDENBYTE); + FORBIDDENBYTE); for (i = 0; i < SST; ++i) { const uchar byte = tail[i]; fprintf(stderr, " at tail+%d: 0x%02x", - i, byte); + i, byte); if (byte != FORBIDDENBYTE) fputs(" *** OUCH", stderr); fputc('\n', stderr); @@ -1751,7 +1751,7 @@ char buf[128]; fprintf(stderr, "Small block threshold = %d, in %u size classes.\n", - SMALL_REQUEST_THRESHOLD, numclasses); + SMALL_REQUEST_THRESHOLD, numclasses); for (i = 0; i < numclasses; ++i) numpools[i] = numblocks[i] = numfreeblocks[i] = 0; @@ -1809,7 +1809,7 @@ fputc('\n', stderr); fputs("class size num pools blocks in use avail blocks\n" "----- ---- --------- ------------- ------------\n", - stderr); + stderr); for (i = 0; i < numclasses; ++i) { size_t p = numpools[i]; @@ -1824,7 +1824,7 @@ "%11" PY_FORMAT_SIZE_T "u " "%15" PY_FORMAT_SIZE_T "u " "%13" PY_FORMAT_SIZE_T "u\n", - i, size, p, b, f); + i, size, p, b, f); allocated_bytes += b * size; available_bytes += f * size; pool_header_bytes += p * POOL_OVERHEAD; Modified: python/branches/py3k-cdecimal/Objects/rangeobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/rangeobject.c (original) +++ python/branches/py3k-cdecimal/Objects/rangeobject.c Sun Jan 2 13:18:37 2011 @@ -14,6 +14,7 @@ PyObject *start; PyObject *stop; PyObject *step; + PyObject *length; } rangeobject; /* Helper function for validating step. Always returns a new reference or @@ -43,6 +44,31 @@ return step; } +static PyObject * +compute_range_length(PyObject *start, PyObject *stop, PyObject *step); + +static rangeobject * +make_range_object(PyTypeObject *type, PyObject *start, + PyObject *stop, PyObject *step) +{ + rangeobject *obj = NULL; + PyObject *length; + length = compute_range_length(start, stop, step); + if (length == NULL) { + return NULL; + } + obj = PyObject_New(rangeobject, type); + if (obj == NULL) { + Py_DECREF(length); + return NULL; + } + obj->start = start; + obj->stop = stop; + obj->step = step; + obj->length = length; + return obj; +} + /* XXX(nnorwitz): should we error check if the user passes any empty ranges? range(-10) range(0, -5) @@ -51,7 +77,7 @@ static PyObject * range_new(PyTypeObject *type, PyObject *args, PyObject *kw) { - rangeobject *obj = NULL; + rangeobject *obj; PyObject *start = NULL, *stop = NULL, *step = NULL; if (!_PyArg_NoKeywords("range()", kw)) @@ -97,15 +123,11 @@ } } - obj = PyObject_New(rangeobject, &PyRange_Type); - if (obj == NULL) - goto Fail; - obj->start = start; - obj->stop = stop; - obj->step = step; - return (PyObject *) obj; + obj = make_range_object(type, start, stop, step); + if (obj != NULL) + return (PyObject *) obj; -Fail: + /* Failed to create object, release attributes */ Py_XDECREF(start); Py_XDECREF(stop); Py_XDECREF(step); @@ -115,7 +137,7 @@ PyDoc_STRVAR(range_doc, "range([start,] stop[, step]) -> range object\n\ \n\ -Returns an iterator that generates the numbers in the range on demand."); +Returns a virtual sequence of numbers from start to stop by step."); static void range_dealloc(rangeobject *r) @@ -123,6 +145,7 @@ Py_DECREF(r->start); Py_DECREF(r->stop); Py_DECREF(r->step); + Py_DECREF(r->length); PyObject_Del(r); } @@ -131,7 +154,7 @@ * PyLong_Check(). Return NULL when there is an error. */ static PyObject* -range_length_obj(rangeobject *r) +compute_range_length(PyObject *start, PyObject *stop, PyObject *step) { /* ------------------------------------------------------------- Algorithm is equal to that of get_len_of_range(), but it operates @@ -139,7 +162,6 @@ ---------------------------------------------------------------*/ int cmp_result; PyObject *lo, *hi; - PyObject *step = NULL; PyObject *diff = NULL; PyObject *one = NULL; PyObject *tmp1 = NULL, *tmp2 = NULL, *result; @@ -148,20 +170,19 @@ PyObject *zero = PyLong_FromLong(0); if (zero == NULL) return NULL; - cmp_result = PyObject_RichCompareBool(r->step, zero, Py_GT); + cmp_result = PyObject_RichCompareBool(step, zero, Py_GT); Py_DECREF(zero); if (cmp_result == -1) return NULL; if (cmp_result == 1) { - lo = r->start; - hi = r->stop; - step = r->step; + lo = start; + hi = stop; Py_INCREF(step); } else { - lo = r->stop; - hi = r->start; - step = PyNumber_Negative(r->step); + lo = stop; + hi = start; + step = PyNumber_Negative(step); if (!step) return NULL; } @@ -206,32 +227,15 @@ static Py_ssize_t range_length(rangeobject *r) { - PyObject *len = range_length_obj(r); - Py_ssize_t result = -1; - if (len) { - result = PyLong_AsSsize_t(len); - Py_DECREF(len); - } - return result; + return PyLong_AsSsize_t(r->length); } /* range(...)[x] is necessary for: seq[:] = range(...) */ - static PyObject * -range_item(rangeobject *r, Py_ssize_t i) +compute_range_item(rangeobject *r, Py_ssize_t i) { - Py_ssize_t len = range_length(r); PyObject *rem, *incr, *result; - /* XXX(nnorwitz): should negative indices be supported? */ - /* XXX(nnorwitz): should support range[x] where x > PY_SSIZE_T_MAX? */ - if (i < 0 || i >= len) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_IndexError, - "range object index out of range"); - return NULL; - } - /* XXX(nnorwitz): optimize for short ints. */ rem = PyLong_FromSsize_t(i); if (!rem) @@ -246,31 +250,22 @@ } static PyObject * -range_repr(rangeobject *r) +range_item(rangeobject *r, Py_ssize_t i) { - Py_ssize_t istep; - - /* Check for special case values for printing. We don't always - need the step value. We don't care about errors - (it means overflow), so clear the errors. */ - istep = PyNumber_AsSsize_t(r->step, NULL); - if (istep != 1 || (istep == -1 && PyErr_Occurred())) { - PyErr_Clear(); - } + /* XXX(nnorwitz): should we support range[x] where x > PY_SSIZE_T_MAX? */ + Py_ssize_t len = range_length(r); - if (istep == 1) - return PyUnicode_FromFormat("range(%R, %R)", r->start, r->stop); - else - return PyUnicode_FromFormat("range(%R, %R, %R)", - r->start, r->stop, r->step); -} + if (i < 0) + i += len; -/* Pickling support */ -static PyObject * -range_reduce(rangeobject *r, PyObject *args) -{ - return Py_BuildValue("(O(OOO))", Py_TYPE(r), - r->start, r->stop, r->step); + if (i < 0 || i >= len) { + /* Also handles case where len < 0 due to (e.g) OverflowError */ + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_IndexError, + "range object index out of range"); + return NULL; + } + return compute_range_item(r, i); } /* Assumes (PyLong_CheckExact(ob) || PyBool_Check(ob)) */ @@ -388,15 +383,110 @@ static PySequenceMethods range_as_sequence = { (lenfunc)range_length, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - (ssizeargfunc)range_item, /* sq_item */ - 0, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc)range_item, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ (objobjproc)range_contains, /* sq_contains */ }; +static PyObject * +range_repr(rangeobject *r) +{ + Py_ssize_t istep; + + /* Check for special case values for printing. We don't always + need the step value. We don't care about errors + (it means overflow), so clear the errors. */ + istep = PyNumber_AsSsize_t(r->step, NULL); + if (istep != 1 || (istep == -1 && PyErr_Occurred())) { + PyErr_Clear(); + } + + if (istep == 1) + return PyUnicode_FromFormat("range(%R, %R)", r->start, r->stop); + else + return PyUnicode_FromFormat("range(%R, %R, %R)", + r->start, r->stop, r->step); +} + +/* Pickling support */ +static PyObject * +range_reduce(rangeobject *r, PyObject *args) +{ + return Py_BuildValue("(O(OOO))", Py_TYPE(r), + r->start, r->stop, r->step); +} + +static PyObject * +range_subscript(rangeobject* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + return range_item(self, i); + } + if (PySlice_Check(item)) { + Py_ssize_t start, stop, step, len, rlen; + rangeobject *result; + PyObject *substart = NULL, *substep = NULL, *substop = NULL; + + rlen = range_length(self); + if (rlen < 0) { + return NULL; + } + + if (PySlice_GetIndicesEx(item, rlen, + &start, &stop, &step, &len) < 0) { + return NULL; + } + if (step == 1) { + substep = self->step; + Py_INCREF(substep); + } else { + /* NB: slice step != Py_None here */ + substep = PyNumber_Multiply(self->step, ((PySliceObject*)item)->step); + if (substep == NULL) + goto fail; + } + substart = compute_range_item(self, start); + if (substart == NULL) + goto fail; + if (len <= 0) { + substop = substart; + Py_INCREF(substop); + } + else { + substop = compute_range_item(self, stop); + if (substop == NULL) + goto fail; + } + result = make_range_object(Py_TYPE(self), substart, substop, substep); + if (result != NULL) + return (PyObject *) result; + fail: + Py_XDECREF(substart); + Py_XDECREF(substep); + Py_XDECREF(substop); + return NULL; + } + PyErr_Format(PyExc_TypeError, + "range indices must be integers or slices, not %.200s", + item->ob_type->tp_name); + return NULL; +} + + +static PyMappingMethods range_as_mapping = { + (lenfunc)range_length, /* mp_length */ + (binaryfunc)range_subscript, /* mp_subscript */ + (objobjargproc)0, /* mp_ass_subscript */ +}; + static PyObject * range_iter(PyObject *seq); static PyObject * range_reverse(PyObject *seq); @@ -431,7 +521,7 @@ (reprfunc)range_repr, /* tp_repr */ 0, /* tp_as_number */ &range_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ + &range_as_mapping, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ @@ -491,22 +581,6 @@ return PyLong_FromLong(r->len - r->index); } -typedef struct { - PyObject_HEAD - PyObject *index; - PyObject *start; - PyObject *step; - PyObject *len; -} longrangeiterobject; - -static PyObject * -longrangeiter_len(longrangeiterobject *r, PyObject *no_args) -{ - return PyNumber_Subtract(r->len, r->index); -} - -static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw); - PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); @@ -516,6 +590,8 @@ {NULL, NULL} /* sentinel */ }; +static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw); + PyTypeObject PyRangeIter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "range_iterator", /* tp_name */ @@ -590,7 +666,7 @@ is not representable as a C long, OverflowError is raised. */ static PyObject * -int_range_iter(long start, long stop, long step) +fast_range_iter(long start, long stop, long step) { rangeiterobject *it = PyObject_New(rangeiterobject, &PyRangeIter_Type); unsigned long ulen; @@ -622,7 +698,21 @@ &start, &stop, &step)) return NULL; - return int_range_iter(start, stop, step); + return fast_range_iter(start, stop, step); +} + +typedef struct { + PyObject_HEAD + PyObject *index; + PyObject *start; + PyObject *step; + PyObject *len; +} longrangeiterobject; + +static PyObject * +longrangeiter_len(longrangeiterobject *r, PyObject *no_args) +{ + return PyNumber_Subtract(r->len, r->index); } static PyMethodDef longrangeiter_methods[] = { @@ -736,7 +826,7 @@ PyErr_Clear(); goto long_range; } - int_it = int_range_iter(lstart, lstop, lstep); + int_it = fast_range_iter(lstart, lstop, lstep); if (int_it == NULL && PyErr_ExceptionMatches(PyExc_OverflowError)) { PyErr_Clear(); goto long_range; @@ -751,14 +841,11 @@ /* Do all initialization here, so we can DECREF on failure. */ it->start = r->start; it->step = r->step; + it->len = r->length; Py_INCREF(it->start); Py_INCREF(it->step); + Py_INCREF(it->len); - it->len = it->index = NULL; - - it->len = range_length_obj(r); - if (!it->len) - goto create_failure; it->index = PyLong_FromLong(0); if (!it->index) goto create_failure; @@ -775,7 +862,7 @@ { rangeobject *range = (rangeobject*) seq; longrangeiterobject *it; - PyObject *one, *sum, *diff, *len = NULL, *product; + PyObject *one, *sum, *diff, *product; long lstart, lstop, lstep, new_start, new_stop; unsigned long ulen; @@ -838,7 +925,7 @@ new_stop = lstart - lstep; new_start = (long)(new_stop + ulen * lstep); - return int_range_iter(new_start, new_stop, -lstep); + return fast_range_iter(new_start, new_stop, -lstep); long_range: it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type); @@ -846,18 +933,14 @@ return NULL; /* start + (len - 1) * step */ - len = range_length_obj(range); - if (!len) - goto create_failure; - - /* Steal reference to len. */ - it->len = len; + it->len = range->length; + Py_INCREF(it->len); one = PyLong_FromLong(1); if (!one) goto create_failure; - diff = PyNumber_Subtract(len, one); + diff = PyNumber_Subtract(it->len, one); Py_DECREF(one); if (!diff) goto create_failure; Modified: python/branches/py3k-cdecimal/Objects/setobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/setobject.c (original) +++ python/branches/py3k-cdecimal/Objects/setobject.c Sun Jan 2 13:18:37 2011 @@ -1525,6 +1525,20 @@ "Remove all elements of another set from this set."); static PyObject * +set_copy_and_difference(PySetObject *so, PyObject *other) +{ + PyObject *result; + + result = set_copy(so); + if (result == NULL) + return NULL; + if (set_difference_update_internal((PySetObject *) result, other) != -1) + return result; + Py_DECREF(result); + return NULL; +} + +static PyObject * set_difference(PySetObject *so, PyObject *other) { PyObject *result; @@ -1532,13 +1546,13 @@ Py_ssize_t pos = 0; if (!PyAnySet_Check(other) && !PyDict_CheckExact(other)) { - result = set_copy(so); - if (result == NULL) - return NULL; - if (set_difference_update_internal((PySetObject *)result, other) != -1) - return result; - Py_DECREF(result); - return NULL; + return set_copy_and_difference(so, other); + } + + /* If len(so) much more than len(other), it's more efficient to simply copy + * so and then iterate other looking for common elements. */ + if ((PySet_GET_SIZE(so) >> 2) > PyObject_Size(other)) { + return set_copy_and_difference(so, other); } result = make_new_set_basetype(Py_TYPE(so), NULL); @@ -1560,6 +1574,7 @@ return result; } + /* Iterate over so, checking for common elements in other. */ while (set_next(so, &pos, &entry)) { int rv = set_contains_entry((PySetObject *)other, entry); if (rv == -1) { Modified: python/branches/py3k-cdecimal/Objects/sliceobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/sliceobject.c (original) +++ python/branches/py3k-cdecimal/Objects/sliceobject.c Sun Jan 2 13:18:37 2011 @@ -99,9 +99,10 @@ } int -PySlice_GetIndices(PySliceObject *r, Py_ssize_t length, +PySlice_GetIndices(PyObject *_r, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step) { + PySliceObject *r = (PySliceObject*)_r; /* XXX support long ints */ if (r->step == Py_None) { *step = 1; @@ -130,10 +131,11 @@ } int -PySlice_GetIndicesEx(PySliceObject *r, Py_ssize_t length, +PySlice_GetIndicesEx(PyObject *_r, Py_ssize_t length, Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength) { + PySliceObject *r = (PySliceObject*)_r; /* this is harder to get right than you might think */ Py_ssize_t defstart, defstop; @@ -256,7 +258,7 @@ return NULL; } - if (PySlice_GetIndicesEx(self, ilen, &start, &stop, + if (PySlice_GetIndicesEx((PyObject*)self, ilen, &start, &stop, &step, &slicelength) < 0) { return NULL; } Modified: python/branches/py3k-cdecimal/Objects/stringlib/formatter.h ============================================================================== --- python/branches/py3k-cdecimal/Objects/stringlib/formatter.h (original) +++ python/branches/py3k-cdecimal/Objects/stringlib/formatter.h Sun Jan 2 13:18:37 2011 @@ -941,13 +941,8 @@ from a hard-code pseudo-locale */ LocaleInfo locale; - /* Alternate is not allowed on floats. */ - if (format->alternate) { - PyErr_SetString(PyExc_ValueError, - "Alternate form (#) not allowed in float format " - "specifier"); - goto done; - } + if (format->alternate) + flags |= Py_DTSF_ALT; if (type == '\0') { /* Omitted type specifier. Behaves in the same way as repr(x) @@ -1104,15 +1099,7 @@ from a hard-code pseudo-locale */ LocaleInfo locale; - /* Alternate is not allowed on complex. */ - if (format->alternate) { - PyErr_SetString(PyExc_ValueError, - "Alternate form (#) not allowed in complex format " - "specifier"); - goto done; - } - - /* Neither is zero pading. */ + /* Zero padding is not allowed. */ if (format->fill_char == '0') { PyErr_SetString(PyExc_ValueError, "Zero padding is not allowed in complex format " @@ -1135,6 +1122,9 @@ if (im == -1.0 && PyErr_Occurred()) goto done; + if (format->alternate) + flags |= Py_DTSF_ALT; + if (type == '\0') { /* Omitted type specifier. Should be like str(self). */ type = 'r'; Modified: python/branches/py3k-cdecimal/Objects/structseq.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/structseq.c (original) +++ python/branches/py3k-cdecimal/Objects/structseq.c Sun Jan 2 13:18:37 2011 @@ -3,7 +3,6 @@ #include "Python.h" #include "structmember.h" -#include "structseq.h" static char visible_length_key[] = "n_sequence_fields"; static char real_length_key[] = "n_fields"; @@ -44,6 +43,18 @@ return (PyObject*)obj; } +void +PyStructSequence_SetItem(PyObject* op, Py_ssize_t i, PyObject* v) +{ + PyStructSequence_SET_ITEM(op, i, v); +} + +PyObject* +PyStructSequence_GetItem(PyObject* op, Py_ssize_t i) +{ + return PyStructSequence_GET_ITEM(op, i); +} + static void structseq_dealloc(PyStructSequence *obj) { @@ -366,3 +377,11 @@ SET_DICT_FROM_INT(real_length_key, n_members); SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members); } + +PyTypeObject* +PyStructSequence_NewType(PyStructSequence_Desc *desc) +{ + PyTypeObject *result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); + PyStructSequence_InitType(result, desc); + return result; +} Modified: python/branches/py3k-cdecimal/Objects/tupleobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/tupleobject.c (original) +++ python/branches/py3k-cdecimal/Objects/tupleobject.c Sun Jan 2 13:18:37 2011 @@ -689,7 +689,7 @@ PyObject* it; PyObject **src, **dest; - if (PySlice_GetIndicesEx((PySliceObject*)item, + if (PySlice_GetIndicesEx(item, PyTuple_GET_SIZE(self), &start, &stop, &step, &slicelength) < 0) { return NULL; Modified: python/branches/py3k-cdecimal/Objects/typeobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/typeobject.c (original) +++ python/branches/py3k-cdecimal/Objects/typeobject.c Sun Jan 2 13:18:37 2011 @@ -2304,6 +2304,44 @@ return (PyObject *)type; } +static short slotoffsets[] = { + -1, /* invalid slot */ +#include "typeslots.inc" +}; + +PyObject* PyType_FromSpec(PyType_Spec *spec) +{ + PyHeapTypeObject *res = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); + char *res_start = (char*)res; + PyType_Slot *slot; + + res->ht_name = PyUnicode_FromString(spec->name); + if (!res->ht_name) + goto fail; + res->ht_type.tp_name = _PyUnicode_AsString(res->ht_name); + if (!res->ht_type.tp_name) + goto fail; + + res->ht_type.tp_basicsize = spec->basicsize; + res->ht_type.tp_itemsize = spec->itemsize; + res->ht_type.tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE; + + for (slot = spec->slots; slot->slot; slot++) { + if (slot->slot >= sizeof(slotoffsets)/sizeof(slotoffsets[0])) { + PyErr_SetString(PyExc_RuntimeError, "invalid slot offset"); + goto fail; + } + *(void**)(res_start + slotoffsets[slot->slot]) = slot->pfunc; + } + + return (PyObject*)res; + + fail: + Py_DECREF(res); + return NULL; +} + + /* Internal API to look for a name through the MRO. This returns a borrowed reference, and doesn't set an exception! */ PyObject * Modified: python/branches/py3k-cdecimal/Objects/unicodectype.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/unicodectype.c (original) +++ python/branches/py3k-cdecimal/Objects/unicodectype.c Sun Jan 2 13:18:37 2011 @@ -9,7 +9,6 @@ */ #include "Python.h" -#include "unicodeobject.h" #define ALPHA_MASK 0x01 #define DECIMAL_MASK 0x02 Modified: python/branches/py3k-cdecimal/Objects/unicodeobject.c ============================================================================== --- python/branches/py3k-cdecimal/Objects/unicodeobject.c (original) +++ python/branches/py3k-cdecimal/Objects/unicodeobject.c Sun Jan 2 13:18:37 2011 @@ -41,9 +41,6 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" -#include "bytes_methods.h" - -#include "unicodeobject.h" #include "ucnhash.h" #ifdef MS_WINDOWS @@ -1264,7 +1261,7 @@ } Py_ssize_t -PyUnicode_AsWideChar(PyUnicodeObject *unicode, +PyUnicode_AsWideChar(PyObject *unicode, wchar_t *w, Py_ssize_t size) { @@ -1272,7 +1269,7 @@ PyErr_BadInternalCall(); return -1; } - return unicode_aswidechar(unicode, w, size); + return unicode_aswidechar((PyUnicodeObject*)unicode, w, size); } wchar_t* @@ -6207,6 +6204,30 @@ return NULL; } +PyObject * +PyUnicode_TransformDecimalToASCII(Py_UNICODE *s, + Py_ssize_t length) +{ + PyObject *result; + Py_UNICODE *p; /* write pointer into result */ + Py_ssize_t i; + /* Copy to a new string */ + result = (PyObject *)_PyUnicode_New(length); + Py_UNICODE_COPY(PyUnicode_AS_UNICODE(result), s, length); + if (result == NULL) + return result; + p = PyUnicode_AS_UNICODE(result); + /* Iterate over code points */ + for (i = 0; i < length; i++) { + Py_UNICODE ch =s[i]; + if (ch > 127) { + int decimal = Py_UNICODE_TODECIMAL(ch); + if (decimal >= 0) + p[i] = '0' + decimal; + } + } + return result; +} /* --- Decimal Encoder ---------------------------------------------------- */ int PyUnicode_EncodeDecimal(Py_UNICODE *s, @@ -7425,26 +7446,11 @@ static char *kwlist[] = {"encoding", "errors", 0}; char *encoding = NULL; char *errors = NULL; - PyObject *v; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|ss:encode", kwlist, &encoding, &errors)) return NULL; - v = PyUnicode_AsEncodedString((PyObject *)self, encoding, errors); - if (v == NULL) - goto onError; - if (!PyBytes_Check(v)) { - PyErr_Format(PyExc_TypeError, - "encoder did not return a bytes object " - "(type=%.400s)", - Py_TYPE(v)->tp_name); - Py_DECREF(v); - return NULL; - } - return v; - - onError: - return NULL; + return PyUnicode_AsEncodedString((PyObject *)self, encoding, errors); } PyDoc_STRVAR(expandtabs__doc__, @@ -8945,6 +8951,13 @@ { return PyLong_FromLong(numfree); } + +static PyObject * +unicode__decimal2ascii(PyObject *self) +{ + return PyUnicode_TransformDecimalToASCII(PyUnicode_AS_UNICODE(self), + PyUnicode_GET_SIZE(self)); +} #endif PyDoc_STRVAR(startswith__doc__, @@ -9086,7 +9099,6 @@ return Py_BuildValue("(u#)", v->str, v->length); } - static PyMethodDef unicode_methods[] = { /* Order is according to common usage: often used methods should @@ -9143,8 +9155,9 @@ #endif #if 0 - /* This one is just used for debugging the implementation. */ + /* These methods are just used for debugging the implementation. */ {"freelistsize", (PyCFunction) unicode_freelistsize, METH_NOARGS}, + {"_decimal2ascii", (PyCFunction) unicode__decimal2ascii, METH_NOARGS}, #endif {"__getnewargs__", (PyCFunction)unicode_getnewargs, METH_NOARGS}, @@ -9195,7 +9208,7 @@ Py_UNICODE* result_buf; PyObject* result; - if (PySlice_GetIndicesEx((PySliceObject*)item, PyUnicode_GET_SIZE(self), + if (PySlice_GetIndicesEx(item, PyUnicode_GET_SIZE(self), &start, &stop, &step, &slicelength) < 0) { return NULL; } Modified: python/branches/py3k-cdecimal/PC/VC6/readme.txt ============================================================================== --- python/branches/py3k-cdecimal/PC/VC6/readme.txt (original) +++ python/branches/py3k-cdecimal/PC/VC6/readme.txt Sun Jan 2 13:18:37 2011 @@ -158,9 +158,17 @@ You can (theoretically) use any version of OpenSSL you like - the build process will automatically select the latest version. - You must also install ActivePerl from + You can install the NASM assembler from + http://www.nasm.us/ + for x86 builds. Put nasmw.exe anywhere in your PATH. + Note: recent releases of nasm only have nasm.exe. Just rename it to + nasmw.exe. + + You can also install ActivePerl from http://www.activestate.com/activeperl/ - as this is used by the OpenSSL build process. Complain to them . + if you like to use the official sources instead of the files from + python's subversion repository. The svn version contains pre-build + makefiles and assembly files. The MSVC project simply invokes PC/VC6/build_ssl.py to perform the build. This Python script locates and builds your OpenSSL Modified: python/branches/py3k-cdecimal/PC/getpathp.c ============================================================================== --- python/branches/py3k-cdecimal/PC/getpathp.c (original) +++ python/branches/py3k-cdecimal/PC/getpathp.c Sun Jan 2 13:18:37 2011 @@ -707,3 +707,38 @@ calculate_path(); return progpath; } + +/* Load python3.dll before loading any extension module that might refer + to it. That way, we can be sure that always the python3.dll corresponding + to this python DLL is loaded, not a python3.dll that might be on the path + by chance. + Return whether the DLL was found. +*/ +static int python3_checked = 0; +static HANDLE hPython3; +int +_Py_CheckPython3() +{ + wchar_t py3path[MAXPATHLEN+1]; + wchar_t *s; + if (python3_checked) + return hPython3 != NULL; + python3_checked = 1; + + /* If there is a python3.dll next to the python3y.dll, + assume this is a build tree; use that DLL */ + wcscpy(py3path, dllpath); + s = wcsrchr(py3path, L'\\'); + if (!s) + s = py3path; + wcscpy(s, L"\\python3.dll"); + hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + if (hPython3 != NULL) + return 1; + + /* Check sys.prefix\DLLs\python3.dll */ + wcscpy(py3path, Py_GetPrefix()); + wcscat(py3path, L"\\DLLs\\python3.dll"); + hPython3 = LoadLibraryExW(py3path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); + return hPython3 != NULL; +} Modified: python/branches/py3k-cdecimal/PC/pyconfig.h ============================================================================== --- python/branches/py3k-cdecimal/PC/pyconfig.h (original) +++ python/branches/py3k-cdecimal/PC/pyconfig.h Sun Jan 2 13:18:37 2011 @@ -318,8 +318,10 @@ /* So MSVC users need not specify the .lib file in their Makefile (other compilers are generally taken care of by distutils.) */ -# ifdef _DEBUG +# if defined(_DEBUG) # pragma comment(lib,"python32_d.lib") +# elif defined(Py_LIMITED_API) +# pragma comment(lib,"python3.lib") # else # pragma comment(lib,"python32.lib") # endif /* _DEBUG */ Modified: python/branches/py3k-cdecimal/PC/python_nt.rc ============================================================================== --- python/branches/py3k-cdecimal/PC/python_nt.rc (original) +++ python/branches/py3k-cdecimal/PC/python_nt.rc Sun Jan 2 13:18:37 2011 @@ -61,7 +61,7 @@ VALUE "FileDescription", "Python Core\0" VALUE "FileVersion", PYTHON_VERSION VALUE "InternalName", "Python DLL\0" - VALUE "LegalCopyright", "Copyright ? 2001-2010 Python Software Foundation. Copyright ? 2000 BeOpen.com. Copyright ? 1995-2001 CNRI. Copyright ? 1991-1995 SMC.\0" + VALUE "LegalCopyright", "Copyright ? 2001-2011 Python Software Foundation. Copyright ? 2000 BeOpen.com. Copyright ? 1995-2001 CNRI. Copyright ? 1991-1995 SMC.\0" VALUE "OriginalFilename", PYTHON_DLL_NAME "\0" VALUE "ProductName", "Python\0" VALUE "ProductVersion", PYTHON_VERSION Modified: python/branches/py3k-cdecimal/PCbuild/build_tkinter.py ============================================================================== --- python/branches/py3k-cdecimal/PCbuild/build_tkinter.py (original) +++ python/branches/py3k-cdecimal/PCbuild/build_tkinter.py Sun Jan 2 13:18:37 2011 @@ -11,8 +11,8 @@ here = os.path.abspath(os.path.dirname(__file__)) par = os.path.pardir -TCL = "tcl8.5.2" -TK = "tk8.5.2" +TCL = "tcl8.5.9" +TK = "tk8.5.9" TIX = "tix-8.4.3.x" ROOT = os.path.abspath(os.path.join(here, par, par)) Modified: python/branches/py3k-cdecimal/PCbuild/make_buildinfo.c ============================================================================== --- python/branches/py3k-cdecimal/PCbuild/make_buildinfo.c (original) +++ python/branches/py3k-cdecimal/PCbuild/make_buildinfo.c Sun Jan 2 13:18:37 2011 @@ -52,9 +52,9 @@ if (_stat(command+1, &st) < 0) /* subwcrev.exe not part of the release */ return 0; - strcat_s(command, CMD_SIZE, "\" .. ..\\Modules\\getbuildinfo.c "); - strcat_s(command, CMD_SIZE, tmppath); - strcat_s(command, CMD_SIZE, "getbuildinfo2.c"); + strcat_s(command, CMD_SIZE, "\" .. ..\\Modules\\getbuildinfo.c \""); + strcat_s(command, CMD_SIZE, tmppath); /* quoted tmppath */ + strcat_s(command, CMD_SIZE, "getbuildinfo2.c\""); puts(command); fflush(stdout); if (system(command) < 0) return 0; @@ -91,23 +91,36 @@ if (argc > 2) { tmpdir = argv[2]; strcat_s(tmppath, _countof(tmppath), tmpdir); + /* Hack fix for bad command line: If the command is issued like this: + * $(SolutionDir)make_buildinfo.exe" Debug "$(IntDir)" + * we will get a trailing quote because IntDir ends with a backslash that then + * escapes the final ". To simplify the life for developers, catch that problem + * here by cutting it off. + * The proper command line, btw is: + * $(SolutionDir)make_buildinfo.exe" Debug "$(IntDir)\" + * Hooray for command line parsing on windows. + */ + if (strlen(tmppath) > 0 && tmppath[strlen(tmppath)-1] == '"') + tmppath[strlen(tmppath)-1] = '\0'; strcat_s(tmppath, _countof(tmppath), "\\"); } if ((do_unlink = make_buildinfo2(tmppath))) { + strcat_s(command, CMD_SIZE, "\""); strcat_s(command, CMD_SIZE, tmppath); - strcat_s(command, CMD_SIZE, "getbuildinfo2.c -DSUBWCREV "); + strcat_s(command, CMD_SIZE, "getbuildinfo2.c\" -DSUBWCREV "); } else strcat_s(command, CMD_SIZE, "..\\Modules\\getbuildinfo.c"); - strcat_s(command, CMD_SIZE, " -Fo"); + strcat_s(command, CMD_SIZE, " -Fo\""); strcat_s(command, CMD_SIZE, tmppath); - strcat_s(command, CMD_SIZE, "getbuildinfo.o -I..\\Include -I..\\PC"); + strcat_s(command, CMD_SIZE, "getbuildinfo.o\" -I..\\Include -I..\\PC"); puts(command); fflush(stdout); result = system(command); if (do_unlink) { command[0] = '\0'; + strcat_s(command, CMD_SIZE, "\""); strcat_s(command, CMD_SIZE, tmppath); - strcat_s(command, CMD_SIZE, "getbuildinfo2.c"); + strcat_s(command, CMD_SIZE, "getbuildinfo2.c\""); _unlink(command); } if (result < 0) Modified: python/branches/py3k-cdecimal/PCbuild/pcbuild.sln ============================================================================== --- python/branches/py3k-cdecimal/PCbuild/pcbuild.sln (original) +++ python/branches/py3k-cdecimal/PCbuild/pcbuild.sln Sun Jan 2 13:18:37 2011 @@ -78,8 +78,8 @@ ProjectSection(ProjectDependencies) = postProject {B11D750F-CD1F-4A96-85CE-E69A5C5259F9} = {B11D750F-CD1F-4A96-85CE-E69A5C5259F9} {86937F53-C189-40EF-8CE8-8759D8E7D480} = {86937F53-C189-40EF-8CE8-8759D8E7D480} - {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} {E5B04CC0-EB4C-42AB-B4DC-18EF95F864B0} = {E5B04CC0-EB4C-42AB-B4DC-18EF95F864B0} + {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_testcapi", "_testcapi.vcproj", "{6901D91C-6E48-4BB7-9FEC-700C8131DF1D}" @@ -117,8 +117,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "_hashlib", "_hashlib.vcproj", "{447F05A8-F581-4CAC-A466-5AC7936E207E}" ProjectSection(ProjectDependencies) = postProject {B11D750F-CD1F-4A96-85CE-E69A5C5259F9} = {B11D750F-CD1F-4A96-85CE-E69A5C5259F9} - {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} {E5B04CC0-EB4C-42AB-B4DC-18EF95F864B0} = {E5B04CC0-EB4C-42AB-B4DC-18EF95F864B0} + {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} = {CF7AC3D1-E2DF-41D2-BEA6-1E2556CDEA26} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sqlite3", "sqlite3.vcproj", "{A1A295E5-463C-437F-81CA-1F32367685DA}" @@ -138,6 +138,10 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "kill_python", "kill_python.vcproj", "{6DE10744-E396-40A5-B4E2-1B69AA7C8D31}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "python3dll", "python3dll.vcproj", "{885D4898-D08D-4091-9C40-C700CFE3FC5A}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xxlimited", "xxlimited.vcproj", "{F749B822-B489-4CA5-A3AD-CE078F5F338A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -574,6 +578,37 @@ {6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Release|Win32.Build.0 = Release|Win32 {6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Release|x64.ActiveCfg = Release|x64 {6DE10744-E396-40A5-B4E2-1B69AA7C8D31}.Release|x64.Build.0 = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|Win32.ActiveCfg = PGInstrument|Win32 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.ActiveCfg = Debug|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Debug|x64.Build.0 = Debug|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.ActiveCfg = PGInstrument|Win32 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|Win32.Build.0 = PGInstrument|Win32 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.ActiveCfg = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGInstrument|x64.Build.0 = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.ActiveCfg = PGUpdate|Win32 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|Win32.Build.0 = PGUpdate|Win32 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.ActiveCfg = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.PGUpdate|x64.Build.0 = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.ActiveCfg = Release|Win32 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|Win32.Build.0 = Release|Win32 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|x64.ActiveCfg = Release|x64 + {885D4898-D08D-4091-9C40-C700CFE3FC5A}.Release|x64.Build.0 = Release|x64 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|Win32.ActiveCfg = Debug|Win32 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|Win32.Build.0 = Debug|Win32 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|x64.ActiveCfg = Debug|x64 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Debug|x64.Build.0 = Debug|x64 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|Win32.ActiveCfg = Release|Win32 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|Win32.Build.0 = Release|Win32 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|x64.ActiveCfg = Release|x64 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGInstrument|x64.Build.0 = Release|x64 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGUpdate|Win32.ActiveCfg = Release|Win32 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGUpdate|Win32.Build.0 = Release|Win32 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGUpdate|x64.ActiveCfg = Release|x64 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.PGUpdate|x64.Build.0 = Release|x64 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Release|Win32.ActiveCfg = Release|Win32 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Release|Win32.Build.0 = Release|Win32 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Release|x64.ActiveCfg = Release|x64 + {F749B822-B489-4CA5-A3AD-CE078F5F338A}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE Modified: python/branches/py3k-cdecimal/PCbuild/pyproject.vsprops ============================================================================== --- python/branches/py3k-cdecimal/PCbuild/pyproject.vsprops (original) +++ python/branches/py3k-cdecimal/PCbuild/pyproject.vsprops Sun Jan 2 13:18:37 2011 @@ -50,7 +50,7 @@ /> decoding_state == STATE_NORMAL) { /* We already have a codec associated with @@ -585,12 +586,16 @@ if (badchar) { /* Need to add 1 to the line number, since this line has not been counted, yet. */ - PyErr_Format(PyExc_SyntaxError, - "Non-UTF-8 code starting with '\\x%.2x' " - "in file %.200s on line %i, " - "but no encoding declared; " - "see http://python.org/dev/peps/pep-0263/ for details", - badchar, tok->filename, tok->lineno + 1); + filename = PyUnicode_DecodeFSDefault(tok->filename); + if (filename != NULL) { + PyErr_Format(PyExc_SyntaxError, + "Non-UTF-8 code starting with '\\x%.2x' " + "in file %.200U on line %i, " + "but no encoding declared; " + "see http://python.org/dev/peps/pep-0263/ for details", + badchar, filename, tok->lineno + 1); + Py_DECREF(filename); + } return error_ret(tok); } #endif Modified: python/branches/py3k-cdecimal/Python/_warnings.c ============================================================================== --- python/branches/py3k-cdecimal/Python/_warnings.c (original) +++ python/branches/py3k-cdecimal/Python/_warnings.c Sun Jan 2 13:18:37 2011 @@ -783,7 +783,7 @@ { PyObject *res; PyObject *message = PyUnicode_FromString(text); - PyObject *filename = PyUnicode_FromString(filename_str); + PyObject *filename = PyUnicode_DecodeFSDefault(filename_str); PyObject *module = NULL; int ret = -1; Modified: python/branches/py3k-cdecimal/Python/ast.c ============================================================================== --- python/branches/py3k-cdecimal/Python/ast.c (original) +++ python/branches/py3k-cdecimal/Python/ast.c Sun Jan 2 13:18:37 2011 @@ -7,7 +7,6 @@ #include "Python-ast.h" #include "grammar.h" #include "node.h" -#include "pyarena.h" #include "ast.h" #include "token.h" #include "parsetok.h" Modified: python/branches/py3k-cdecimal/Python/bltinmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Python/bltinmodule.c (original) +++ python/branches/py3k-cdecimal/Python/bltinmodule.c Sun Jan 2 13:18:37 2011 @@ -5,7 +5,6 @@ #include "node.h" #include "code.h" -#include "eval.h" #include @@ -311,6 +310,20 @@ Return the binary representation of an integer or long integer."); +static PyObject * +builtin_callable(PyObject *self, PyObject *v) +{ + return PyBool_FromLong((long)PyCallable_Check(v)); +} + +PyDoc_STRVAR(callable_doc, +"callable(object) -> bool\n\ +\n\ +Return whether the object is callable (i.e., some kind of function).\n\ +Note that classes are callable, as are instances of classes with a\n\ +__call__() method."); + + typedef struct { PyObject_HEAD PyObject *func; @@ -530,19 +543,20 @@ int mode = -1; int dont_inherit = 0; int supplied_flags = 0; + int optimize = -1; int is_ast; PyCompilerFlags cf; PyObject *cmd; static char *kwlist[] = {"source", "filename", "mode", "flags", - "dont_inherit", NULL}; + "dont_inherit", "optimize", NULL}; int start[] = {Py_file_input, Py_eval_input, Py_single_input}; PyObject *result; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&s|ii:compile", kwlist, + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&s|iii:compile", kwlist, &cmd, PyUnicode_FSConverter, &filename_obj, &startstr, &supplied_flags, - &dont_inherit)) + &dont_inherit, &optimize)) return NULL; filename = PyBytes_AS_STRING(filename_obj); @@ -557,6 +571,12 @@ } /* XXX Warn if (supplied_flags & PyCF_MASK_OBSOLETE) != 0? */ + if (optimize < -1 || optimize > 2) { + PyErr_SetString(PyExc_ValueError, + "compile(): invalid optimize value"); + goto error; + } + if (!dont_inherit) { PyEval_MergeCompilerFlags(&cf); } @@ -591,8 +611,8 @@ PyArena_Free(arena); goto error; } - result = (PyObject*)PyAST_Compile(mod, filename, - &cf, arena); + result = (PyObject*)PyAST_CompileEx(mod, filename, + &cf, optimize, arena); PyArena_Free(arena); } goto finally; @@ -602,7 +622,7 @@ if (str == NULL) goto error; - result = Py_CompileStringFlags(str, filename, start[mode], &cf); + result = Py_CompileStringExFlags(str, filename, start[mode], &cf, optimize); goto finally; error: @@ -714,7 +734,7 @@ "code object passed to eval() may not contain free variables"); return NULL; } - return PyEval_EvalCode((PyCodeObject *) cmd, globals, locals); + return PyEval_EvalCode(cmd, globals, locals); } cf.cf_flags = PyCF_SOURCE_IS_UTF8; @@ -790,7 +810,7 @@ "contain free variables"); return NULL; } - v = PyEval_EvalCode((PyCodeObject *) prog, globals, locals); + v = PyEval_EvalCode(prog, globals, locals); } else { char *str; @@ -2242,6 +2262,7 @@ {"any", builtin_any, METH_O, any_doc}, {"ascii", builtin_ascii, METH_O, ascii_doc}, {"bin", builtin_bin, METH_O, bin_doc}, + {"callable", builtin_callable, METH_O, callable_doc}, {"chr", builtin_chr, METH_VARARGS, chr_doc}, {"compile", (PyCFunction)builtin_compile, METH_VARARGS | METH_KEYWORDS, compile_doc}, {"delattr", builtin_delattr, METH_VARARGS, delattr_doc}, Modified: python/branches/py3k-cdecimal/Python/ceval.c ============================================================================== --- python/branches/py3k-cdecimal/Python/ceval.c (original) +++ python/branches/py3k-cdecimal/Python/ceval.c Sun Jan 2 13:18:37 2011 @@ -13,7 +13,6 @@ #include "code.h" #include "frameobject.h" -#include "eval.h" #include "opcode.h" #include "structmember.h" @@ -756,7 +755,7 @@ PyObject * -PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals) +PyEval_EvalCode(PyObject *co, PyObject *globals, PyObject *locals) { return PyEval_EvalCodeEx(co, globals, locals, @@ -3060,10 +3059,11 @@ the test in the if statements in Misc/gdbinit (pystack and pystackv). */ PyObject * -PyEval_EvalCodeEx(PyCodeObject *co, PyObject *globals, PyObject *locals, +PyEval_EvalCodeEx(PyObject *_co, PyObject *globals, PyObject *locals, PyObject **args, int argcount, PyObject **kws, int kwcount, PyObject **defs, int defcount, PyObject *kwdefs, PyObject *closure) { + PyCodeObject* co = (PyCodeObject*)_co; register PyFrameObject *f; register PyObject *retval = NULL; register PyObject **fastlocals, **freevars; @@ -3969,7 +3969,7 @@ d = &PyTuple_GET_ITEM(argdefs, 0); nd = Py_SIZE(argdefs); } - return PyEval_EvalCodeEx(co, globals, + return PyEval_EvalCodeEx((PyObject*)co, globals, (PyObject *)NULL, (*pp_stack)-n, na, (*pp_stack)-2*nk, nk, d, nd, kwdefs, PyFunction_GET_CLOSURE(func)); Modified: python/branches/py3k-cdecimal/Python/compile.c ============================================================================== --- python/branches/py3k-cdecimal/Python/compile.c (original) +++ python/branches/py3k-cdecimal/Python/compile.c Sun Jan 2 13:18:37 2011 @@ -25,10 +25,8 @@ #include "Python-ast.h" #include "node.h" -#include "pyarena.h" #include "ast.h" #include "code.h" -#include "compile.h" #include "symtable.h" #include "opcode.h" @@ -141,6 +139,7 @@ PyFutureFeatures *c_future; /* pointer to module's __future__ */ PyCompilerFlags *c_flags; + int c_optimize; /* optimization level */ int c_interactive; /* true if in interactive mode */ int c_nestlevel; @@ -177,7 +176,7 @@ static int compiler_in_loop(struct compiler *); static int inplace_binop(struct compiler *, operator_ty); -static int expr_constant(expr_ty e); +static int expr_constant(struct compiler *, expr_ty); static int compiler_with(struct compiler *, stmt_ty); static int compiler_call_helper(struct compiler *c, int n, @@ -256,8 +255,8 @@ } PyCodeObject * -PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags, - PyArena *arena) +PyAST_CompileEx(mod_ty mod, const char *filename, PyCompilerFlags *flags, + int optimize, PyArena *arena) { struct compiler c; PyCodeObject *co = NULL; @@ -285,6 +284,7 @@ c.c_future->ff_features = merged; flags->cf_flags = merged; c.c_flags = flags; + c.c_optimize = (optimize == -1) ? Py_OptimizeFlag : optimize; c.c_nestlevel = 0; c.c_st = PySymtable_Build(mod, filename, c.c_future); @@ -1151,7 +1151,7 @@ if (!asdl_seq_LEN(stmts)) return 1; st = (stmt_ty)asdl_seq_GET(stmts, 0); - if (compiler_isdocstring(st) && Py_OptimizeFlag < 2) { + if (compiler_isdocstring(st) && c->c_optimize < 2) { /* don't generate docstrings if -OO */ i = 1; VISIT(c, expr, st->v.Expr.value); @@ -1465,7 +1465,7 @@ st = (stmt_ty)asdl_seq_GET(s->v.FunctionDef.body, 0); docstring = compiler_isdocstring(st); - if (docstring && Py_OptimizeFlag < 2) + if (docstring && c->c_optimize < 2) first_const = st->v.Expr.value->v.Str.s; if (compiler_add_o(c, c->u->u_consts, first_const) < 0) { compiler_exit_scope(c); @@ -1699,7 +1699,7 @@ if (end == NULL) return 0; - constant = expr_constant(s->v.If.test); + constant = expr_constant(c, s->v.If.test); /* constant = 0: "if 0" * constant = 1: "if 1", "if 2", ... * constant = -1: rest */ @@ -1761,7 +1761,7 @@ compiler_while(struct compiler *c, stmt_ty s) { basicblock *loop, *orelse, *end, *anchor = NULL; - int constant = expr_constant(s->v.While.test); + int constant = expr_constant(c, s->v.While.test); if (constant == 0) { if (s->v.While.orelse) @@ -2213,7 +2213,7 @@ static PyObject *assertion_error = NULL; basicblock *end; - if (Py_OptimizeFlag) + if (c->c_optimize) return 1; if (assertion_error == NULL) { assertion_error = PyUnicode_InternFromString("AssertionError"); @@ -3013,7 +3013,7 @@ */ static int -expr_constant(expr_ty e) +expr_constant(struct compiler *c, expr_ty e) { char *id; switch (e->kind) { @@ -3031,7 +3031,7 @@ if (strcmp(id, "False") == 0) return 0; if (strcmp(id, "None") == 0) return 0; if (strcmp(id, "__debug__") == 0) - return ! Py_OptimizeFlag; + return ! c->c_optimize; /* fall through */ default: return -1; @@ -4082,3 +4082,13 @@ assemble_free(&a); return co; } + +#undef PyAST_Compile +PyAPI_FUNC(PyCodeObject *) +PyAST_Compile(mod_ty mod, const char *filename, PyCompilerFlags *flags, + PyArena *arena) +{ + return PyAST_CompileEx(mod, filename, flags, -1, arena); +} + + Modified: python/branches/py3k-cdecimal/Python/dynload_shlib.c ============================================================================== --- python/branches/py3k-cdecimal/Python/dynload_shlib.c (original) +++ python/branches/py3k-cdecimal/Python/dynload_shlib.c Sun Jan 2 13:18:37 2011 @@ -53,6 +53,8 @@ #else /* !__VMS */ {"." SOABI ".so", "rb", C_EXTENSION}, {"module." SOABI ".so", "rb", C_EXTENSION}, + {".abi" PYTHON_ABI_STRING ".so", "rb", C_EXTENSION}, + {"module.abi" PYTHON_ABI_STRING ".so", "rb", C_EXTENSION}, {".so", "rb", C_EXTENSION}, {"module.so", "rb", C_EXTENSION}, #endif /* __VMS */ Modified: python/branches/py3k-cdecimal/Python/dynload_win.c ============================================================================== --- python/branches/py3k-cdecimal/Python/dynload_win.c (original) +++ python/branches/py3k-cdecimal/Python/dynload_win.c Sun Jan 2 13:18:37 2011 @@ -134,6 +134,15 @@ !strncmp(import_name,"python",6)) { char *pch; +#ifndef _DEBUG + /* In a release version, don't claim that python3.dll is + a Python DLL. */ + if (strcmp(import_name, "python3.dll") == 0) { + import_data += 20; + continue; + } +#endif + /* Ensure python prefix is followed only by numbers to the end of the basename */ pch = import_name + 6; @@ -162,13 +171,16 @@ return NULL; } - dl_funcptr _PyImport_GetDynLoadFunc(const char *fqname, const char *shortname, const char *pathname, FILE *fp) { dl_funcptr p; char funcname[258], *import_python; +#ifndef _DEBUG + _Py_CheckPython3(); +#endif + PyOS_snprintf(funcname, sizeof(funcname), "PyInit_%.200s", shortname); { Modified: python/branches/py3k-cdecimal/Python/errors.c ============================================================================== --- python/branches/py3k-cdecimal/Python/errors.c (original) +++ python/branches/py3k-cdecimal/Python/errors.c Sun Jan 2 13:18:37 2011 @@ -515,7 +515,7 @@ int ierr, const char *filename) { - PyObject *name = filename ? PyUnicode_FromString(filename) : NULL; + PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; PyObject *ret = PyErr_SetExcFromWindowsErrWithFilenameObject(exc, ierr, name); @@ -552,7 +552,7 @@ int ierr, const char *filename) { - PyObject *name = filename ? PyUnicode_FromString(filename) : NULL; + PyObject *name = filename ? PyUnicode_DecodeFSDefault(filename) : NULL; PyObject *result = PyErr_SetExcFromWindowsErrWithFilenameObject( PyExc_WindowsError, ierr, name); Modified: python/branches/py3k-cdecimal/Python/future.c ============================================================================== --- python/branches/py3k-cdecimal/Python/future.c (original) +++ python/branches/py3k-cdecimal/Python/future.c Sun Jan 2 13:18:37 2011 @@ -4,7 +4,6 @@ #include "token.h" #include "graminit.h" #include "code.h" -#include "compile.h" #include "symtable.h" #define UNDEFINED_FUTURE_FEATURE "future feature %.100s is not defined" Modified: python/branches/py3k-cdecimal/Python/getcopyright.c ============================================================================== --- python/branches/py3k-cdecimal/Python/getcopyright.c (original) +++ python/branches/py3k-cdecimal/Python/getcopyright.c Sun Jan 2 13:18:37 2011 @@ -4,7 +4,7 @@ static char cprt[] = "\ -Copyright (c) 2001-2010 Python Software Foundation.\n\ +Copyright (c) 2001-2011 Python Software Foundation.\n\ All Rights Reserved.\n\ \n\ Copyright (c) 2000 BeOpen.com.\n\ Modified: python/branches/py3k-cdecimal/Python/import.c ============================================================================== --- python/branches/py3k-cdecimal/Python/import.c (original) +++ python/branches/py3k-cdecimal/Python/import.c Sun Jan 2 13:18:37 2011 @@ -5,13 +5,9 @@ #include "Python-ast.h" #undef Yield /* undefine macro conflicting with winbase.h */ -#include "pyarena.h" -#include "pythonrun.h" #include "errcode.h" #include "marshal.h" #include "code.h" -#include "compile.h" -#include "eval.h" #include "osdefs.h" #include "importdl.h" @@ -329,8 +325,17 @@ { if (import_lock != NULL) import_lock = PyThread_allocate_lock(); - import_lock_thread = -1; - import_lock_level = 0; + if (import_lock_level > 1) { + /* Forked as a side effect of import */ + long me = PyThread_get_thread_ident(); + PyThread_acquire_lock(import_lock, 0); + /* XXX: can the previous line fail? */ + import_lock_thread = me; + import_lock_level--; + } else { + import_lock_thread = -1; + import_lock_level = 0; + } } #endif @@ -801,7 +806,7 @@ PyErr_Clear(); /* Not important enough to report */ Py_DECREF(v); - v = PyEval_EvalCode((PyCodeObject *)co, d, d); + v = PyEval_EvalCode(co, d, d); if (v == NULL) goto error; Py_DECREF(v); @@ -3201,14 +3206,14 @@ static PyObject * imp_find_module(PyObject *self, PyObject *args) { - char *name; + PyObject *name; PyObject *ret, *path = NULL; - if (!PyArg_ParseTuple(args, "es|O:find_module", - Py_FileSystemDefaultEncoding, &name, + if (!PyArg_ParseTuple(args, "O&|O:find_module", + PyUnicode_FSConverter, &name, &path)) return NULL; - ret = call_find_module(name, path); - PyMem_Free(name); + ret = call_find_module(PyBytes_AS_STRING(name), path); + Py_DECREF(name); return ret; } @@ -3326,23 +3331,23 @@ imp_load_compiled(PyObject *self, PyObject *args) { char *name; - char *pathname; + PyObject *pathname; PyObject *fob = NULL; PyObject *m; FILE *fp; - if (!PyArg_ParseTuple(args, "ses|O:load_compiled", + if (!PyArg_ParseTuple(args, "sO&|O:load_compiled", &name, - Py_FileSystemDefaultEncoding, &pathname, + PyUnicode_FSConverter, &pathname, &fob)) return NULL; - fp = get_file(pathname, fob, "rb"); + fp = get_file(PyBytes_AS_STRING(pathname), fob, "rb"); if (fp == NULL) { - PyMem_Free(pathname); + Py_DECREF(pathname); return NULL; } - m = load_compiled_module(name, pathname, fp); + m = load_compiled_module(name, PyBytes_AS_STRING(pathname), fp); fclose(fp); - PyMem_Free(pathname); + Py_DECREF(pathname); return m; } @@ -3381,22 +3386,22 @@ imp_load_source(PyObject *self, PyObject *args) { char *name; - char *pathname; + PyObject *pathname; PyObject *fob = NULL; PyObject *m; FILE *fp; - if (!PyArg_ParseTuple(args, "ses|O:load_source", + if (!PyArg_ParseTuple(args, "sO&|O:load_source", &name, - Py_FileSystemDefaultEncoding, &pathname, + PyUnicode_FSConverter, &pathname, &fob)) return NULL; - fp = get_file(pathname, fob, "r"); + fp = get_file(PyBytes_AS_STRING(pathname), fob, "r"); if (fp == NULL) { - PyMem_Free(pathname); + Py_DECREF(pathname); return NULL; } - m = load_source_module(name, pathname, fp); - PyMem_Free(pathname); + m = load_source_module(name, PyBytes_AS_STRING(pathname), fp); + Py_DECREF(pathname); fclose(fp); return m; } @@ -3450,13 +3455,13 @@ imp_load_package(PyObject *self, PyObject *args) { char *name; - char *pathname; + PyObject *pathname; PyObject * ret; - if (!PyArg_ParseTuple(args, "ses:load_package", - &name, Py_FileSystemDefaultEncoding, &pathname)) + if (!PyArg_ParseTuple(args, "sO&:load_package", + &name, PyUnicode_FSConverter, &pathname)) return NULL; - ret = load_package(name, pathname); - PyMem_Free(pathname); + ret = load_package(name, PyBytes_AS_STRING(pathname)); + Py_DECREF(pathname); return ret; } @@ -3529,21 +3534,23 @@ { static char *kwlist[] = {"path", NULL}; + PyObject *pathname_obj; char *pathname; char buf[MAXPATHLEN+1]; if (!PyArg_ParseTupleAndKeywords( - args, kws, "es", kwlist, - Py_FileSystemDefaultEncoding, &pathname)) + args, kws, "O&", kwlist, + PyUnicode_FSConverter, &pathname_obj)) return NULL; + pathname = PyBytes_AS_STRING(pathname_obj); if (make_source_pathname(pathname, buf) == NULL) { PyErr_Format(PyExc_ValueError, "Not a PEP 3147 pyc path: %s", pathname); - PyMem_Free(pathname); + Py_DECREF(pathname_obj); return NULL; } - PyMem_Free(pathname); + Py_DECREF(pathname_obj); return PyUnicode_FromString(buf); } Modified: python/branches/py3k-cdecimal/Python/peephole.c ============================================================================== --- python/branches/py3k-cdecimal/Python/peephole.c (original) +++ python/branches/py3k-cdecimal/Python/peephole.c Sun Jan 2 13:18:37 2011 @@ -4,10 +4,8 @@ #include "Python-ast.h" #include "node.h" -#include "pyarena.h" #include "ast.h" #include "code.h" -#include "compile.h" #include "symtable.h" #include "opcode.h" Modified: python/branches/py3k-cdecimal/Python/pyarena.c ============================================================================== --- python/branches/py3k-cdecimal/Python/pyarena.c (original) +++ python/branches/py3k-cdecimal/Python/pyarena.c Sun Jan 2 13:18:37 2011 @@ -1,5 +1,4 @@ #include "Python.h" -#include "pyarena.h" /* A simple arena block structure. Modified: python/branches/py3k-cdecimal/Python/pythonrun.c ============================================================================== --- python/branches/py3k-cdecimal/Python/pythonrun.c (original) +++ python/branches/py3k-cdecimal/Python/pythonrun.c Sun Jan 2 13:18:37 2011 @@ -11,14 +11,10 @@ #include "parsetok.h" #include "errcode.h" #include "code.h" -#include "compile.h" #include "symtable.h" -#include "pyarena.h" #include "ast.h" -#include "eval.h" #include "marshal.h" #include "osdefs.h" -#include "abstract.h" #ifdef HAVE_SIGNAL_H #include @@ -82,6 +78,7 @@ int Py_DebugFlag; /* Needed by parser.c */ int Py_VerboseFlag; /* Needed by import.c */ +int Py_QuietFlag; /* Needed by sysmodule.c */ int Py_InteractiveFlag; /* Needed by Py_FdIsInteractive() below */ int Py_InspectFlag; /* Needed to determine whether to exit at SystemError */ int Py_NoSiteFlag; /* Suppress 'import site' */ @@ -1759,7 +1756,7 @@ co = PyAST_Compile(mod, filename, flags, arena); if (co == NULL) return NULL; - v = PyEval_EvalCode(co, globals, locals); + v = PyEval_EvalCode((PyObject*)co, globals, locals); Py_DECREF(co); return v; } @@ -1789,7 +1786,7 @@ return NULL; } co = (PyCodeObject *)v; - v = PyEval_EvalCode(co, globals, locals); + v = PyEval_EvalCode((PyObject*)co, globals, locals); if (v && flags) flags->cf_flags |= (co->co_flags & PyCF_MASK); Py_DECREF(co); @@ -1797,8 +1794,8 @@ } PyObject * -Py_CompileStringFlags(const char *str, const char *filename, int start, - PyCompilerFlags *flags) +Py_CompileStringExFlags(const char *str, const char *filename, int start, + PyCompilerFlags *flags, int optimize) { PyCodeObject *co; mod_ty mod; @@ -1816,11 +1813,19 @@ PyArena_Free(arena); return result; } - co = PyAST_Compile(mod, filename, flags, arena); + co = PyAST_CompileEx(mod, filename, flags, optimize, arena); PyArena_Free(arena); return (PyObject *)co; } +/* For use in Py_LIMITED_API */ +#undef Py_CompileString +PyObject * +PyCompileString(const char *str, const char *filename, int start) +{ + return Py_CompileStringFlags(str, filename, start, NULL); +} + struct symtable * Py_SymtableString(const char *str, const char *filename, int start) { @@ -2446,7 +2451,15 @@ PyAPI_FUNC(PyObject *) Py_CompileString(const char *str, const char *p, int s) { - return Py_CompileStringFlags(str, p, s, NULL); + return Py_CompileStringExFlags(str, p, s, NULL, -1); +} + +#undef Py_CompileStringFlags +PyAPI_FUNC(PyObject *) +Py_CompileStringFlags(const char *str, const char *p, int s, + PyCompilerFlags *flags) +{ + return Py_CompileStringExFlags(str, p, s, flags, -1); } #undef PyRun_InteractiveOne Modified: python/branches/py3k-cdecimal/Python/sysmodule.c ============================================================================== --- python/branches/py3k-cdecimal/Python/sysmodule.c (original) +++ python/branches/py3k-cdecimal/Python/sysmodule.c Sun Jan 2 13:18:37 2011 @@ -15,10 +15,8 @@ */ #include "Python.h" -#include "structseq.h" #include "code.h" #include "frameobject.h" -#include "eval.h" #include "osdefs.h" @@ -67,6 +65,68 @@ return PyDict_SetItemString(sd, name, v); } +/* Write repr(o) to sys.stdout using sys.stdout.encoding and 'backslashreplace' + error handler. If sys.stdout has a buffer attribute, use + sys.stdout.buffer.write(encoded), otherwise redecode the string and use + sys.stdout.write(redecoded). + + Helper function for sys_displayhook(). */ +static int +sys_displayhook_unencodable(PyObject *outf, PyObject *o) +{ + PyObject *stdout_encoding = NULL; + PyObject *encoded, *escaped_str, *repr_str, *buffer, *result; + char *stdout_encoding_str; + int ret; + + stdout_encoding = PyObject_GetAttrString(outf, "encoding"); + if (stdout_encoding == NULL) + goto error; + stdout_encoding_str = _PyUnicode_AsString(stdout_encoding); + if (stdout_encoding_str == NULL) + goto error; + + repr_str = PyObject_Repr(o); + if (repr_str == NULL) + goto error; + encoded = PyUnicode_AsEncodedString(repr_str, + stdout_encoding_str, + "backslashreplace"); + Py_DECREF(repr_str); + if (encoded == NULL) + goto error; + + buffer = PyObject_GetAttrString(outf, "buffer"); + if (buffer) { + result = PyObject_CallMethod(buffer, "write", "(O)", encoded); + Py_DECREF(buffer); + Py_DECREF(encoded); + if (result == NULL) + goto error; + Py_DECREF(result); + } + else { + PyErr_Clear(); + escaped_str = PyUnicode_FromEncodedObject(encoded, + stdout_encoding_str, + "strict"); + Py_DECREF(encoded); + if (PyFile_WriteObject(escaped_str, outf, Py_PRINT_RAW) != 0) { + Py_DECREF(escaped_str); + goto error; + } + Py_DECREF(escaped_str); + } + ret = 0; + goto finally; + +error: + ret = -1; +finally: + Py_XDECREF(stdout_encoding); + return ret; +} + static PyObject * sys_displayhook(PyObject *self, PyObject *o) { @@ -74,6 +134,7 @@ PyInterpreterState *interp = PyThreadState_GET()->interp; PyObject *modules = interp->modules; PyObject *builtins = PyDict_GetItemString(modules, "builtins"); + int err; if (builtins == NULL) { PyErr_SetString(PyExc_RuntimeError, "lost builtins module"); @@ -94,8 +155,19 @@ PyErr_SetString(PyExc_RuntimeError, "lost sys.stdout"); return NULL; } - if (PyFile_WriteObject(o, outf, 0) != 0) - return NULL; + if (PyFile_WriteObject(o, outf, 0) != 0) { + if (PyErr_ExceptionMatches(PyExc_UnicodeEncodeError)) { + /* repr(o) is not encodable to sys.stdout.encoding with + * sys.stdout.errors error handler (which is probably 'strict') */ + PyErr_Clear(); + err = sys_displayhook_unencodable(outf, o); + if (err) + return NULL; + } + else { + return NULL; + } + } if (PyFile_WriteString("\n", outf) != 0) return NULL; if (PyObject_SetAttrString(builtins, "_", o) != 0) @@ -1345,7 +1417,8 @@ #endif /* {"unbuffered", "-u"}, */ /* {"skip_first", "-x"}, */ - {"bytes_warning", "-b"}, + {"bytes_warning", "-b"}, + {"quiet", "-q"}, {0} }; @@ -1389,6 +1462,7 @@ /* SetFlag(saw_unbuffered_flag); */ /* SetFlag(skipfirstline); */ SetFlag(Py_BytesWarningFlag); + SetFlag(Py_QuietFlag); #undef SetFlag if (PyErr_Occurred()) { Modified: python/branches/py3k-cdecimal/Python/thread_nt.h ============================================================================== --- python/branches/py3k-cdecimal/Python/thread_nt.h (original) +++ python/branches/py3k-cdecimal/Python/thread_nt.h Sun Jan 2 13:18:37 2011 @@ -238,10 +238,13 @@ * and 0 if the lock was not acquired. This means a 0 is returned * if the lock has already been acquired by this thread! */ -int -PyThread_acquire_lock_timed(PyThread_type_lock aLock, PY_TIMEOUT_T microseconds) -{ - int success ; +PyLockStatus +PyThread_acquire_lock_timed(PyThread_type_lock aLock, + PY_TIMEOUT_T microseconds, int intr_flag) +{ + /* Fow now, intr_flag does nothing on Windows, and lock acquires are + * uninterruptible. */ + PyLockStatus success; PY_TIMEOUT_T milliseconds; if (microseconds >= 0) { @@ -258,7 +261,13 @@ dprintf(("%ld: PyThread_acquire_lock_timed(%p, %lld) called\n", PyThread_get_thread_ident(), aLock, microseconds)); - success = aLock && EnterNonRecursiveMutex((PNRMUTEX) aLock, (DWORD) milliseconds) == WAIT_OBJECT_0 ; + if (aLock && EnterNonRecursiveMutex((PNRMUTEX)aLock, + (DWORD)milliseconds) == WAIT_OBJECT_0) { + success = PY_LOCK_ACQUIRED; + } + else { + success = PY_LOCK_FAILURE; + } dprintf(("%ld: PyThread_acquire_lock(%p, %lld) -> %d\n", PyThread_get_thread_ident(), aLock, microseconds, success)); @@ -268,7 +277,7 @@ int PyThread_acquire_lock(PyThread_type_lock aLock, int waitflag) { - return PyThread_acquire_lock_timed(aLock, waitflag ? -1 : 0); + return PyThread_acquire_lock_timed(aLock, waitflag ? -1 : 0, 0); } void Modified: python/branches/py3k-cdecimal/Python/thread_pthread.h ============================================================================== --- python/branches/py3k-cdecimal/Python/thread_pthread.h (original) +++ python/branches/py3k-cdecimal/Python/thread_pthread.h Sun Jan 2 13:18:37 2011 @@ -316,16 +316,17 @@ return (status == -1) ? errno : status; } -int -PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) +PyLockStatus +PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, + int intr_flag) { - int success; + PyLockStatus success; sem_t *thelock = (sem_t *)lock; int status, error = 0; struct timespec ts; - dprintf(("PyThread_acquire_lock_timed(%p, %lld) called\n", - lock, microseconds)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", + lock, microseconds, intr_flag)); if (microseconds > 0) MICROSECONDS_TO_TIMESPEC(microseconds, ts); @@ -336,33 +337,38 @@ status = fix_status(sem_trywait(thelock)); else status = fix_status(sem_wait(thelock)); - } while (status == EINTR); /* Retry if interrupted by a signal */ - - if (microseconds > 0) { - if (status != ETIMEDOUT) - CHECK_STATUS("sem_timedwait"); - } - else if (microseconds == 0) { - if (status != EAGAIN) - CHECK_STATUS("sem_trywait"); - } - else { - CHECK_STATUS("sem_wait"); + /* Retry if interrupted by a signal, unless the caller wants to be + notified. */ + } while (!intr_flag && status == EINTR); + + /* Don't check the status if we're stopping because of an interrupt. */ + if (!(intr_flag && status == EINTR)) { + if (microseconds > 0) { + if (status != ETIMEDOUT) + CHECK_STATUS("sem_timedwait"); + } + else if (microseconds == 0) { + if (status != EAGAIN) + CHECK_STATUS("sem_trywait"); + } + else { + CHECK_STATUS("sem_wait"); + } } - success = (status == 0) ? 1 : 0; + if (status == 0) { + success = PY_LOCK_ACQUIRED; + } else if (intr_flag && status == EINTR) { + success = PY_LOCK_INTR; + } else { + success = PY_LOCK_FAILURE; + } - dprintf(("PyThread_acquire_lock_timed(%p, %lld) -> %d\n", - lock, microseconds, success)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n", + lock, microseconds, intr_flag, success)); return success; } -int -PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) -{ - return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0); -} - void PyThread_release_lock(PyThread_type_lock lock) { @@ -436,21 +442,25 @@ free((void *)thelock); } -int -PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds) +PyLockStatus +PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, + int intr_flag) { - int success; + PyLockStatus success; pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; - dprintf(("PyThread_acquire_lock_timed(%p, %lld) called\n", - lock, microseconds)); + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", + lock, microseconds, intr_flag)); status = pthread_mutex_lock( &thelock->mut ); CHECK_STATUS("pthread_mutex_lock[1]"); - success = thelock->locked == 0; - if (!success && microseconds != 0) { + if (thelock->locked == 0) { + success = PY_LOCK_ACQUIRED; + } else if (microseconds == 0) { + success = PY_LOCK_FAILURE; + } else { struct timespec ts; if (microseconds > 0) MICROSECONDS_TO_TIMESPEC(microseconds, ts); @@ -458,7 +468,8 @@ /* mut must be locked by me -- part of the condition * protocol */ - while (thelock->locked) { + success = PY_LOCK_FAILURE; + while (success == PY_LOCK_FAILURE) { if (microseconds > 0) { status = pthread_cond_timedwait( &thelock->lock_released, @@ -473,25 +484,30 @@ &thelock->mut); CHECK_STATUS("pthread_cond_wait"); } + + if (intr_flag && status == 0 && thelock->locked) { + /* We were woken up, but didn't get the lock. We probably received + * a signal. Return PY_LOCK_INTR to allow the caller to handle + * it and retry. */ + success = PY_LOCK_INTR; + break; + } else if (status == 0 && !thelock->locked) { + success = PY_LOCK_ACQUIRED; + } else { + success = PY_LOCK_FAILURE; + } } - success = (status == 0); } - if (success) thelock->locked = 1; + if (success == PY_LOCK_ACQUIRED) thelock->locked = 1; status = pthread_mutex_unlock( &thelock->mut ); CHECK_STATUS("pthread_mutex_unlock[1]"); - if (error) success = 0; - dprintf(("PyThread_acquire_lock_timed(%p, %lld) -> %d\n", - lock, microseconds, success)); + if (error) success = PY_LOCK_FAILURE; + dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n", + lock, microseconds, intr_flag, success)); return success; } -int -PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) -{ - return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0); -} - void PyThread_release_lock(PyThread_type_lock lock) { @@ -515,6 +531,12 @@ #endif /* USE_SEMAPHORES */ +int +PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) +{ + return PyThread_acquire_lock_timed(lock, waitflag ? -1 : 0, /*intr_flag=*/0); +} + /* set the thread stack size. * Return 0 if size is valid, -1 if size is invalid, * -2 if setting stack size is not supported. Modified: python/branches/py3k-cdecimal/Python/traceback.c ============================================================================== --- python/branches/py3k-cdecimal/Python/traceback.c (original) +++ python/branches/py3k-cdecimal/Python/traceback.c Sun Jan 2 13:18:37 2011 @@ -7,7 +7,6 @@ #include "frameobject.h" #include "structmember.h" #include "osdefs.h" -#include "traceback.h" #ifdef HAVE_FCNTL_H #include #endif Modified: python/branches/py3k-cdecimal/README ============================================================================== --- python/branches/py3k-cdecimal/README (original) +++ python/branches/py3k-cdecimal/README Sun Jan 2 13:18:37 2011 @@ -1,7 +1,7 @@ -This is Python version 3.2 alpha 4 -================================== +This is Python version 3.2 beta 2 +================================= -Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Python Software Foundation. All rights reserved. @@ -97,10 +97,7 @@ left by the previous test run). The test set produces some output. You can generally ignore the messages about skipped tests due to optional features which can't be imported. If a message is printed about a failed test or a traceback -or core dump is produced, something is wrong. On some Linux systems (those that -are not yet using glibc 6), test_strftime fails due to a non-standard -implementation of strftime() in the C library. Please ignore this, or upgrade to -glibc version 6. +or core dump is produced, something is wrong. By default, tests are prevented from overusing resources like disk space and memory. To enable these tests, run "make testall". @@ -109,7 +106,7 @@ include the output of "make test". It is useless. Run the failing test manually, as follows: - ./python Lib/test/regrtest.py -v test_whatever + ./python -m test -v test_whatever (substituting the top of the source tree for '.' if you built in a different directory). This runs the test in verbose mode. Modified: python/branches/py3k-cdecimal/Tools/README ============================================================================== --- python/branches/py3k-cdecimal/Tools/README (original) +++ python/branches/py3k-cdecimal/Tools/README Sun Jan 2 13:18:37 2011 @@ -5,7 +5,7 @@ ccbench A Python concurrency benchmark. -framer Generate boilerplate code for C extension types. +demo Several Python programming demos. freeze Create a stand-alone executable from a Python program. @@ -21,6 +21,8 @@ msi Support for packaging Python as an MSI package on Windows. +parser Un-parsing tool to generate code from an AST. + pybench Comprehensive Python benchmarking suite. pynche A Tkinter-based color editor. @@ -30,7 +32,7 @@ tabs and spaces, and 2to3, which converts Python 2 code to Python 3 code. -ssl Currently, a tool to fetch server certificates. +test2to3 A demonstration of how to use 2to3 transparently in setup.py. unicode Tools used to generate unicode database files for Python 2.0 (by Fredrik Lundh). Modified: python/branches/py3k-cdecimal/Tools/buildbot/external-amd64.bat ============================================================================== --- python/branches/py3k-cdecimal/Tools/buildbot/external-amd64.bat (original) +++ python/branches/py3k-cdecimal/Tools/buildbot/external-amd64.bat Sun Jan 2 13:18:37 2011 @@ -5,17 +5,17 @@ call "%VS90COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64 if not exist tcltk64\bin\tcl85g.dll ( - cd tcl-8.5.2.1\win + cd tcl-8.5.9.0\win nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 clean all nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 install cd ..\.. ) if not exist tcltk64\bin\tk85g.dll ( - cd tk-8.5.2.0\win - nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 TCLDIR=..\..\tcl-8.5.2.1 clean - nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 TCLDIR=..\..\tcl-8.5.2.1 all - nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 TCLDIR=..\..\tcl-8.5.2.1 install + cd tk-8.5.9.0\win + nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 TCLDIR=..\..\tcl-8.5.9.0 clean + nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 TCLDIR=..\..\tcl-8.5.9.0 all + nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 MACHINE=AMD64 INSTALLDIR=..\..\tcltk64 TCLDIR=..\..\tcl-8.5.9.0 install cd ..\.. ) Modified: python/branches/py3k-cdecimal/Tools/buildbot/external-common.bat ============================================================================== --- python/branches/py3k-cdecimal/Tools/buildbot/external-common.bat (original) +++ python/branches/py3k-cdecimal/Tools/buildbot/external-common.bat Sun Jan 2 13:18:37 2011 @@ -15,7 +15,7 @@ @rem if exist tk-8.4.18.1 rd /s/q tk-8.4.18.1 @rem if exist db-4.4.20 rd /s/q db-4.4.20 @rem if exist openssl-1.0.0a rd /s/q openssl-1.0.0a - at rem if exist sqlite-3.6.21 rd /s/q sqlite-3.6.21 + at rem if exist sqlite-3.7.4 rd /s/q sqlite-3.7.4 @rem bzip if not exist bzip2-1.0.5 ( @@ -30,14 +30,14 @@ if not exist openssl-1.0.0a svn export http://svn.python.org/projects/external/openssl-1.0.0a @rem tcl/tk -if not exist tcl-8.5.2.1 ( +if not exist tcl-8.5.9.0 ( rd /s/q tcltk tcltk64 - svn export http://svn.python.org/projects/external/tcl-8.5.2.1 + svn export http://svn.python.org/projects/external/tcl-8.5.9.0 ) -if not exist tk-8.5.2.0 svn export http://svn.python.org/projects/external/tk-8.5.2.0 +if not exist tk-8.5.9.0 svn export http://svn.python.org/projects/external/tk-8.5.9.0 @rem sqlite3 -if not exist sqlite-3.6.21 ( - rd /s/q sqlite-source-3.3.4 - svn export http://svn.python.org/projects/external/sqlite-3.6.21 +if not exist sqlite-3.7.4 ( + rd /s/q sqlite-source-3.6.21 + svn export http://svn.python.org/projects/external/sqlite-3.7.4 ) Modified: python/branches/py3k-cdecimal/Tools/buildbot/external.bat ============================================================================== --- python/branches/py3k-cdecimal/Tools/buildbot/external.bat (original) +++ python/branches/py3k-cdecimal/Tools/buildbot/external.bat Sun Jan 2 13:18:37 2011 @@ -6,16 +6,16 @@ if not exist tcltk\bin\tcl85g.dll ( @rem all and install need to be separate invocations, otherwise nmakehlp is not found on install - cd tcl-8.5.2.1\win + cd tcl-8.5.9.0\win nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 DEBUG=1 INSTALLDIR=..\..\tcltk clean all nmake -f makefile.vc DEBUG=1 INSTALLDIR=..\..\tcltk install cd ..\.. ) if not exist tcltk\bin\tk85g.dll ( - cd tk-8.5.2.0\win - nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 INSTALLDIR=..\..\tcltk TCLDIR=..\..\tcl-8.5.2.1 clean - nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 INSTALLDIR=..\..\tcltk TCLDIR=..\..\tcl-8.5.2.1 all - nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 INSTALLDIR=..\..\tcltk TCLDIR=..\..\tcl-8.5.2.1 install + cd tk-8.5.9.0\win + nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 INSTALLDIR=..\..\tcltk TCLDIR=..\..\tcl-8.5.9.0 clean + nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 INSTALLDIR=..\..\tcltk TCLDIR=..\..\tcl-8.5.9.0 all + nmake -f makefile.vc COMPILERFLAGS=-DWINVER=0x0500 OPTS=noxp DEBUG=1 INSTALLDIR=..\..\tcltk TCLDIR=..\..\tcl-8.5.9.0 install cd ..\.. ) Modified: python/branches/py3k-cdecimal/Tools/buildbot/test.bat ============================================================================== --- python/branches/py3k-cdecimal/Tools/buildbot/test.bat (original) +++ python/branches/py3k-cdecimal/Tools/buildbot/test.bat Sun Jan 2 13:18:37 2011 @@ -1,4 +1,4 @@ @rem Used by the buildbot "test" step. cd PCbuild -call rt.bat -d -q -uall -rw -n +call rt.bat -d -q -uall -rwW -n Modified: python/branches/py3k-cdecimal/Tools/msi/msi.py ============================================================================== --- python/branches/py3k-cdecimal/Tools/msi/msi.py (original) +++ python/branches/py3k-cdecimal/Tools/msi/msi.py Sun Jan 2 13:18:37 2011 @@ -1035,6 +1035,8 @@ if dir=='xmltestdata': lib.glob("*.xml") lib.add_file("test.xml.out") + if dir=='subprocessdata': + lib.glob("*.py") if dir=='output': lib.glob("test_*") if dir=='sndhdrdata': @@ -1054,6 +1056,10 @@ if dir=="macholib": lib.add_file("README.ctypes") lib.glob("fetch_macholib*") + if dir=='turtledemo': + lib.add_file("turtle.cfg") + if dir=="pydoc_data": + lib.add_file("_pydoc.css") if dir=="data" and parent.physical=="test" and parent.basedir.physical=="email": # This should contain all non-.svn files listed in subversion for f in os.listdir(lib.absolute): @@ -1082,6 +1088,7 @@ continue dlls.append(f) lib.add_file(f) + lib.add_file('python3.dll') # Add sqlite if msilib.msi_type=="Intel64;1033": sqlite_arch = "/ia64" @@ -1118,6 +1125,7 @@ for f in dlls: lib.add_file(f.replace('pyd','lib')) lib.add_file('python%s%s.lib' % (major, minor)) + lib.add_file('python3.lib') # Add the mingw-format library if have_mingw: lib.add_file('libpython%s%s.a' % (major, minor)) Modified: python/branches/py3k-cdecimal/Tools/scripts/README ============================================================================== --- python/branches/py3k-cdecimal/Tools/scripts/README (original) +++ python/branches/py3k-cdecimal/Tools/scripts/README Sun Jan 2 13:18:37 2011 @@ -2,8 +2,6 @@ useful while building, extending or managing Python. Some (e.g., dutree or lll) are also generally useful UNIX tools. -See also the Demo/scripts directory! - 2to3 Main script for running the 2to3 conversion tool analyze_dxp.py Analyzes the result of sys.getdxp() byext.py Print lines/words/chars stats of files by extension Deleted: python/branches/py3k-cdecimal/Tools/scripts/redemo.py ============================================================================== --- python/branches/py3k-cdecimal/Tools/scripts/redemo.py Sun Jan 2 13:18:37 2011 +++ (empty file) @@ -1,171 +0,0 @@ -"""Basic regular expression demostration facility (Perl style syntax).""" - -from tkinter import * -import re - -class ReDemo: - - def __init__(self, master): - self.master = master - - self.promptdisplay = Label(self.master, anchor=W, - text="Enter a Perl-style regular expression:") - self.promptdisplay.pack(side=TOP, fill=X) - - self.regexdisplay = Entry(self.master) - self.regexdisplay.pack(fill=X) - self.regexdisplay.focus_set() - - self.addoptions() - - self.statusdisplay = Label(self.master, text="", anchor=W) - self.statusdisplay.pack(side=TOP, fill=X) - - self.labeldisplay = Label(self.master, anchor=W, - text="Enter a string to search:") - self.labeldisplay.pack(fill=X) - self.labeldisplay.pack(fill=X) - - self.showframe = Frame(master) - self.showframe.pack(fill=X, anchor=W) - - self.showvar = StringVar(master) - self.showvar.set("first") - - self.showfirstradio = Radiobutton(self.showframe, - text="Highlight first match", - variable=self.showvar, - value="first", - command=self.recompile) - self.showfirstradio.pack(side=LEFT) - - self.showallradio = Radiobutton(self.showframe, - text="Highlight all matches", - variable=self.showvar, - value="all", - command=self.recompile) - self.showallradio.pack(side=LEFT) - - self.stringdisplay = Text(self.master, width=60, height=4) - self.stringdisplay.pack(fill=BOTH, expand=1) - self.stringdisplay.tag_configure("hit", background="yellow") - - self.grouplabel = Label(self.master, text="Groups:", anchor=W) - self.grouplabel.pack(fill=X) - - self.grouplist = Listbox(self.master) - self.grouplist.pack(expand=1, fill=BOTH) - - self.regexdisplay.bind('', self.recompile) - self.stringdisplay.bind('', self.reevaluate) - - self.compiled = None - self.recompile() - - btags = self.regexdisplay.bindtags() - self.regexdisplay.bindtags(btags[1:] + btags[:1]) - - btags = self.stringdisplay.bindtags() - self.stringdisplay.bindtags(btags[1:] + btags[:1]) - - def addoptions(self): - self.frames = [] - self.boxes = [] - self.vars = [] - for name in ('IGNORECASE', - 'LOCALE', - 'MULTILINE', - 'DOTALL', - 'VERBOSE'): - if len(self.boxes) % 3 == 0: - frame = Frame(self.master) - frame.pack(fill=X) - self.frames.append(frame) - val = getattr(re, name) - var = IntVar() - box = Checkbutton(frame, - variable=var, text=name, - offvalue=0, onvalue=val, - command=self.recompile) - box.pack(side=LEFT) - self.boxes.append(box) - self.vars.append(var) - - def getflags(self): - flags = 0 - for var in self.vars: - flags = flags | var.get() - flags = flags - return flags - - def recompile(self, event=None): - try: - self.compiled = re.compile(self.regexdisplay.get(), - self.getflags()) - bg = self.promptdisplay['background'] - self.statusdisplay.config(text="", background=bg) - except re.error as msg: - self.compiled = None - self.statusdisplay.config( - text="re.error: %s" % str(msg), - background="red") - self.reevaluate() - - def reevaluate(self, event=None): - try: - self.stringdisplay.tag_remove("hit", "1.0", END) - except TclError: - pass - try: - self.stringdisplay.tag_remove("hit0", "1.0", END) - except TclError: - pass - self.grouplist.delete(0, END) - if not self.compiled: - return - self.stringdisplay.tag_configure("hit", background="yellow") - self.stringdisplay.tag_configure("hit0", background="orange") - text = self.stringdisplay.get("1.0", END) - last = 0 - nmatches = 0 - while last <= len(text): - m = self.compiled.search(text, last) - if m is None: - break - first, last = m.span() - if last == first: - last = first+1 - tag = "hit0" - else: - tag = "hit" - pfirst = "1.0 + %d chars" % first - plast = "1.0 + %d chars" % last - self.stringdisplay.tag_add(tag, pfirst, plast) - if nmatches == 0: - self.stringdisplay.yview_pickplace(pfirst) - groups = list(m.groups()) - groups.insert(0, m.group()) - for i in range(len(groups)): - g = "%2d: %r" % (i, groups[i]) - self.grouplist.insert(END, g) - nmatches = nmatches + 1 - if self.showvar.get() == "first": - break - - if nmatches == 0: - self.statusdisplay.config(text="(no match)", - background="yellow") - else: - self.statusdisplay.config(text="") - - -# Main function, run when invoked as a stand-alone Python program. - -def main(): - root = Tk() - demo = ReDemo(root) - root.protocol('WM_DELETE_WINDOW', root.quit) - root.mainloop() - -if __name__ == '__main__': - main() Modified: python/branches/py3k-cdecimal/Tools/scripts/untabify.py ============================================================================== --- python/branches/py3k-cdecimal/Tools/scripts/untabify.py (original) +++ python/branches/py3k-cdecimal/Tools/scripts/untabify.py Sun Jan 2 13:18:37 2011 @@ -5,7 +5,7 @@ import os import sys import getopt - +import tokenize def main(): tabsize = 8 @@ -27,8 +27,9 @@ def process(filename, tabsize, verbose=True): try: - with open(filename) as f: + with tokenize.open(filename) as f: text = f.read() + encoding = f.encoding except IOError as msg: print("%r: I/O error: %s" % (filename, msg)) return @@ -44,7 +45,7 @@ os.rename(filename, backup) except os.error: pass - with open(filename, "w") as f: + with open(filename, "w", encoding=encoding) as f: f.write(newtext) if verbose: print(filename) Modified: python/branches/py3k-cdecimal/Tools/unicode/gencodec.py ============================================================================== --- python/branches/py3k-cdecimal/Tools/unicode/gencodec.py (original) +++ python/branches/py3k-cdecimal/Tools/unicode/gencodec.py Sun Jan 2 13:18:37 2011 @@ -34,6 +34,9 @@ # Standard undefined Unicode code point UNI_UNDEFINED = chr(0xFFFE) +# Placeholder for a missing codepoint +MISSING_CODE = -1 + mapRE = re.compile('((?:0x[0-9a-fA-F]+\+?)+)' '\s+' '((?:(?:0x[0-9a-fA-Z]+|<[A-Za-z]+>)\+?)*)' @@ -52,7 +55,7 @@ """ if not codes: - return None + return MISSING_CODE l = codes.split('+') if len(l) == 1: return int(l[0],16) @@ -60,8 +63,8 @@ try: l[i] = int(l[i],16) except ValueError: - l[i] = None - l = [x for x in l if x is not None] + l[i] = MISSING_CODE + l = [x for x in l if x != MISSING_CODE] if len(l) == 1: return l[0] else: @@ -113,7 +116,7 @@ # mappings to None for the rest if len(identity) >= len(unmapped): for enc in unmapped: - enc2uni[enc] = (None, "") + enc2uni[enc] = (MISSING_CODE, "") enc2uni['IDENTITY'] = 256 return enc2uni @@ -211,7 +214,7 @@ (mapkey, mapcomment) = mapkey if isinstance(mapvalue, tuple): (mapvalue, mapcomment) = mapvalue - if mapkey is None: + if mapkey == MISSING_CODE: continue table[mapkey] = (mapvalue, mapcomment) if mapkey > maxkey: @@ -223,11 +226,11 @@ # Create table code for key in range(maxkey + 1): if key not in table: - mapvalue = None + mapvalue = MISSING_CODE mapcomment = 'UNDEFINED' else: mapvalue, mapcomment = table[key] - if mapvalue is None: + if mapvalue == MISSING_CODE: mapchar = UNI_UNDEFINED else: if isinstance(mapvalue, tuple): Modified: python/branches/py3k-cdecimal/configure ============================================================================== --- python/branches/py3k-cdecimal/configure (original) +++ python/branches/py3k-cdecimal/configure Sun Jan 2 13:18:37 2011 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 86306 . +# From configure.in Revision: 86687 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.67 for python 3.2. # @@ -647,6 +647,7 @@ RUNSHARED INSTSONAME LDLIBRARYDIR +PY3LIBRARY BLDLIBRARY DLLLIBRARY LDLIBRARY @@ -4710,13 +4711,14 @@ + LDLIBRARY="$LIBRARY" BLDLIBRARY='$(LDLIBRARY)' INSTSONAME='$(LDLIBRARY)' DLLLIBRARY='' LDLIBRARYDIR='' RUNSHARED='' -LDVERSION="$(VERSION)" +LDVERSION="$VERSION" # LINKCC is the command that links the python executable -- default is $(CC). # If CXX is set, and if it is needed to link a main function that was @@ -4906,6 +4908,10 @@ BLDLIBRARY='-Wl,-R,$(LIBDIR) -L. -lpython$(LDVERSION)' RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} INSTSONAME="$LDLIBRARY".$SOVERSION + if test $with_pydebug == no + then + PY3LIBRARY=libpython3.so + fi ;; Linux*|GNU*|NetBSD*|FreeBSD*|DragonFly*) LDLIBRARY='libpython$(LDVERSION).so' @@ -4917,6 +4923,11 @@ ;; esac INSTSONAME="$LDLIBRARY".$SOVERSION + PY3LIBRARY=libpython3.so + if test $with_pydebug == no + then + PY3LIBRARY=libpython3.so + fi ;; hp*|HP*) case `uname -m` in @@ -13776,6 +13787,12 @@ OSF*) as_fn_error $? "OSF* systems are deprecated unless somebody volunteers. Check http://bugs.python.org/issue8606" "$LINENO" 5 ;; esac +ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" +if test "x$ac_cv_func_pipe2" = x""yes; then : + +$as_echo "#define HAVE_PIPE2 1" >>confdefs.h + +fi Modified: python/branches/py3k-cdecimal/configure.in ============================================================================== --- python/branches/py3k-cdecimal/configure.in (original) +++ python/branches/py3k-cdecimal/configure.in Sun Jan 2 13:18:37 2011 @@ -608,6 +608,7 @@ AC_SUBST(LDLIBRARY) AC_SUBST(DLLLIBRARY) AC_SUBST(BLDLIBRARY) +AC_SUBST(PY3LIBRARY) AC_SUBST(LDLIBRARYDIR) AC_SUBST(INSTSONAME) AC_SUBST(RUNSHARED) @@ -618,7 +619,7 @@ DLLLIBRARY='' LDLIBRARYDIR='' RUNSHARED='' -LDVERSION="$(VERSION)" +LDVERSION="$VERSION" # LINKCC is the command that links the python executable -- default is $(CC). # If CXX is set, and if it is needed to link a main function that was @@ -737,6 +738,10 @@ BLDLIBRARY='-Wl,-R,$(LIBDIR) -L. -lpython$(LDVERSION)' RUNSHARED=LD_LIBRARY_PATH=`pwd`:${LD_LIBRARY_PATH} INSTSONAME="$LDLIBRARY".$SOVERSION + if test $with_pydebug == no + then + PY3LIBRARY=libpython3.so + fi ;; Linux*|GNU*|NetBSD*|FreeBSD*|DragonFly*) LDLIBRARY='libpython$(LDVERSION).so' @@ -748,6 +753,11 @@ ;; esac INSTSONAME="$LDLIBRARY".$SOVERSION + PY3LIBRARY=libpython3.so + if test $with_pydebug == no + then + PY3LIBRARY=libpython3.so + fi ;; hp*|HP*) case `uname -m` in @@ -4252,7 +4262,7 @@ OSF*) AC_MSG_ERROR(OSF* systems are deprecated unless somebody volunteers. Check http://bugs.python.org/issue8606) ;; esac - +AC_CHECK_FUNC(pipe2, AC_DEFINE(HAVE_PIPE2, 1, [Define if the OS supports pipe2()]), ) AC_SUBST(THREADHEADERS) Modified: python/branches/py3k-cdecimal/pyconfig.h.in ============================================================================== --- python/branches/py3k-cdecimal/pyconfig.h.in (original) +++ python/branches/py3k-cdecimal/pyconfig.h.in Sun Jan 2 13:18:37 2011 @@ -503,6 +503,9 @@ /* Define to 1 if you have the `pause' function. */ #undef HAVE_PAUSE +/* Define if the OS supports pipe2() */ +#undef HAVE_PIPE2 + /* Define to 1 if you have the `plock' function. */ #undef HAVE_PLOCK Deleted: python/branches/py3k-cdecimal/runtests.sh ============================================================================== --- python/branches/py3k-cdecimal/runtests.sh Sun Jan 2 13:18:37 2011 +++ (empty file) @@ -1,93 +0,0 @@ -#!/bin/bash - -HELP="Usage: ./runtests.py [-h] [-x] [flags] [tests] - -Runs each unit test independently, with output directed to a file in -OUT/.out. If no tests are given, all tests are run; otherwise, -only the specified tests are run, unless -x is also given, in which -case all tests *except* those given are run. - -Standard output shows the name of the tests run, with 'BAD' or -'SKIPPED' added if the test didn't produce a positive result. Also, -three files are created, named 'BAD', 'GOOD' and 'SKIPPED', to which -are written the names of the tests categorized by result. - -Flags (arguments starting with '-') are passed transparently to -regrtest.py, except for -x, which is processed here." - -# Choose the Python binary. -case `uname` in -Darwin) PYTHON=./python.exe;; -CYGWIN*) PYTHON=./python.exe;; -*) PYTHON=./python;; -esac - -PYTHON="$PYTHON -bb" - -# Unset PYTHONPATH, just to be sure. -unset PYTHONPATH - -# Create the output directory if necessary. -mkdir -p OUT - -# Empty the summary files. ->GOOD ->BAD ->SKIPPED - -# Process flags (transparently pass these on to regrtest.py) -FLAGS="" -EXCEPT="" -while : -do - case $1 in - -h|--h|-help|--help) echo "$HELP"; exit;; - --) FLAGS="$FLAGS $1"; shift; break;; - -x) EXCEPT="$1"; shift;; - -*) FLAGS="$FLAGS $1"; shift;; - *) break;; - esac -done - -# Compute the list of tests to run. -case "$#$EXCEPT" in -0) - TESTS=`(cd Lib/test; ls test_*.py | sed 's/\.py//')` - ;; -*-x) - PAT="^(`echo $@ | sed 's/\.py//g' | sed 's/ /|/g'`)$" - TESTS=`(cd Lib/test; ls test_*.py | sed 's/\.py//' | egrep -v "$PAT")` - ;; -*) - TESTS="$@" - ;; -esac - -# Run the tests. -for T in $TESTS -do - echo -n $T - if case $T in - *curses*) - echo - $PYTHON -E Lib/test/regrtest.py $FLAGS $T 2>OUT/$T.out - ;; - *) $PYTHON -E Lib/test/regrtest.py $FLAGS $T >OUT/$T.out 2>&1;; - esac - then - if grep -q "1 test skipped:" OUT/$T.out - then - echo " SKIPPED" - echo $T >>SKIPPED - else - echo - echo $T >>GOOD - fi - else - echo " BAD" - echo $T >>BAD - fi -done - -# Summarize results -wc -l BAD GOOD SKIPPED Modified: python/branches/py3k-cdecimal/setup.py ============================================================================== --- python/branches/py3k-cdecimal/setup.py (original) +++ python/branches/py3k-cdecimal/setup.py Sun Jan 2 13:18:37 2011 @@ -14,6 +14,7 @@ from distutils.command.build_ext import build_ext from distutils.command.install import install from distutils.command.install_lib import install_lib +from distutils.command.build_scripts import build_scripts from distutils.spawn import find_executable # Were we compiled --with-pydebug or with #define Py_DEBUG? @@ -27,11 +28,19 @@ _BUILDDIR_COOKIE = "pybuilddir.txt" def add_dir_to_list(dirlist, dir): - """Add the directory 'dir' to the list 'dirlist' (at the front) if + """Add the directory 'dir' to the list 'dirlist' (after any relative + directories) if: + 1) 'dir' is not already in 'dirlist' - 2) 'dir' actually exists, and is a directory.""" - if dir is not None and os.path.isdir(dir) and dir not in dirlist: - dirlist.insert(0, dir) + 2) 'dir' actually exists, and is a directory. + """ + if dir is None or not os.path.isdir(dir) or dir in dirlist: + return + for i, path in enumerate(dirlist): + if not os.path.isabs(path): + dirlist.insert(i + 1, dir) + return + dirlist.insert(0, dir) def macosx_sdk_root(): """ @@ -362,7 +371,9 @@ return sys.platform def detect_modules(self): - # Ensure that /usr/local is always used + # Ensure that /usr/local is always used, but the local build + # directories (i.e. '.' and 'Include') must be first. See issue + # 10520. add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib') add_dir_to_list(self.compiler.include_dirs, '/usr/local/include') @@ -437,9 +448,10 @@ # This should work on any unixy platform ;-) # If the user has bothered specifying additional -I and -L flags # in OPT and LDFLAGS we might as well use them here. - # NOTE: using shlex.split would technically be more correct, but - # also gives a bootstrap problem. Let's hope nobody uses directories - # with whitespace in the name to store libraries. + # + # NOTE: using shlex.split would technically be more correct, but + # also gives a bootstrap problem. Let's hope nobody uses + # directories with whitespace in the name to store libraries. cflags, ldflags = sysconfig.get_config_vars( 'CFLAGS', 'LDFLAGS') for item in cflags.split(): @@ -1571,6 +1583,10 @@ ## # Uncomment these lines if you want to play with xxmodule.c ## ext = Extension('xx', ['xxmodule.c']) ## self.extensions.append(ext) + if 'd' not in sys.abiflags: + ext = Extension('xxlimited', ['xxlimited.c'], + define_macros=[('Py_LIMITED_API', 1)]) + self.extensions.append(ext) # XXX handle these, but how to detect? # *** Uncomment and edit for PIL (TkImaging) extension only: @@ -1858,6 +1874,25 @@ def is_chmod_supported(self): return hasattr(os, 'chmod') +class PyBuildScripts(build_scripts): + def copy_scripts(self): + outfiles, updated_files = build_scripts.copy_scripts(self) + fullversion = '-{0[0]}.{0[1]}'.format(sys.version_info) + minoronly = '.{0[1]}'.format(sys.version_info) + newoutfiles = [] + newupdated_files = [] + for filename in outfiles: + if filename.endswith('2to3'): + newfilename = filename + fullversion + else: + newfilename = filename + minoronly + log.info('renaming {} to {}'.format(filename, newfilename)) + os.rename(filename, newfilename) + newoutfiles.append(newfilename) + if filename in updated_files: + newupdated_files.append(newfilename) + return newoutfiles, newupdated_files + SUMMARY = """ Python is an interpreted, interactive, object-oriented programming language. It is often compared to Tcl, Perl, Scheme or Java. @@ -1903,12 +1938,17 @@ platforms = ["Many"], # Build info - cmdclass = {'build_ext':PyBuildExt, 'install':PyBuildInstall, - 'install_lib':PyBuildInstallLib}, + cmdclass = {'build_ext': PyBuildExt, + 'build_scripts': PyBuildScripts, + 'install': PyBuildInstall, + 'install_lib': PyBuildInstallLib}, # The struct module is defined here, because build_ext won't be # called unless there's at least one extension module defined. ext_modules=[Extension('_struct', ['_struct.c'])], + # If you change the scripts installed here, you also need to + # check the PyBuildScripts command above, and change the links + # created by the bininstall target in Makefile.pre.in scripts = ["Tools/scripts/pydoc3", "Tools/scripts/idle3", "Tools/scripts/2to3"] ) From python-checkins at python.org Sun Jan 2 13:50:36 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 13:50:36 +0100 (CET) Subject: [Python-checkins] r87617 - in python/branches/py3k-cdecimal/Modules/cdecimal: basearith.c basearith.h bench.c constants.c constants.h context.c convolute.c convolute.h crt.c crt.h difradix2.c difradix2.h fnt.c fnt.h fourstep.c fourstep.h io.c io.h memory.c memory.h mptypes.h numbertheory.c numbertheory.h sixstep.c sixstep.h transpose.c transpose.h vccompat.h vcdiv64.asm Message-ID: <20110102125036.90425EE991@mail.python.org> Author: stefan.krah Date: Sun Jan 2 13:50:36 2011 New Revision: 87617 Log: Reduce the diff size between upstream and py3k-cdecimal. Modified: python/branches/py3k-cdecimal/Modules/cdecimal/basearith.c python/branches/py3k-cdecimal/Modules/cdecimal/basearith.h python/branches/py3k-cdecimal/Modules/cdecimal/bench.c python/branches/py3k-cdecimal/Modules/cdecimal/constants.c python/branches/py3k-cdecimal/Modules/cdecimal/constants.h python/branches/py3k-cdecimal/Modules/cdecimal/context.c python/branches/py3k-cdecimal/Modules/cdecimal/convolute.c python/branches/py3k-cdecimal/Modules/cdecimal/convolute.h python/branches/py3k-cdecimal/Modules/cdecimal/crt.c python/branches/py3k-cdecimal/Modules/cdecimal/crt.h python/branches/py3k-cdecimal/Modules/cdecimal/difradix2.c python/branches/py3k-cdecimal/Modules/cdecimal/difradix2.h python/branches/py3k-cdecimal/Modules/cdecimal/fnt.c python/branches/py3k-cdecimal/Modules/cdecimal/fnt.h python/branches/py3k-cdecimal/Modules/cdecimal/fourstep.c python/branches/py3k-cdecimal/Modules/cdecimal/fourstep.h python/branches/py3k-cdecimal/Modules/cdecimal/io.c python/branches/py3k-cdecimal/Modules/cdecimal/io.h python/branches/py3k-cdecimal/Modules/cdecimal/memory.c python/branches/py3k-cdecimal/Modules/cdecimal/memory.h python/branches/py3k-cdecimal/Modules/cdecimal/mptypes.h python/branches/py3k-cdecimal/Modules/cdecimal/numbertheory.c python/branches/py3k-cdecimal/Modules/cdecimal/numbertheory.h python/branches/py3k-cdecimal/Modules/cdecimal/sixstep.c python/branches/py3k-cdecimal/Modules/cdecimal/sixstep.h python/branches/py3k-cdecimal/Modules/cdecimal/transpose.c python/branches/py3k-cdecimal/Modules/cdecimal/transpose.h python/branches/py3k-cdecimal/Modules/cdecimal/vccompat.h python/branches/py3k-cdecimal/Modules/cdecimal/vcdiv64.asm Modified: python/branches/py3k-cdecimal/Modules/cdecimal/basearith.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/basearith.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/basearith.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/basearith.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/basearith.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/basearith.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/bench.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/bench.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/bench.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/constants.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/constants.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/constants.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/constants.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/constants.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/constants.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/context.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/context.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/context.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/convolute.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/convolute.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/convolute.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/convolute.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/convolute.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/convolute.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/crt.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/crt.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/crt.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/crt.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/crt.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/crt.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/difradix2.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/difradix2.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/difradix2.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/difradix2.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/difradix2.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/difradix2.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/fnt.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/fnt.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/fnt.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/fnt.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/fnt.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/fnt.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/fourstep.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/fourstep.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/fourstep.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/fourstep.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/fourstep.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/fourstep.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/io.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/io.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/io.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/io.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/io.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/io.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/memory.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/memory.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/memory.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/memory.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/memory.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/memory.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/mptypes.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/mptypes.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/mptypes.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/numbertheory.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/numbertheory.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/numbertheory.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/numbertheory.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/numbertheory.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/numbertheory.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/sixstep.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/sixstep.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/sixstep.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/sixstep.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/sixstep.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/sixstep.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/transpose.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/transpose.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/transpose.c Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/transpose.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/transpose.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/transpose.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/vccompat.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/vccompat.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/vccompat.h Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/vcdiv64.asm ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/vcdiv64.asm (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/vcdiv64.asm Sun Jan 2 13:50:36 2011 @@ -1,6 +1,28 @@ ; -; Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. -; Licensed to PSF under a Contributor Agreement. +; Copyright (c) 2008-2010 Stefan Krah. All rights reserved. +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions +; are met: +; +; 1. Redistributions of source code must retain the above copyright +; notice, this list of conditions and the following disclaimer. +; +; 2. Redistributions in binary form must reproduce the above copyright +; notice, this list of conditions and the following disclaimer in the +; documentation and/or other materials provided with the distribution. +; +; THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +; OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +; HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +; OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +; SUCH DAMAGE. ; From python-checkins at python.org Sun Jan 2 13:56:30 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 13:56:30 +0100 (CET) Subject: [Python-checkins] r87618 - in python/branches/py3k-cdecimal/Modules/cdecimal: bits.h cdecimal.c docstrings.h mpdecimal.c mpdecimal.h mpsignal.c mptest.h typearith.h umodarith.h Message-ID: <20110102125630.B0A7EEE986@mail.python.org> Author: stefan.krah Date: Sun Jan 2 13:56:30 2011 New Revision: 87618 Log: Reduce the diff size between upstream and py3k-cdecimal. Modified: python/branches/py3k-cdecimal/Modules/cdecimal/bits.h python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.h python/branches/py3k-cdecimal/Modules/cdecimal/mpsignal.c python/branches/py3k-cdecimal/Modules/cdecimal/mptest.h python/branches/py3k-cdecimal/Modules/cdecimal/typearith.h python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h Modified: python/branches/py3k-cdecimal/Modules/cdecimal/bits.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/bits.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/bits.h Sun Jan 2 13:56:30 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c Sun Jan 2 13:56:30 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h Sun Jan 2 13:56:30 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2001-2010 Python Software Foundation. All Rights Reserved. - * Modified and extended by Stefan Krah. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c Sun Jan 2 13:56:30 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.h Sun Jan 2 13:56:30 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/mpsignal.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/mpsignal.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/mpsignal.c Sun Jan 2 13:56:30 2011 @@ -1,3 +1,31 @@ +/* + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + + #include "mpdecimal.h" Modified: python/branches/py3k-cdecimal/Modules/cdecimal/mptest.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/mptest.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/mptest.h Sun Jan 2 13:56:30 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/typearith.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/typearith.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/typearith.h Sun Jan 2 13:56:30 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ Modified: python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h Sun Jan 2 13:56:30 2011 @@ -1,6 +1,28 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All Rights Reserved. - * Licensed to PSF under a Contributor Agreement. + * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ From python-checkins at python.org Sun Jan 2 13:59:10 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 13:59:10 +0100 (CET) Subject: [Python-checkins] r87619 - python/branches/py3k-cdecimal/Modules/cdecimal/bits.h Message-ID: <20110102125910.833F4EE991@mail.python.org> Author: stefan.krah Date: Sun Jan 2 13:59:10 2011 New Revision: 87619 Log: Use consistent style for inline asm. Modified: python/branches/py3k-cdecimal/Modules/cdecimal/bits.h Modified: python/branches/py3k-cdecimal/Modules/cdecimal/bits.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/bits.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/bits.h Sun Jan 2 13:59:10 2011 @@ -134,9 +134,9 @@ __asm__ ( #ifdef CONFIG_64 - "bsfq %1, %0" + "bsfq %1, %0\n\t" #else - "bsf %1, %0" + "bsf %1, %0\n\t" #endif :"=r" (retval) :"r" (a) From python-checkins at python.org Sun Jan 2 14:02:29 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 14:02:29 +0100 (CET) Subject: [Python-checkins] r87620 - python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h Message-ID: <20110102130229.C1553EE991@mail.python.org> Author: stefan.krah Date: Sun Jan 2 14:02:29 2011 New Revision: 87620 Log: Revert to correct license. Modified: python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h Modified: python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h Sun Jan 2 14:02:29 2011 @@ -1,28 +1,6 @@ /* - * Copyright (c) 2008-2010 Stefan Krah. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * Copyright (c) 2001-2010 Python Software Foundation. All Rights Reserved. + * Modified and extended by Stefan Krah. */ From python-checkins at python.org Sun Jan 2 14:05:07 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 14:05:07 +0100 (CET) Subject: [Python-checkins] r87621 - python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h Message-ID: <20110102130507.E2880EE991@mail.python.org> Author: stefan.krah Date: Sun Jan 2 14:05:07 2011 New Revision: 87621 Log: Quantize now takes an optional rounding argument. Modified: python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h Modified: python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/docstrings.h Sun Jan 2 14:05:07 2011 @@ -329,8 +329,8 @@ \n"); PyDoc_STRVAR(doc_quantize,"\n\ -quantize(exp[, context]) - Return a value equal to the first operand after\n\ -rounding and having the exponent of the second operand.\n\ +quantize(exp[, rounding[, context]]) - Return a value equal to the first\n\ +operand after rounding and having the exponent of the second operand.\n\ \n\ >>> Decimal('1.41421356').quantize(Decimal('1.000'))\n\ Decimal('1.414')\n\ @@ -345,8 +345,8 @@ \n\ If the exponent of the second operand is larger than that of the first, then\n\ rounding may be necessary. In this case, the rounding mode is determined by the\n\ -given context argument; if no argument is given, the rounding mode of the\n\ -current default context is used.\n\ +rounding argument if given, else by the given context argument; if neither\n\ +argument is given, the rounding mode of the current thread?s context is used.\n\ \n"); PyDoc_STRVAR(doc_radix,"\n\ From python-checkins at python.org Sun Jan 2 14:09:57 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 14:09:57 +0100 (CET) Subject: [Python-checkins] r87622 - python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c Message-ID: <20110102130957.A615EEE9C0@mail.python.org> Author: stefan.krah Date: Sun Jan 2 14:09:57 2011 New Revision: 87622 Log: Do not continue after MPD_Malloc_error. Modified: python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c Modified: python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c Sun Jan 2 14:09:57 2011 @@ -1615,11 +1615,12 @@ } /* fold down */ else if (ctx->clamp && dec->exp > mpd_etop(ctx)) { shift = dec->exp - mpd_etop(ctx); - /* if shiftl fails, dec is NaN */ - (void)mpd_qshiftl(dec, dec, shift, status); + if (!mpd_qshiftl(dec, dec, shift, status)) { + return; + } dec->exp -= shift; *status |= MPD_Clamped; - if (adjexp < ctx->emin) { + if (!mpd_iszerocoeff(dec) && adjexp < ctx->emin) { *status |= MPD_Subnormal; } } @@ -6932,7 +6933,7 @@ return; } - _mpd_qinvroot(result, a, ctx, status); + _mpd_qinvroot(result, a, ctx, status); } /* From python-checkins at python.org Sun Jan 2 14:13:37 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 14:13:37 +0100 (CET) Subject: [Python-checkins] r87623 - python/branches/py3k-cdecimal/Modules/cdecimal/typearith.h Message-ID: <20110102131337.D3CB2EE98E@mail.python.org> Author: stefan.krah Date: Sun Jan 2 14:13:37 2011 New Revision: 87623 Log: Use consistent style for inline asm. Modified: python/branches/py3k-cdecimal/Modules/cdecimal/typearith.h Modified: python/branches/py3k-cdecimal/Modules/cdecimal/typearith.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/typearith.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/typearith.h Sun Jan 2 14:13:37 2011 @@ -207,9 +207,9 @@ { mpd_uint_t h, l; - asm ( "mulq %3\n\t"\ - : "=d" (h), "=a" (l)\ - : "%a" (a), "rm" (b)\ + asm ( "mulq %3\n\t" + : "=d" (h), "=a" (l) + : "%a" (a), "rm" (b) : "cc" ); @@ -223,9 +223,9 @@ { mpd_uint_t qq, rr; - asm ( "divq %4\n\t"\ - : "=a" (qq), "=d" (rr)\ - : "a" (lo), "d" (hi), "rm" (d)\ + asm ( "divq %4\n\t" + : "=a" (qq), "=d" (rr) + : "a" (lo), "d" (hi), "rm" (d) : "cc" ); @@ -463,9 +463,9 @@ { mpd_uint_t h, l; - asm ( "mull %3\n\t"\ - : "=d" (h), "=a" (l)\ - : "%a" (a), "rm" (b)\ + asm ( "mull %3\n\t" + : "=d" (h), "=a" (l) + : "%a" (a), "rm" (b) : "cc" ); @@ -479,9 +479,9 @@ { mpd_uint_t qq, rr; - asm ( "divl %4\n\t"\ - : "=a" (qq), "=d" (rr)\ - : "a" (lo), "d" (hi), "rm" (d)\ + asm ( "divl %4\n\t" + : "=a" (qq), "=d" (rr) + : "a" (lo), "d" (hi), "rm" (d) : "cc" ); From python-checkins at python.org Sun Jan 2 14:18:01 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 14:18:01 +0100 (CET) Subject: [Python-checkins] r87624 - python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h Message-ID: <20110102131801.3F2B3EE9C4@mail.python.org> Author: stefan.krah Date: Sun Jan 2 14:18:01 2011 New Revision: 87624 Log: 1) Make inline asm PIC-compliant. 2) Use consistent style. Modified: python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h Modified: python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h Sun Jan 2 14:18:01 2011 @@ -370,26 +370,25 @@ { mpd_uint_t retval; - asm( - "fildl %2\n\t"\ - "fildl %1\n\t"\ - "fmulp %%st, %%st(1)\n\t"\ - "fldt (%4)\n\t"\ - "fmul %%st(1), %%st\n\t"\ - "flds MPD_TWO63\n\t"\ - "fadd %%st, %%st(1)\n\t"\ - "fsubrp %%st, %%st(1)\n\t"\ - "fldl (%3)\n\t"\ - "fmulp %%st, %%st(1)\n\t"\ - "fsubrp %%st, %%st(1)\n\t"\ - "fistpl %0\n\t"\ - : "=m" (retval)\ - : "m" (a), "m" (b), "r" (dmod), "r" (dinvmod)\ + asm ( + "fildl %2\n\t" + "fildl %1\n\t" + "fmulp %%st, %%st(1)\n\t" + "fldt (%4)\n\t" + "fmul %%st(1), %%st\n\t" + "flds %5\n\t" + "fadd %%st, %%st(1)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fldl (%3)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fistpl %0\n\t" + : "=m" (retval) + : "m" (a), "m" (b), "r" (dmod), "r" (dinvmod), "m" (MPD_TWO63) : "st", "memory" ); return retval; - } /* all operands < dmod */ @@ -397,34 +396,34 @@ ppro_mulmod2c(mpd_uint_t *a0, mpd_uint_t *a1, mpd_uint_t w, double *dmod, uint32_t *dinvmod) { - - asm( - "fildl %2\n\t"\ - "fildl (%1)\n\t"\ - "fmul %%st(1), %%st\n\t"\ - "fxch %%st(1)\n\t"\ - "fildl (%0)\n\t"\ - "fmulp %%st, %%st(1) \n\t"\ - "fldt (%4)\n\t"\ - "flds MPD_TWO63\n\t"\ - "fld %%st(2)\n\t"\ - "fmul %%st(2)\n\t"\ - "fadd %%st(1)\n\t"\ - "fsub %%st(1)\n\t"\ - "fmull (%3)\n\t"\ - "fsubrp %%st, %%st(3)\n\t"\ - "fxch %%st(2)\n\t"\ - "fistpl (%0)\n\t"\ - "fmul %%st(2)\n\t"\ - "fadd %%st(1)\n\t"\ - "fsubp %%st, %%st(1)\n\t"\ - "fmull (%3)\n\t"\ - "fsubrp %%st, %%st(1)\n\t"\ - "fistpl (%1)\n\t"\ - : : "r" (a0), "r" (a1), "m" (w), "r" (dmod), "r" (dinvmod)\ + asm ( + "fildl %2\n\t" + "fildl (%1)\n\t" + "fmul %%st(1), %%st\n\t" + "fxch %%st(1)\n\t" + "fildl (%0)\n\t" + "fmulp %%st, %%st(1) \n\t" + "fldt (%4)\n\t" + "flds %5\n\t" + "fld %%st(2)\n\t" + "fmul %%st(2)\n\t" + "fadd %%st(1)\n\t" + "fsub %%st(1)\n\t" + "fmull (%3)\n\t" + "fsubrp %%st, %%st(3)\n\t" + "fxch %%st(2)\n\t" + "fistpl (%0)\n\t" + "fmul %%st(2)\n\t" + "fadd %%st(1)\n\t" + "fsubp %%st, %%st(1)\n\t" + "fmull (%3)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fistpl (%1)\n\t" + : : "r" (a0), "r" (a1), "m" (w), + "r" (dmod), "r" (dinvmod), + "m" (MPD_TWO63) : "st", "memory" ); - } /* all operands < dmod */ @@ -432,42 +431,42 @@ ppro_mulmod2(mpd_uint_t *a0, mpd_uint_t b0, mpd_uint_t *a1, mpd_uint_t b1, double *dmod, uint32_t *dinvmod) { - - asm( - "fildl %3\n\t"\ - "fildl (%2)\n\t"\ - "fmulp %%st, %%st(1)\n\t"\ - "fildl %1\n\t"\ - "fildl (%0)\n\t"\ - "fmulp %%st, %%st(1)\n\t"\ - "fldt (%5)\n\t"\ - "fld %%st(2)\n\t"\ - "fmul %%st(1), %%st\n\t"\ - "fxch %%st(1)\n\t"\ - "fmul %%st(2), %%st\n\t"\ - "flds MPD_TWO63\n\t"\ - "fldl (%4)\n\t"\ - "fxch %%st(3)\n\t"\ - "fadd %%st(1), %%st\n\t"\ - "fxch %%st(2)\n\t"\ - "fadd %%st(1), %%st\n\t"\ - "fxch %%st(2)\n\t"\ - "fsub %%st(1), %%st\n\t"\ - "fxch %%st(2)\n\t"\ - "fsubp %%st, %%st(1)\n\t"\ - "fxch %%st(1)\n\t"\ - "fmul %%st(2), %%st\n\t"\ - "fxch %%st(1)\n\t"\ - "fmulp %%st, %%st(2)\n\t"\ - "fsubrp %%st, %%st(3)\n\t"\ - "fsubrp %%st, %%st(1)\n\t"\ - "fxch %%st(1)\n\t"\ - "fistpl (%2)\n\t"\ - "fistpl (%0)\n\t"\ - : : "r" (a0), "m" (b0), "r" (a1), "m" (b1), "r" (dmod), "r" (dinvmod)\ + asm ( + "fildl %3\n\t" + "fildl (%2)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fildl %1\n\t" + "fildl (%0)\n\t" + "fmulp %%st, %%st(1)\n\t" + "fldt (%5)\n\t" + "fld %%st(2)\n\t" + "fmul %%st(1), %%st\n\t" + "fxch %%st(1)\n\t" + "fmul %%st(2), %%st\n\t" + "flds %6\n\t" + "fldl (%4)\n\t" + "fxch %%st(3)\n\t" + "fadd %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fadd %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fsub %%st(1), %%st\n\t" + "fxch %%st(2)\n\t" + "fsubp %%st, %%st(1)\n\t" + "fxch %%st(1)\n\t" + "fmul %%st(2), %%st\n\t" + "fxch %%st(1)\n\t" + "fmulp %%st, %%st(2)\n\t" + "fsubrp %%st, %%st(3)\n\t" + "fsubrp %%st, %%st(1)\n\t" + "fxch %%st(1)\n\t" + "fistpl (%2)\n\t" + "fistpl (%0)\n\t" + : : "r" (a0), "m" (b0), "r" (a1), "m" (b1), + "r" (dmod), "r" (dinvmod), + "m" (MPD_TWO63) : "st", "memory" ); - } /* END PPRO GCC ASM */ #elif defined(MASM) From python-checkins at python.org Sun Jan 2 14:24:16 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 14:24:16 +0100 (CET) Subject: [Python-checkins] r87625 - python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c Message-ID: <20110102132416.8A750EE991@mail.python.org> Author: stefan.krah Date: Sun Jan 2 14:24:16 2011 New Revision: 87625 Log: Add optional rounding argument to quantize(). Modified: python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c Modified: python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c Sun Jan 2 14:24:16 2011 @@ -526,7 +526,7 @@ "OOO", self, key, failobj); } return PyObject_CallMethod((PyObject *)&PyDict_Type, "get", - "OO", self, key); + "OO", self, key); } static PyObject * @@ -1348,8 +1348,8 @@ ctx.prec = 9; ctx.traps = 0; - *CtxAddr(v) = ctx; - CtxCaps(v) = 1; + *CtxAddr(v) = ctx; + CtxCaps(v) = 1; } /* Factory function for creating IEEE interchange format contexts */ @@ -1382,8 +1382,8 @@ error: PyErr_Format(PyExc_ValueError, "argument must be a multiple of 32, with a maximum of %d.", - MPD_IEEE_CONTEXT_MAX_BITS - ); + MPD_IEEE_CONTEXT_MAX_BITS); + return NULL; } @@ -2764,30 +2764,29 @@ static char *kwlist[] = {"rounding", "context", NULL}; PyDecObject *result; PyObject *ctxobj; - int round = -1; - mpd_context_t *ctx, workctx; uint32_t status = 0; - - assert(PyTuple_Check(args)); + mpd_context_t *ctx; + mpd_context_t workctx; + int round = -1; CURRENT_CONTEXT(ctxobj); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", - kwlist, &round, &ctxobj)) { - return NULL; - } - if (!PyDecContext_Check(ctxobj)) { - PyErr_SetString(PyExc_TypeError, - "optional second arg must be a context."); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, + &round, &ctxobj)) { return NULL; } - if ((result = dec_alloc()) == NULL) { - return NULL; /* GCOV_UNLIKELY */ - } + CONTEXT_CHECK_VA(ctxobj); ctx = CtxAddr(ctxobj); + workctx = *ctx; if (round >= 0) { - workctx.round = round; + if (!mpd_qsetround(&workctx, round)) { + return value_error_ptr(invalid_rounding_err); + } + } + + if ((result = dec_alloc()) == NULL) { + return NULL; /* GCOV_UNLIKELY */ } mpd_qround_to_int(result->dec, DecAddr(self), &workctx, &status); @@ -2796,7 +2795,7 @@ return NULL; /* GCOV_UNLIKELY */ } - return (PyObject *)result; + return (PyObject *) result; } static PyObject * @@ -2805,30 +2804,29 @@ static char *kwlist[] = {"rounding", "context", NULL}; PyDecObject *result; PyObject *ctxobj; - int round = -1; - mpd_context_t *ctx, workctx; uint32_t status = 0; - - assert(PyTuple_Check(args)); + mpd_context_t *ctx; + mpd_context_t workctx; + int round = -1; CURRENT_CONTEXT(ctxobj); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", - kwlist, &round, &ctxobj)) { - return NULL; - } - if (!PyDecContext_Check(ctxobj)) { - PyErr_SetString(PyExc_TypeError, - "optional second arg must be a context."); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO", kwlist, + &round, &ctxobj)) { return NULL; } - if ((result = dec_alloc()) == NULL) { - return NULL; /* GCOV_UNLIKELY */ - } + CONTEXT_CHECK_VA(ctxobj); ctx = CtxAddr(ctxobj); + workctx = *ctx; if (round >= 0) { - workctx.round = round; + if (!mpd_qsetround(&workctx, round)) { + return value_error_ptr(invalid_rounding_err); + } + } + + if ((result = dec_alloc()) == NULL) { + return NULL; /* GCOV_UNLIKELY */ } mpd_qround_to_intx(result->dec, DecAddr(self), &workctx, &status); @@ -2837,7 +2835,7 @@ return NULL; } - return (PyObject *)result; + return (PyObject *) result; } /* Caller guarantees type */ @@ -3049,7 +3047,7 @@ return NULL; } - return (PyObject *)result; + return (PyObject *) result; } else { return _PyInt_FromDec(a, ctx, MPD_ROUND_HALF_EVEN); @@ -3491,7 +3489,7 @@ static int _Dec_nonzero(PyDecObject *v) { - return !mpd_iszero(v->dec); + return !mpd_iszero(v->dec); } static PyObject * @@ -3600,7 +3598,6 @@ _DecOpt_BinaryFunc(mpd_qmul) _DecOpt_BinaryFunc(mpd_qnext_toward) _DecOpt_BinaryFunc(mpd_qpow) -_DecOpt_BinaryFunc(mpd_qquantize) _DecOpt_BinaryFunc(mpd_qrem) _DecOpt_BinaryFunc(mpd_qrem_near) _DecOpt_BinaryFunc(mpd_qsub) @@ -3787,6 +3784,53 @@ } static PyObject * +_Dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"exp", "rounding", "context", NULL}; + PyObject *w, *ctxobj; + PyDecObject *a, *b; + PyDecObject *result; + uint32_t status = 0; + mpd_context_t *ctx; + mpd_context_t workctx; + int round = -1; + + CURRENT_CONTEXT(ctxobj); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|iO", kwlist, + &w, &round, &ctxobj)) { + return NULL; + } + + CONTEXT_CHECK_VA(ctxobj); + ctx = CtxAddr(ctxobj); + + workctx = *ctx; + if (round >= 0) { + if (!mpd_qsetround(&workctx, round)) { + return value_error_ptr(invalid_rounding_err); + } + } + + CONVERT_BINOP_SET(v, w, &a, &b, ctx); + + if ((result = dec_alloc()) == NULL) { + Py_DECREF(a); /* GCOV_UNLIKELY */ + Py_DECREF(b); /* GCOV_UNLIKELY */ + return NULL; /* GCOV_UNLIKELY */ + } + + mpd_qquantize(result->dec, a->dec, b->dec, &workctx, &status); + Py_DECREF(a); + Py_DECREF(b); + if (dec_addstatus(ctx, status)) { + Py_DECREF(result); + return NULL; + } + + return (PyObject *) result; +} + +static PyObject * _Dec_mpd_radix(PyObject *self UNUSED, PyObject *dummy UNUSED) { return Py_BuildValue("i", 10); @@ -4255,7 +4299,7 @@ { "next_toward", _DecOpt_mpd_qnext_toward, METH_VARARGS, doc_next_toward }, { "pow", _DecOpt_mpd_qpow, METH_VARARGS, doc_pow }, /* alias for power */ { "power", _DecOpt_mpd_qpow, METH_VARARGS, doc_power }, - { "quantize", _DecOpt_mpd_qquantize, METH_VARARGS, doc_quantize }, + { "quantize", (PyCFunction)_Dec_mpd_qquantize, METH_VARARGS|METH_KEYWORDS, doc_quantize }, { "rem", _DecOpt_mpd_qrem, METH_VARARGS, doc_rem }, /* alias for remainder */ { "remainder", _DecOpt_mpd_qrem, METH_VARARGS, doc_remainder }, { "remainder_near", _DecOpt_mpd_qrem_near, METH_VARARGS, doc_remainder_near }, @@ -4568,7 +4612,7 @@ ctx = CtxAddr(self); CONVERT_OP_SET(v, &result, ctx); - return (PyObject *)result; + return (PyObject *) result; } /* Arithmetic operations */ From python-checkins at python.org Sun Jan 2 15:20:16 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 2 Jan 2011 15:20:16 +0100 (CET) Subject: [Python-checkins] r87626 - python/branches/release27-maint/Modules/_json.c Message-ID: <20110102142016.5237FEE986@mail.python.org> Author: georg.brandl Date: Sun Jan 2 15:20:16 2011 New Revision: 87626 Log: #10804: fix copy-paste error when checking assigned fields for NULL. Modified: python/branches/release27-maint/Modules/_json.c Modified: python/branches/release27-maint/Modules/_json.c ============================================================================== --- python/branches/release27-maint/Modules/_json.c (original) +++ python/branches/release27-maint/Modules/_json.c Sun Jan 2 15:20:16 2011 @@ -1732,7 +1732,7 @@ if (s->object_hook == NULL) goto bail; s->pairs_hook = PyObject_GetAttrString(ctx, "object_pairs_hook"); - if (s->object_hook == NULL) + if (s->pairs_hook == NULL) goto bail; s->parse_float = PyObject_GetAttrString(ctx, "parse_float"); if (s->parse_float == NULL) From python-checkins at python.org Sun Jan 2 15:23:43 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 2 Jan 2011 15:23:43 +0100 (CET) Subject: [Python-checkins] r87627 - python/branches/py3k/Doc/library/optparse.rst Message-ID: <20110102142343.41402EE986@mail.python.org> Author: georg.brandl Date: Sun Jan 2 15:23:43 2011 New Revision: 87627 Log: #1665333: add more docs for optparse.OptionGroup. Modified: python/branches/py3k/Doc/library/optparse.rst Modified: python/branches/py3k/Doc/library/optparse.rst ============================================================================== --- python/branches/py3k/Doc/library/optparse.rst (original) +++ python/branches/py3k/Doc/library/optparse.rst Sun Jan 2 15:23:43 2011 @@ -61,9 +61,9 @@ .. code-block:: text - usage: [options] + Usage: [options] - options: + Options: -h, --help show this help message and exit -f FILE, --file=FILE write report to FILE -q, --quiet don't print status messages to stdout @@ -492,9 +492,9 @@ .. code-block:: text - usage: [options] arg1 arg2 + Usage: [options] arg1 arg2 - options: + Options: -h, --help show this help message and exit -v, --verbose make lots of noise [default] -q, --quiet be vewwy quiet (I'm hunting wabbits) @@ -518,7 +518,7 @@ is then printed before the detailed option help. If you don't supply a usage string, :mod:`optparse` uses a bland but sensible - default: ``"usage: %prog [options]"``, which is fine if your script doesn't + default: ``"Usage: %prog [options]"``, which is fine if your script doesn't take any positional arguments. * every option defines a help string, and doesn't worry about line-wrapping--- @@ -550,12 +550,33 @@ default value. If an option has no default value (or the default value is ``None``), ``%default`` expands to ``none``. +Grouping Options +++++++++++++++++ + When dealing with many options, it is convenient to group these options for better help output. An :class:`OptionParser` can contain several option groups, each of which can contain several options. -Continuing with the parser defined above, adding an :class:`OptionGroup` to a -parser is easy:: +An option group is obtained using the class :class:`OptionGroup`: + +.. class:: OptionGroup(parser, title, description=None) + + where + + * parser is the :class:`OptionParser` instance the group will be insterted in + to + * title is the group title + * description, optional, is a long description of the group + +:class:`OptionGroup` inherits from :class:`OptionContainer` (like +:class:`OptionParser`) and so the :meth:`add_option` method can be used to add +an option to the group. + +Once all the options are declared, using the :class:`OptionParser` method +:meth:`add_option_group` the group is added to the previously defined parser. + +Continuing with the parser defined in the previous section, adding an +:class:`OptionGroup` to a parser is easy:: group = OptionGroup(parser, "Dangerous Options", "Caution: use these options at your own risk. " @@ -567,20 +588,73 @@ .. code-block:: text - usage: [options] arg1 arg2 + Usage: [options] arg1 arg2 + + Options: + -h, --help show this help message and exit + -v, --verbose make lots of noise [default] + -q, --quiet be vewwy quiet (I'm hunting wabbits) + -f FILE, --filename=FILE + write output to FILE + -m MODE, --mode=MODE interaction mode: novice, intermediate, or + expert [default: intermediate] + + Dangerous Options: + Caution: use these options at your own risk. It is believed that some + of them bite. + + -g Group option. + +A bit more complete example might invole using more than one group: still +extendind the previous example:: + + group = OptionGroup(parser, "Dangerous Options", + "Caution: use these options at your own risk. " + "It is believed that some of them bite.") + group.add_option("-g", action="store_true", help="Group option.") + parser.add_option_group(group) + + group = OptionGroup(parser, "Debug Options") + group.add_option("-d", "--debug", action="store_true", + help="Print debug information") + group.add_option("-s", "--sql", action="store_true", + help="Print all SQL statements executed") + group.add_option("-e", action="store_true", help="Print every action done") + parser.add_option_group(group) + +that results in the following output: + +.. code-block:: text + + Usage: [options] arg1 arg2 + + Options: + -h, --help show this help message and exit + -v, --verbose make lots of noise [default] + -q, --quiet be vewwy quiet (I'm hunting wabbits) + -f FILE, --filename=FILE + write output to FILE + -m MODE, --mode=MODE interaction mode: novice, intermediate, or expert + [default: intermediate] + + Dangerous Options: + Caution: use these options at your own risk. It is believed that some + of them bite. + + -g Group option. + + Debug Options: + -d, --debug Print debug information + -s, --sql Print all SQL statements executed + -e Print every action done + +Another interesting method, in particular when working programmatically with +option groups is: + +.. method:: OptionParser.get_option_group(opt_str) - options: - -h, --help show this help message and exit - -v, --verbose make lots of noise [default] - -q, --quiet be vewwy quiet (I'm hunting wabbits) - -fFILE, --file=FILE write output to FILE - -mMODE, --mode=MODE interaction mode: one of 'novice', 'intermediate' - [default], 'expert' - - Dangerous Options: - Caution: use of these options is at your own risk. It is believed that - some of them bite. - -g Group option. + Return, if defined, the :class:`OptionGroup` that has the title or the long + description equals to *opt_str* .. _optparse-printing-version-string: @@ -652,14 +726,14 @@ that takes an integer:: $ /usr/bin/foo -n 4x - usage: foo [options] + Usage: foo [options] foo: error: option -n: invalid integer value: '4x' Or, where the user fails to pass a value at all:: $ /usr/bin/foo -n - usage: foo [options] + Usage: foo [options] foo: error: -n option requires an argument @@ -1161,9 +1235,9 @@ .. code-block:: text - usage: foo.py [options] + Usage: foo.py [options] - options: + Options: -h, --help Show this help message and exit -v Be moderately verbose --file=FILENAME Input file to read data from @@ -1358,7 +1432,7 @@ option strings. Now ``--dry-run`` is the only way for the user to activate that option. If the user asks for help, the help message will reflect that:: - options: + Options: --dry-run do no harm [...] -n, --noisy be noisy @@ -1374,7 +1448,7 @@ At this point, the original ``-n``/``--dry-run`` option is no longer accessible, so :mod:`optparse` removes it, leaving this help text:: - options: + Options: [...] -n, --noisy be noisy --dry-run new dry-run option From python-checkins at python.org Sun Jan 2 17:16:10 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 17:16:10 +0100 (CET) Subject: [Python-checkins] r87628 - python/branches/py3k/Lib/test/test_threadsignals.py Message-ID: <20110102161610.1F336EE985@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 17:16:09 2011 New Revision: 87628 Log: Relax test condition a lot Modified: python/branches/py3k/Lib/test/test_threadsignals.py Modified: python/branches/py3k/Lib/test/test_threadsignals.py ============================================================================== --- python/branches/py3k/Lib/test/test_threadsignals.py (original) +++ python/branches/py3k/Lib/test/test_threadsignals.py Sun Jan 2 17:16:09 2011 @@ -176,8 +176,9 @@ self.assertLess(self.end - self.start, 2.0) self.assertGreater(self.end - self.start, 0.3) # If the signal is received several times before PyErr_CheckSignals() - # is called, the handler will get called less than 40 times. - self.assertGreater(self.sigs_recvd, 20) + # is called, the handler will get called less than 40 times. Just + # check it's been called at least once. + self.assertGreater(self.sigs_recvd, 0) finally: signal.signal(signal.SIGUSR1, old_handler) From python-checkins at python.org Sun Jan 2 17:33:08 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 17:33:08 +0100 (CET) Subject: [Python-checkins] r87629 - in python/branches/py3k-cdecimal/Lib/test/mpdecimal: config.h.in configure configure.in Message-ID: <20110102163308.887E5EE993@mail.python.org> Author: stefan.krah Date: Sun Jan 2 17:33:08 2011 New Revision: 87629 Log: Automatic workarounds for the following toolchain bugs: 1) gcc-4.5 miscompiles inline asm: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html 2) gcc-4.6/glibc: _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/config.h.in python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure.in Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/config.h.in ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/config.h.in (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/config.h.in Sun Jan 2 17:33:08 2011 @@ -1,11 +1,18 @@ /* config.h.in. Generated from configure.in by autoheader. */ -/* Define if we can use x64 gcc inline assembler */ +/* Define if the gcc version is 4.5.x. */ +#undef HAVE_GCC_4_5 + +/* Define if we can use x64 gcc inline assembler. */ #undef HAVE_GCC_ASM_FOR_X64 -/* Define if we can use x87 gcc inline assembler */ +/* Define if we can use x87 gcc inline assembler. */ #undef HAVE_GCC_ASM_FOR_X87 +/* Define if glibc has incorrect _FORTIFY_SOURCE wrappers for memmove and + bcopy. */ +#undef HAVE_GLIBC_MEMMOVE_BUG + /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H @@ -30,7 +37,7 @@ /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H -/* Define if your compiler provides __uint128_t */ +/* Define if your compiler provides __uint128_t. */ #undef HAVE_UINT128_T /* Define to 1 if you have the header file. */ Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure Sun Jan 2 17:33:08 2011 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.67 for mpdecimal 2.0. +# Generated by GNU Autoconf 2.67 for mpdecimal @RELEASE_VERSION at . # # Report bugs to . # @@ -551,11 +551,11 @@ # Identity of this package. PACKAGE_NAME='mpdecimal' -PACKAGE_TARNAME='mpdecimal-2.0.tar.gz' -PACKAGE_VERSION='2.0' -PACKAGE_STRING='mpdecimal 2.0' +PACKAGE_TARNAME='mpdecimal' +PACKAGE_VERSION='@RELEASE_VERSION@' +PACKAGE_STRING='mpdecimal @RELEASE_VERSION@' PACKAGE_BUGREPORT='mpdecimal-bugs at bytereef.org' -PACKAGE_URL='http://www.bytereef.org/libmpdec.html' +PACKAGE_URL='http://www.bytereef.org/mpdecimal/index.html' # Factoring default headers for most tests. ac_includes_default="\ @@ -1216,7 +1216,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures mpdecimal 2.0 to adapt to many kinds of systems. +\`configure' configures mpdecimal @RELEASE_VERSION@ to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1264,8 +1264,7 @@ --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] - --docdir=DIR documentation root - [DATAROOTDIR/doc/mpdecimal-2.0.tar.gz] + --docdir=DIR documentation root [DATAROOTDIR/doc/mpdecimal] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] @@ -1278,13 +1277,13 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of mpdecimal 2.0:";; + short | recursive ) echo "Configuration of mpdecimal @RELEASE_VERSION@:";; esac cat <<\_ACEOF Some influential environment variables: MACHINE force configuration: x64, uint128, ansi64, ppro, ansi32, - ansi-legacy, universal + ansi-legacy CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a @@ -1298,7 +1297,7 @@ it to find libraries and programs with nonstandard names/locations. Report bugs to . -mpdecimal home page: . +mpdecimal home page: . _ACEOF ac_status=$? fi @@ -1361,7 +1360,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -mpdecimal configure 2.0 +mpdecimal configure @RELEASE_VERSION@ generated by GNU Autoconf 2.67 Copyright (C) 2010 Free Software Foundation, Inc. @@ -2022,7 +2021,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by mpdecimal $as_me 2.0, which was +It was created by mpdecimal $as_me @RELEASE_VERSION@, which was generated by GNU Autoconf 2.67. Invocation command line was $ $0 $@ @@ -3877,11 +3876,57 @@ +# _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: +# http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for glibc _FORTIFY_SOURCE/memmove bug" >&5 +$as_echo_n "checking for glibc _FORTIFY_SOURCE/memmove bug... " >&6; } +saved_cflags="$CFLAGS" +CFLAGS="-O2 -D_FORTIFY_SOURCE=2" +if test "$cross_compiling" = yes; then : + have_glibc_memmove_bug=undefined +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +void foo(void *p, void *q) { memmove(p, q, 19); } +int main() { + char a[32] = "123456789000000000"; + foo(&a[9], a); + if (strcmp(a, "123456789123456789000000000") != 0) + return 1; + foo(a, &a[9]); + if (strcmp(a, "123456789000000000") != 0) + return 1; + return 0; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + have_glibc_memmove_bug=no +else + have_glibc_memmove_bug=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +CFLAGS="$saved_cflags" +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_glibc_memmove_bug" >&5 +$as_echo "$have_glibc_memmove_bug" >&6; } +if test "$have_glibc_memmove_bug" = yes; then + +$as_echo "#define HAVE_GLIBC_MEMMOVE_BUG 1" >>confdefs.h + +fi + # suncc is dectected as cc: case $ac_sys_system in sun*|Sun*) case $CC in - cc|suncc) + cc) CC=suncc ;; esac @@ -3896,34 +3941,36 @@ MPD_CCOV= MPD_LDCOV= case $CC in - gcc) + *gcc*) MPD_WARN="-Wall -W -Wno-unknown-pragmas" MPD_OPT="-O2 -fpic -s" MPD_PGEN="-fprofile-generate -fprofile-values" MPD_PUSE="-fprofile-use -freorder-blocks" - MPD_CCOV="-DTEST_COVERAGE -O0 -g -fno-inline -fprofile-arcs -ftest-coverage -fpic" - MPD_LDCOV="-fprofile-arcs" + MPD_CCOV="-DTEST_COVERAGE -O0 -g -fno-inline -fprofile-arcs -ftest-coverage -fpic" + MPD_LDCOV="-fprofile-arcs" ;; - icc) + *icc*) AR=xiar MPD_WARN="-Wall -Wno-unknown-pragmas" MPD_OPT="-O2 -fpic -s" MPD_PGEN="-wd11505 -prof-gen" MPD_PUSE="-wd11505 -prof-use" ;; - clang) + *clang*) MPD_WARN="-Wall -W -Wno-unknown-pragmas" MPD_OPT="-O2 -fpic" ;; - suncc) + *suncc*) MPD_WARN= MPD_OPT="-O2 -fpic -s" ;; esac # Auto-detect machine dependent settings: +M64= M32= if test -n "$MACHINE"; then + M64="-m64 " M32="-m32 " case "$MACHINE" in x64|uint128|ansi64|full_coverage|ppro|ansi32|ansi-legacy|universal) @@ -3944,9 +3991,9 @@ MACHINE="ansi32" if test $have_gcc_asm_for_x87 = yes; then case $CC in - gcc|clang) # icc >= 11.0 works as well + *gcc*|*clang*) # icc >= 11.0 works as well case $ac_sys_system in - darwin|Darwin) + darwin*|Darwin*) ;; *) MACHINE="ppro" @@ -3963,27 +4010,53 @@ CONFIGURE_LDFLAGS= case "$MACHINE" in x64) - MPD_CONFIG="-DCONFIG_64 -DASM" + MPD_CONFIG=$M64"-DCONFIG_64 -DASM" + CONFIGURE_LDFLAGS=$M64 MPD_PREC=19 MPD_DPREC=38 ;; uint128) - MPD_CONFIG="-DCONFIG_64 -DANSI -DHAVE_UINT128_T" + MPD_CONFIG=$M64"-DCONFIG_64 -DANSI -DHAVE_UINT128_T" + CONFIGURE_LDFLAGS=$M64 MPD_PREC=19 MPD_DPREC=38 ;; ansi64) - MPD_CONFIG="-DCONFIG_64 -DANSI" + MPD_CONFIG=$M64"-DCONFIG_64 -DANSI" + CONFIGURE_LDFLAGS=$M64 MPD_PREC=19 MPD_DPREC=38 ;; full_coverage) # Formerly ansi64c32, for testing only! - MPD_CONFIG="-DCONFIG_32 -DANSI" + MPD_CONFIG=$M64"-DCONFIG_32 -DANSI" + CONFIGURE_LDFLAGS=$M64 ;; ppro) MPD_CONFIG=$M32"-DCONFIG_32 -DPPRO -DASM" CONFIGURE_LDFLAGS=$M32 + # gcc-4.5 miscompiles inline asm: + # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 + # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html + case $CC in + *gcc*) + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc-4.5" >&5 +$as_echo_n "checking for gcc-4.5... " >&6; } + gcc_version=`$CC -dumpversion` + have_gcc_4_5=no + case $gcc_version in + 4.5*) + have_gcc_4_5=yes + MPD_CONFIG="$MPD_CONFIG -fno-ipa-pure-const" + +$as_echo "#define HAVE_GCC_4_5 1" >>confdefs.h + + ;; + esac + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_4_5" >&5 +$as_echo "$have_gcc_4_5" >&6; } + ;; + esac ;; ansi32) MPD_CONFIG=$M32"-DCONFIG_32 -DANSI" @@ -4015,7 +4088,10 @@ if test -z "$CFLAGS"; then CONFIGURE_CFLAGS="$MPD_WARN $MPD_CONFIG $MPD_OPT" else - CONFIGURE_CFLAGS="$CFLAGS" + CONFIGURE_CFLAGS="$MPD_CONFIG -fpic $CFLAGS" +fi +if test "$have_glibc_memmove_bug" = yes; then + CONFIGURE_CFLAGS="$CONFIGURE_CFLAGS -U_FORTIFY_SOURCE" fi if test -n "$LDFLAGS"; then @@ -4531,7 +4607,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by mpdecimal $as_me 2.0, which was +This file was extended by mpdecimal $as_me @RELEASE_VERSION@, which was generated by GNU Autoconf 2.67. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4588,13 +4664,13 @@ $config_headers Report bugs to . -mpdecimal home page: ." +mpdecimal home page: ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -mpdecimal config.status 2.0 +mpdecimal config.status @RELEASE_VERSION@ configured by $0, generated by GNU Autoconf 2.67, with options \\"\$ac_cs_config\\" @@ -5297,5 +5373,25 @@ fi +GLIBC_MEMMOVE_BUG_WARN=" +***************************** WARNING ********************************* + +Detected glibc _FORTIFY_SOURCE/memmove bug. See: + + http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html +Enabling -U_FORTIFY_SOURCE workaround. If -D_FORTIFY_SOURCE is also +present in the command line, make sure that the order of the two +options is: + + ... -D_FORTIFY_SOURCE=2 ... -U_FORTIFY_SOURCE ... + +A better solution is to upgrade glibc or to report the bug to your +OS vendor. + +***************************** WARNING ********************************* +" +if test "$have_glibc_memmove_bug" = yes; then + echo "$GLIBC_MEMMOVE_BUG_WARN" +fi Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure.in ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure.in (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure.in Sun Jan 2 17:33:08 2011 @@ -1,17 +1,10 @@ dnl Some parts taken from Python's configure.in. -dnl Only use correct autoconf version: -m4_define([version_required], -[m4_if(m4_version_compare(m4_defn([m4_PACKAGE_VERSION]), [$1]), 0, - [], - [m4_fatal([Autoconf version $1 is required for mpdecimal], 63)]) -]) -version_required(2.67) - -AC_INIT(mpdecimal, 2.0, mpdecimal-bugs at bytereef.org, mpdecimal-2.0.tar.gz, http://www.bytereef.org/libmpdec.html) +AC_PREREQ([2.67]) +AC_INIT(mpdecimal, @RELEASE_VERSION@, mpdecimal-bugs at bytereef.org, mpdecimal, http://www.bytereef.org/mpdecimal/index.html) AC_CONFIG_HEADER(config.h) AC_CONFIG_FILES([Makefile tests/Makefile]) -AC_ARG_VAR(MACHINE, [force configuration: x64, uint128, ansi64, ppro, ansi32, ansi-legacy, universal]) +AC_ARG_VAR(MACHINE, [force configuration: x64, uint128, ansi64, ppro, ansi32, ansi-legacy]) LIBSHARED=libmpdec.so.$PACKAGE_VERSION AC_SUBST(LIBSHARED) @@ -42,7 +35,7 @@ AC_TYPE_UINT32_T AC_TYPE_UINT64_T AC_CHECK_TYPE(__uint128_t, AC_DEFINE(HAVE_UINT128_T, 1, - [Define if your compiler provides __uint128_t]),,) + [Define if your compiler provides __uint128_t.]),,) # Sizes of various types: AC_CHECK_SIZEOF(size_t, 4) @@ -56,7 +49,7 @@ AC_MSG_RESULT($have_gcc_asm_for_x64) if test "$have_gcc_asm_for_x64" = yes; then AC_DEFINE(HAVE_GCC_ASM_FOR_X64, 1, - [Define if we can use x64 gcc inline assembler]) + [Define if we can use x64 gcc inline assembler.]) fi # x87 with gcc asm: @@ -69,7 +62,7 @@ AC_MSG_RESULT($have_gcc_asm_for_x87) if test "$have_gcc_asm_for_x87" = yes; then AC_DEFINE(HAVE_GCC_ASM_FOR_X87, 1, - [Define if we can use x87 gcc inline assembler]) + [Define if we can use x87 gcc inline assembler.]) fi # gmp for extended tests: @@ -108,11 +101,43 @@ AC_SUBST(GMPDEPS) AC_SUBST(GMPPATH) +# _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect: +# http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html +AC_MSG_CHECKING(for glibc _FORTIFY_SOURCE/memmove bug) +saved_cflags="$CFLAGS" +CFLAGS="-O2 -D_FORTIFY_SOURCE=2" +AC_RUN_IFELSE([AC_LANG_SOURCE([[ +#include +#include +#include +void foo(void *p, void *q) { memmove(p, q, 19); } +int main() { + char a[32] = "123456789000000000"; + foo(&a[9], a); + if (strcmp(a, "123456789123456789000000000") != 0) + return 1; + foo(a, &a[9]); + if (strcmp(a, "123456789000000000") != 0) + return 1; + return 0; +} +]])], +[have_glibc_memmove_bug=no], +[have_glibc_memmove_bug=yes], +[have_glibc_memmove_bug=undefined]) +CFLAGS="$saved_cflags" +AC_MSG_RESULT($have_glibc_memmove_bug) +if test "$have_glibc_memmove_bug" = yes; then + AC_DEFINE(HAVE_GLIBC_MEMMOVE_BUG, 1, + [Define if glibc has incorrect _FORTIFY_SOURCE wrappers + for memmove and bcopy.]) +fi + # suncc is dectected as cc: case $ac_sys_system in sun*|Sun*) case $CC in - cc|suncc) + cc) CC=suncc ;; esac @@ -127,34 +152,36 @@ MPD_CCOV= MPD_LDCOV= case $CC in - gcc) + *gcc*) MPD_WARN="-Wall -W -Wno-unknown-pragmas" MPD_OPT="-O2 -fpic -s" MPD_PGEN="-fprofile-generate -fprofile-values" MPD_PUSE="-fprofile-use -freorder-blocks" - MPD_CCOV="-DTEST_COVERAGE -O0 -g -fno-inline -fprofile-arcs -ftest-coverage -fpic" - MPD_LDCOV="-fprofile-arcs" + MPD_CCOV="-DTEST_COVERAGE -O0 -g -fno-inline -fprofile-arcs -ftest-coverage -fpic" + MPD_LDCOV="-fprofile-arcs" ;; - icc) + *icc*) AR=xiar MPD_WARN="-Wall -Wno-unknown-pragmas" MPD_OPT="-O2 -fpic -s" MPD_PGEN="-wd11505 -prof-gen" MPD_PUSE="-wd11505 -prof-use" ;; - clang) + *clang*) MPD_WARN="-Wall -W -Wno-unknown-pragmas" MPD_OPT="-O2 -fpic" ;; - suncc) + *suncc*) MPD_WARN= MPD_OPT="-O2 -fpic -s" ;; esac # Auto-detect machine dependent settings: +M64= M32= if test -n "$MACHINE"; then + M64="-m64 " M32="-m32 " case "$MACHINE" in x64|uint128|ansi64|full_coverage|ppro|ansi32|ansi-legacy|universal) @@ -175,9 +202,9 @@ MACHINE="ansi32" if test $have_gcc_asm_for_x87 = yes; then case $CC in - gcc|clang) # icc >= 11.0 works as well + *gcc*|*clang*) # icc >= 11.0 works as well case $ac_sys_system in - darwin|Darwin) + darwin*|Darwin*) ;; *) MACHINE="ppro" @@ -194,27 +221,50 @@ CONFIGURE_LDFLAGS= case "$MACHINE" in x64) - MPD_CONFIG="-DCONFIG_64 -DASM" + MPD_CONFIG=$M64"-DCONFIG_64 -DASM" + CONFIGURE_LDFLAGS=$M64 MPD_PREC=19 MPD_DPREC=38 ;; uint128) - MPD_CONFIG="-DCONFIG_64 -DANSI -DHAVE_UINT128_T" + MPD_CONFIG=$M64"-DCONFIG_64 -DANSI -DHAVE_UINT128_T" + CONFIGURE_LDFLAGS=$M64 MPD_PREC=19 MPD_DPREC=38 ;; ansi64) - MPD_CONFIG="-DCONFIG_64 -DANSI" + MPD_CONFIG=$M64"-DCONFIG_64 -DANSI" + CONFIGURE_LDFLAGS=$M64 MPD_PREC=19 MPD_DPREC=38 ;; full_coverage) # Formerly ansi64c32, for testing only! - MPD_CONFIG="-DCONFIG_32 -DANSI" + MPD_CONFIG=$M64"-DCONFIG_32 -DANSI" + CONFIGURE_LDFLAGS=$M64 ;; ppro) MPD_CONFIG=$M32"-DCONFIG_32 -DPPRO -DASM" CONFIGURE_LDFLAGS=$M32 + # gcc-4.5 miscompiles inline asm: + # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 + # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html + case $CC in + *gcc*) + AC_MSG_CHECKING(for gcc-4.5) + gcc_version=`$CC -dumpversion` + have_gcc_4_5=no + case $gcc_version in + 4.5*) + have_gcc_4_5=yes + MPD_CONFIG="$MPD_CONFIG -fno-ipa-pure-const" + AC_DEFINE(HAVE_GCC_4_5, 1, + [Define if the gcc version is 4.5.x.]) + ;; + esac + AC_MSG_RESULT($have_gcc_4_5) + ;; + esac ;; ansi32) MPD_CONFIG=$M32"-DCONFIG_32 -DANSI" @@ -246,7 +296,10 @@ if test -z "$CFLAGS"; then CONFIGURE_CFLAGS="$MPD_WARN $MPD_CONFIG $MPD_OPT" else - CONFIGURE_CFLAGS="$CFLAGS" + CONFIGURE_CFLAGS="$MPD_CONFIG -fpic $CFLAGS" +fi +if test "$have_glibc_memmove_bug" = yes; then + CONFIGURE_CFLAGS="$CONFIGURE_CFLAGS -U_FORTIFY_SOURCE" fi if test -n "$LDFLAGS"; then @@ -258,5 +311,25 @@ AC_OUTPUT +GLIBC_MEMMOVE_BUG_WARN=" +***************************** WARNING ********************************* + +Detected glibc _FORTIFY_SOURCE/memmove bug. See: + + http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html +Enabling -U_FORTIFY_SOURCE workaround. If -D_FORTIFY_SOURCE is also +present in the command line, make sure that the order of the two +options is: + + ... -D_FORTIFY_SOURCE=2 ... -U_FORTIFY_SOURCE ... + +A better solution is to upgrade glibc or to report the bug to your +OS vendor. + +***************************** WARNING ********************************* +" +if test "$have_glibc_memmove_bug" = yes; then + echo "$GLIBC_MEMMOVE_BUG_WARN" +fi From python-checkins at python.org Sun Jan 2 17:43:20 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 17:43:20 +0100 (CET) Subject: [Python-checkins] r87630 - python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.in Message-ID: <20110102164320.1CD38EE984@mail.python.org> Author: stefan.krah Date: Sun Jan 2 17:43:19 2011 New Revision: 87630 Log: Follow GNU Makefile standards. Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.in Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.in ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.in (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.in Sun Jan 2 17:43:19 2011 @@ -5,6 +5,7 @@ include vars.mk +PACKAGE_TARNAME = @PACKAGE_TARNAME@ LIBSTATIC = libmpdec.a LIBSONAME = @LIBSHARED@ LIBSHARED = @LIBSHARED@ @@ -13,8 +14,13 @@ LD = @CC@ AR = @AR@ GCOV ?= gcov -PREFIX = @prefix@ INC= -I../../../ -I../../../Include +prefix = @prefix@ +exec_prefix = @exec_prefix@ +includedir = @includedir@ +libdir = @libdir@ +datarootdir = @datarootdir@ +docdir = @docdir@ MPD_HEADER = @MPD_HEADER@ MPD_WARN = @MPD_WARN@ @@ -235,9 +241,9 @@ $(MAKE) profile_use install: FORCE - cp $(LIBSTATIC) $(PREFIX)/lib - cp $(LIBSHARED) $(PREFIX)/lib - cp mpdecimal.h $(PREFIX)/include + mkdir -p $(DESTDIR)$(includedir) && cp mpdecimal.h $(DESTDIR)$(includedir) + mkdir -p $(DESTDIR)$(libdir) && cp $(LIBSTATIC) $(LIBSHARED) $(DESTDIR)$(libdir) + mkdir -p $(DESTDIR)$(docdir) && cp -Rp doc/* $(DESTDIR)$(docdir) clean: FORCE rm -f *.o *.so *.gch *.gcda *.gcno *.gcov *.dyn *.dpi *.lock \ From python-checkins at python.org Sun Jan 2 17:46:30 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 17:46:30 +0100 (CET) Subject: [Python-checkins] r87631 - python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.vc Message-ID: <20110102164630.599A4EE984@mail.python.org> Author: stefan.krah Date: Sun Jan 2 17:46:30 2011 New Revision: 87631 Log: Keep the diff to upstream small. Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.vc Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.vc ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.vc (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.vc Sun Jan 2 17:46:30 2011 @@ -5,9 +5,9 @@ INSTALLDIR = . -LIBSTATIC = libmpdec-2.0.lib -LIBIMPORT = libmpdec-2.0.dll.lib -LIBSHARED = libmpdec-2.0.dll +LIBSTATIC = libmpdec- at RELEASE_VERSION@.lib +LIBIMPORT = libmpdec- at RELEASE_VERSION@.dll.lib +LIBSHARED = libmpdec- at RELEASE_VERSION@.dll OBJS = basearith.obj context.obj constants.obj convolute.obj crt.obj \ From python-checkins at python.org Sun Jan 2 17:52:37 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 17:52:37 +0100 (CET) Subject: [Python-checkins] r87632 - python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/cov.c Message-ID: <20110102165237.287DDEE988@mail.python.org> Author: stefan.krah Date: Sun Jan 2 17:52:37 2011 New Revision: 87632 Log: Do the right thing (even in the tests). Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/cov.c Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/cov.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/cov.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/cov.c Sun Jan 2 17:52:37 2011 @@ -12,6 +12,7 @@ #ifndef _MSC_VER #include #define ASSERT(p) if (!(p)) {abort();} + mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n); #else #define ASSERT(p) if (!(p)) {mpd_err_fatal("assertion failed");} #endif @@ -22,8 +23,6 @@ #endif -mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n); - static void mpd_testcontext(mpd_context_t *ctx) { mpd_defaultcontext(ctx); @@ -1164,8 +1163,9 @@ mpd_set_string(&a, "1.23456789e441", &ctx); mpd_fprint(fp, &a); rewind(fp); - fgets(buf, BUFSIZE, fp); - ASSERT(strcmp(buf, "1.23456789e441\n")) + if (fgets(buf, BUFSIZE, fp) != NULL) { + ASSERT(strcmp(buf, "1.23456789e441\n")) + } fclose(fp); } From python-checkins at python.org Sun Jan 2 17:54:10 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 17:54:10 +0100 (CET) Subject: [Python-checkins] r87633 - python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/ppro_mulmod.c Message-ID: <20110102165410.92704EE988@mail.python.org> Author: stefan.krah Date: Sun Jan 2 17:54:10 2011 New Revision: 87633 Log: Get rid of compiler warning. Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/ppro_mulmod.c Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/ppro_mulmod.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/ppro_mulmod.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/ppro_mulmod.c Sun Jan 2 17:54:10 2011 @@ -55,10 +55,8 @@ mpd_uint_t a, b, c, d; mpd_uint_t a1, a2, b1, b2; long i; - int cw; - - cw = mpd_set_fenv(); + (void)mpd_set_fenv(); fprintf(stderr, "%s:\n", argv[0]); fprintf(stderr, "testing MULMOD ... "); From python-checkins at python.org Sun Jan 2 17:57:18 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 17:57:18 +0100 (CET) Subject: [Python-checkins] r87634 - python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/testdata_dist/cov.decTest Message-ID: <20110102165718.4F7D4EE988@mail.python.org> Author: stefan.krah Date: Sun Jan 2 17:57:18 2011 New Revision: 87634 Log: Add coverage test to trigger allocation failure in _mpd_check_exp(). Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/testdata_dist/cov.decTest Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/testdata_dist/cov.decTest ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/testdata_dist/cov.decTest (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/testdata_dist/cov.decTest Sun Jan 2 17:57:18 2011 @@ -308,3 +308,13 @@ trunc10049 trunc 100.0 -> 100 trunc10050 trunc -100.0 -> -100 + +-- negative etop: trigger allocation failure in mpd_qshiftl. +maxexponent: 50 +minexponent: -50 +precision: 100 +clamp: 1 +etop10051 apply 1e+50 -> 100000000000000000000000000000000000000000000000000.0000000000000000000000000000000000000000000000000 Clamped + + + From python-checkins at python.org Sun Jan 2 18:02:03 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 18:02:03 +0100 (CET) Subject: [Python-checkins] r87635 - python/branches/py3k-cdecimal/Lib/test/mpdecimal/python/ctx-deccheck.py Message-ID: <20110102170203.46150EE986@mail.python.org> Author: stefan.krah Date: Sun Jan 2 18:02:02 2011 New Revision: 87635 Log: Add meaningful exit status. Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/python/ctx-deccheck.py Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/python/ctx-deccheck.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/python/ctx-deccheck.py (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/python/ctx-deccheck.py Sun Jan 2 18:02:02 2011 @@ -36,6 +36,7 @@ from randdec import * +EXIT_STATUS = 0 py_minor = sys.version_info[1] py_micro = sys.version_info[2] @@ -377,7 +378,6 @@ return self.un_resolve_ulp(result, "ln", operands) def __pow__(self, result, operands): - """See DIFFERENCES.txt""" if operands[2] is not None: # three argument __pow__ # issue7049: third arg must fit into precision if (operands[0].mpd.is_zero() != operands[1].mpd.is_zero()): @@ -395,6 +395,7 @@ context.f.flags[cdecimal.Inexact] and \ context.d.flags[decimal.Rounded] and \ context.d.flags[decimal.Inexact]: + # decimal.py: correctly-rounded pow() return self.bin_resolve_ulp(result, "__pow__", operands) else: return False @@ -460,9 +461,11 @@ """Verifies that after operation 'funcname' with operand(s) 'operands' result[0] and result[1] as well as the context flags have the same values.""" + global EXIT_STATUS if result[0] != result[1] or not context.assert_eq_status(): if obj_known_disagreement(result, funcname, operands): return # skip known disagreements + EXIT_STATUS = 1 raise CdecException(result, funcname, operands, str(context.f), str(context.d)) @@ -494,6 +497,7 @@ """Verifies that after operation 'funcname' with operand(s) 'operands' self.mpd and self.dec as well as the context flags have the same values.""" + global EXIT_STATUS mpdstr = str(self.mpd) decstr = str(self.dec) mpdstr_eng = self.mpd.to_eng_string() @@ -502,6 +506,7 @@ not context.assert_eq_status(): if cdec_known_disagreement(self, funcname, operands): return # skip known disagreements + EXIT_STATUS = 1 raise CdecException(self, funcname, operands, str(context.f), str(context.d)) @@ -1065,3 +1070,6 @@ prec_lst = sorted(random.sample(range(1, 101), samples)) test_from_float(prec_lst) + + + sys.exit(EXIT_STATUS) From python-checkins at python.org Sun Jan 2 18:04:44 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 18:04:44 +0100 (CET) Subject: [Python-checkins] r87636 - python/branches/py3k-cdecimal/Lib/test/mpdecimal/python/deccheck.py Message-ID: <20110102170444.DAE7BEE988@mail.python.org> Author: stefan.krah Date: Sun Jan 2 18:04:44 2011 New Revision: 87636 Log: 1) Add tests for quantize() rounding argument. 2) Add proper exit status. Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/python/deccheck.py Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/python/deccheck.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/python/deccheck.py (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/python/deccheck.py Sun Jan 2 18:04:44 2011 @@ -47,6 +47,7 @@ from randfloat import * +EXIT_STATUS = 0 py_minor = sys.version_info[1] py_micro = sys.version_info[2] @@ -410,7 +411,6 @@ return self.un_resolve_ulp(result, "ln", operands) def __pow__(self, result, operands): - """See DIFFERENCES.txt""" if operands[2] is not None: # three argument __pow__ # issue7049: third arg must fit into precision if (operands[0].mpd.is_zero() != operands[1].mpd.is_zero()): @@ -428,6 +428,7 @@ context.f.flags[cdecimal.Inexact] and \ context.d.flags[decimal.Rounded] and \ context.d.flags[decimal.Inexact]: + # decimal.py: correctly-rounded pow() return self.bin_resolve_ulp(result, "__pow__", operands) else: return False @@ -509,9 +510,11 @@ """Verifies that after operation 'funcname' with operand(s) 'operands' result[0] and result[1] as well as the context flags have the same values.""" + global EXIT_STATUS if result[0] != result[1] or not context.assert_eq_status(): if obj_known_disagreement(result, funcname, operands): return # skip known disagreements + EXIT_STATUS = 1 raise CdecException(result, funcname, operands, str(context.f), str(context.d)) @@ -541,6 +544,7 @@ """Verifies that after operation 'funcname' with operand(s) 'operands' self.mpd and self.dec as well as the context flags have the same values.""" + global EXIT_STATUS mpdstr = str(self.mpd) decstr = str(self.dec) mpdstr_eng = self.mpd.to_eng_string() @@ -555,6 +559,7 @@ or not context.assert_eq_status(): if cdec_known_disagreement(self, funcname, operands): return # skip known disagreements + EXIT_STATUS = 1 raise CdecException(self, funcname, operands, str(context.f), str(context.d)) @@ -1021,8 +1026,6 @@ def to_sci_string(self): context.clear_status() - # cdecimal's Decimal has a 'to_sci_string' method - # that honours the default context. r_mpd = self.mpd.to_sci_string() r_dec = context.d.to_sci_string(self.dec) verify((r_mpd, r_dec), 'to_sci_string', (self,)) @@ -1338,6 +1341,75 @@ except CdecException as err: log(err) +def assert_eq_status(c, d): + """assert equality of cdecimal and decimal status""" + for signal in c.flags: + if signal == cdecimal.FloatOperation: + continue + if c.flags[signal] == (not d.flags[deccond[signal]]): + return False + return True + +def test_quantize_api(method, prec, exprange, restr_range, iter): + for a in un_incr_digits(prec, restr_range, 1): + emax = random.randrange(exprange) + emin = random.randrange(-exprange, 0) + clamp = random.randrange(2) + exp = randdec(2*prec, exprange) + for rounding in sorted(decround): + try: + c = cdecimal.Context(prec=prec, Emax=emax, Emin=emin, clamp=clamp, traps=[]) + d = decimal.Context(prec=prec, Emax=emax, Emin=emin, traps=[]) + attr = 'clamp' if py_minor >= 2 else "_clamp" + setattr(d, attr, clamp) + + x = cdecimal.Decimal(a) + y = cdecimal.Decimal(exp) + cresult = x.quantize(y, rounding, c) + + u = decimal.Decimal(a) + v = decimal.Decimal(exp) + dresult = u.quantize(v, decround[rounding], d) + except Exception as err: + print(err) + continue + if str(cresult) != str(dresult) or \ + not assert_eq_status(c, d): + print("%s\n%s\n" % (c, d)) + print("x: %s\ny: %s\nu: %s\nv: %s\n" % (x, y, u, v)) + print("a: %s exp: %s\n" % (a, exp)) + print("cresult: %s\ndresult: %s\n" % (cresult, dresult)) + for i in range(1000): + a = randdec(prec, 9999) + prec = random.randrange(1, 50) + emax = random.randrange(exprange) + emin = random.randrange(-exprange, 0) + clamp = random.randrange(2) + exp = randdec(2*prec, exprange) + for rounding in sorted(decround): + try: + c = cdecimal.Context(prec=prec, Emax=emax, Emin=emin, clamp=clamp, traps=[]) + d = decimal.Context(prec=prec, Emax=emax, Emin=emin, traps=[]) + attr = 'clamp' if py_minor >= 2 else "_clamp" + setattr(d, attr, clamp) + + x = cdecimal.Decimal(a) + y = cdecimal.Decimal(exp) + cresult = x.quantize(context=c, exp=y, rounding=rounding) + + u = decimal.Decimal(a) + v = decimal.Decimal(exp) + dresult = u.quantize(context=d, exp=v, rounding=decround[rounding]) + except Exception as err: + print(err) + continue + if str(cresult) != str(dresult) or \ + not assert_eq_status(c, d): + print("%s\n%s\n" % (c, d)) + print("x: %s\ny: %s\nu: %s\nv: %s\n" % (x, y, u, v)) + print("a: %s exp: %s\n" % (a, exp)) + print("cresult: %s\ndresult: %s\n" % (cresult, dresult)) + if __name__ == '__main__': @@ -1449,6 +1521,8 @@ for method in ['logical_and', 'logical_or', 'logical_xor']: test_method(method, testspecs, test_bin_logical) + test_method('quantize_api', testspecs, test_quantize_api) + if py_minor >= 2: # Some tests will fail with 3.1, since alignment has been changed @@ -1458,3 +1532,6 @@ test_method('locale', testspecs, test_locale) test_method('round', testspecs, test_round) test_method('from_float', testspecs, test_from_float) + + + sys.exit(EXIT_STATUS) From python-checkins at python.org Sun Jan 2 18:23:11 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 18:23:11 +0100 (CET) Subject: [Python-checkins] r87637 - python/branches/py3k-cdecimal/Lib/test/decimal_tests.py Message-ID: <20110102172311.AC625EE984@mail.python.org> Author: stefan.krah Date: Sun Jan 2 18:23:11 2011 New Revision: 87637 Log: Add bignum and quantize() api tests. Modified: python/branches/py3k-cdecimal/Lib/test/decimal_tests.py Modified: python/branches/py3k-cdecimal/Lib/test/decimal_tests.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/decimal_tests.py (original) +++ python/branches/py3k-cdecimal/Lib/test/decimal_tests.py Sun Jan 2 18:23:11 2011 @@ -2128,6 +2128,38 @@ self.assertEqual(repr(context.create_decimal_from_float(10)), "Decimal('10')") + def test_quantize(self): + c = Context(Emax=99999, Emin=-99999) + self.assertEqual( + Decimal('7.335').quantize(Decimal('.01')), + Decimal('7.34') + ) + self.assertEqual( + Decimal('7.335').quantize(Decimal('.01'), rounding=ROUND_DOWN), + Decimal('7.33') + ) + self.assertRaises( + InvalidOperation, + Decimal("10e99999").quantize, Decimal('1e100000'), context=c + ) + if HAVE_CDECIMAL: + self.assertRaises( + TypeError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), [] + ) + self.assertRaises( + TypeError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), c + ) + self.assertRaises( + ValueError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), 10 + ) + self.assertRaises( + TypeError, + Decimal("1.23456789").quantize, Decimal('1e-100000'), ROUND_UP, 1000 + ) + class ContextAPItests(unittest.TestCase): def test_pickle(self): @@ -2892,10 +2924,10 @@ for attr in ['capitals', 'clamp', '_allcr']: self.assertRaises(ValueError, setattr, c, attr, -1) self.assertRaises(ValueError, setattr, c, attr, 2) + self.assertRaises(TypeError, setattr, c, attr, [1,2,3]) if HAVE_CONFIG_64: self.assertRaises(ValueError, setattr, c, attr, 2**32) self.assertRaises(ValueError, setattr, c, attr, 2**32+1) - self.assertRaises(TypeError, setattr, c, attr, [1,2,3]) # Specific: _flags, _traps for attr in ['_flags', '_traps']: @@ -3051,14 +3083,17 @@ self.assertEqual(x.to_integral(), 10) self.assertRaises(TypeError, x.to_integral, '10') self.assertRaises(TypeError, x.to_integral, 10, 'x') + self.assertRaises(ValueError, x.to_integral, 10) self.assertEqual(x.to_integral_value(), 10) self.assertRaises(TypeError, x.to_integral_value, '10') self.assertRaises(TypeError, x.to_integral_value, 10, 'x') + self.assertRaises(ValueError, x.to_integral_value, 10) self.assertEqual(x.to_integral_exact(), 10) self.assertRaises(TypeError, x.to_integral_exact, '10') self.assertRaises(TypeError, x.to_integral_exact, 10, 'x') + self.assertRaises(ValueError, x.to_integral_exact, 10) with localcontext() as c: x = Decimal("99999999999999999999999999.9").to_integral_value(ROUND_UP) @@ -3294,6 +3329,18 @@ self.assertTrue(c._traps&DecIEEEInvalidOperation) assertIsExclusivelySet(InvalidOperation, c.traps) + def test_bignum(self): + b1 = 10**35 + b2 = 10**36 + with localcontext() as c: + c.prec = 1000000 + for i in range(5): + a = random.randrange(b1, b2) + b = random.randrange(1000, 1200) + x = a ** b + y = Decimal(a) ** Decimal(b) + self.assertEqual(x, y) + def test_main(arith=False, verbose=None, todo_tests=None, debug=None): """ Execute the tests. From python-checkins at python.org Sun Jan 2 20:07:51 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 2 Jan 2011 20:07:51 +0100 (CET) Subject: [Python-checkins] r87638 - python/branches/py3k/Doc/library/ssl.rst Message-ID: <20110102190751.E24A8EE986@mail.python.org> Author: georg.brandl Date: Sun Jan 2 20:07:51 2011 New Revision: 87638 Log: Fix code indentation. Modified: python/branches/py3k/Doc/library/ssl.rst Modified: python/branches/py3k/Doc/library/ssl.rst ============================================================================== --- python/branches/py3k/Doc/library/ssl.rst (original) +++ python/branches/py3k/Doc/library/ssl.rst Sun Jan 2 20:07:51 2011 @@ -768,11 +768,11 @@ should use the following idiom:: try: - import ssl + import ssl except ImportError: - pass + pass else: - [ do something that requires SSL support ] + ... # do something that requires SSL support Client-side operation ^^^^^^^^^^^^^^^^^^^^^ @@ -883,26 +883,26 @@ method to create a server-side SSL socket for the connection:: while True: - newsocket, fromaddr = bindsocket.accept() - connstream = context.wrap_socket(newsocket, server_side=True) - try: - deal_with_client(connstream) - finally: - connstream.close() + newsocket, fromaddr = bindsocket.accept() + connstream = context.wrap_socket(newsocket, server_side=True) + try: + deal_with_client(connstream) + finally: + connstream.close() Then you'll read data from the ``connstream`` and do something with it till you are finished with the client (or the client is finished with you):: def deal_with_client(connstream): - data = connstream.recv(1024) - # empty data means the client is finished with us - while data: - if not do_something(connstream, data): - # we'll assume do_something returns False - # when we're finished with client - break - data = connstream.recv(1024) - # finished with client + data = connstream.recv(1024) + # empty data means the client is finished with us + while data: + if not do_something(connstream, data): + # we'll assume do_something returns False + # when we're finished with client + break + data = connstream.recv(1024) + # finished with client And go back to listening for new client connections (of course, a real server would probably handle each client connection in a separate thread, or put From python-checkins at python.org Sun Jan 2 20:34:03 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 20:34:03 +0100 (CET) Subject: [Python-checkins] r87639 - in python/branches/py3k: Misc/ACKS Misc/NEWS configure configure.in Message-ID: <20110102193403.F0C2EEE9A7@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 20:34:03 2011 New Revision: 87639 Log: Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD and DragonFly BSD. Patch by Nicolas Joly. Modified: python/branches/py3k/Misc/ACKS python/branches/py3k/Misc/NEWS python/branches/py3k/configure python/branches/py3k/configure.in Modified: python/branches/py3k/Misc/ACKS ============================================================================== --- python/branches/py3k/Misc/ACKS (original) +++ python/branches/py3k/Misc/ACKS Sun Jan 2 20:34:03 2011 @@ -422,6 +422,7 @@ Gregory K. Johnson Simon Johnston Thomas Jollans +Nicolas Joly Evan Jones Jeremy Jones Richard Jones Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sun Jan 2 20:34:03 2011 @@ -85,6 +85,9 @@ Build ----- +- Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD + and DragonFly BSD. Patch by Nicolas Joly. + - Issue #10679: The "idle", "pydoc" and "2to3" scripts are now installed with a version-specific suffix on "make altinstall". Modified: python/branches/py3k/configure ============================================================================== --- python/branches/py3k/configure (original) +++ python/branches/py3k/configure Sun Jan 2 20:34:03 2011 @@ -1,14 +1,14 @@ #! /bin/sh -# From configure.in Revision: 87207 . +# From configure.in Revision: 87577 . # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.67 for python 3.2. +# Generated by GNU Autoconf 2.65 for python 3.2. # # Report bugs to . # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software -# Foundation, Inc. +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. # # # This configure script is free software; the Free Software Foundation @@ -320,7 +320,7 @@ test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" } # as_fn_mkdir_p @@ -360,19 +360,19 @@ fi # as_fn_arith -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. +# script with status $?, using 1 if that was 0. as_fn_error () { - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 fi - $as_echo "$as_me: error: $2" >&2 + $as_echo "$as_me: error: $1" >&2 as_fn_exit $as_status } # as_fn_error @@ -534,7 +534,7 @@ exec 6>&1 # Name of the host. -# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` @@ -829,9 +829,8 @@ fi case $ac_option in - *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; - *=) ac_optarg= ;; - *) ac_optarg=yes ;; + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. @@ -876,7 +875,7 @@ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -902,7 +901,7 @@ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid feature name: $ac_useropt" + as_fn_error "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1106,7 +1105,7 @@ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1122,7 +1121,7 @@ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && - as_fn_error $? "invalid package name: $ac_useropt" + as_fn_error "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in @@ -1152,8 +1151,8 @@ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; - -*) as_fn_error $? "unrecognized option: \`$ac_option' -Try \`$0 --help' for more information" + -*) as_fn_error "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information." ;; *=*) @@ -1161,7 +1160,7 @@ # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) - as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; + as_fn_error "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; @@ -1179,13 +1178,13 @@ if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` - as_fn_error $? "missing argument to $ac_option" + as_fn_error "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; - fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; + fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi @@ -1208,7 +1207,7 @@ [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac - as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" + as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' @@ -1222,8 +1221,8 @@ if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used" >&2 + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -1238,9 +1237,9 @@ ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || - as_fn_error $? "working directory cannot be determined" + as_fn_error "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || - as_fn_error $? "pwd does not report name of working directory" + as_fn_error "pwd does not report name of working directory" # Find the source files, if location was not specified. @@ -1279,11 +1278,11 @@ fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." - as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" + as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( - cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then @@ -1323,7 +1322,7 @@ --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit - -q, --quiet, --silent do not print \`checking ...' messages + -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files @@ -1509,9 +1508,9 @@ if $ac_init_version; then cat <<\_ACEOF python configure 3.2 -generated by GNU Autoconf 2.67 +generated by GNU Autoconf 2.65 -Copyright (C) 2010 Free Software Foundation, Inc. +Copyright (C) 2009 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1581,7 +1580,7 @@ mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 - test $ac_status = 0; } > conftest.i && { + test $ac_status = 0; } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : @@ -1605,10 +1604,10 @@ ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - if eval "test \"\${$3+set}\"" = set; then : + if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 @@ -1644,7 +1643,7 @@ else ac_header_preproc=no fi -rm -f conftest.err conftest.i conftest.$ac_ext +rm -f conftest.err conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } @@ -1667,15 +1666,17 @@ $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} -( $as_echo "## -------------------------------------- ## +( cat <<\_ASBOX +## -------------------------------------- ## ## Report this to http://bugs.python.org/ ## -## -------------------------------------- ##" +## -------------------------------------- ## +_ASBOX ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" @@ -1739,7 +1740,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -1816,7 +1817,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1870,7 +1871,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for uint$2_t" >&5 $as_echo_n "checking for uint$2_t... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1900,7 +1901,8 @@ esac fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if eval test \"x\$"$3"\" = x"no"; then : + eval as_val=\$$3 + if test "x$as_val" = x""no; then : else break @@ -1923,7 +1925,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for int$2_t" >&5 $as_echo_n "checking for int$2_t... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=no" @@ -1934,11 +1936,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default - enum { N = $2 / 2 - 1 }; int main () { -static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; +static int test_array [1 - 2 * !(enum { N = $2 / 2 - 1 }; + 0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0 ; @@ -1949,11 +1951,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default - enum { N = $2 / 2 - 1 }; int main () { -static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) +static int test_array [1 - 2 * !(enum { N = $2 / 2 - 1 }; + ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0 @@ -1974,7 +1976,8 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - if eval test \"x\$"$3"\" = x"no"; then : + eval as_val=\$$3 + if test "x$as_val" = x""no; then : else break @@ -2174,7 +2177,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2242,7 +2245,7 @@ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2.$3" >&5 $as_echo_n "checking for $2.$3... " >&6; } -if eval "test \"\${$4+set}\"" = set; then : +if { as_var=$4; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2290,18 +2293,15 @@ } # ac_fn_c_check_member -# ac_fn_c_check_decl LINENO SYMBOL VAR INCLUDES -# --------------------------------------------- -# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR -# accordingly. +# ac_fn_c_check_decl LINENO SYMBOL VAR +# ------------------------------------ +# Tests whether SYMBOL is declared, setting cache variable VAR accordingly. ac_fn_c_check_decl () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - as_decl_name=`echo $2|sed 's/ *(.*//'` - as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 -$as_echo_n "checking whether $as_decl_name is declared... " >&6; } -if eval "test \"\${$3+set}\"" = set; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $2 is declared" >&5 +$as_echo_n "checking whether $2 is declared... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -2310,12 +2310,8 @@ int main () { -#ifndef $as_decl_name -#ifdef __cplusplus - (void) $as_decl_use; -#else - (void) $as_decl_name; -#endif +#ifndef $2 + (void) $2; #endif ; @@ -2340,7 +2336,7 @@ running configure, to aid debugging if configure makes a mistake. It was created by python $as_me 3.2, which was -generated by GNU Autoconf 2.67. Invocation command line was +generated by GNU Autoconf 2.65. Invocation command line was $ $0 $@ @@ -2450,9 +2446,11 @@ { echo - $as_echo "## ---------------- ## + cat <<\_ASBOX +## ---------------- ## ## Cache variables. ## -## ---------------- ##" +## ---------------- ## +_ASBOX echo # The following way of writing the cache mishandles newlines in values, ( @@ -2486,9 +2484,11 @@ ) echo - $as_echo "## ----------------- ## + cat <<\_ASBOX +## ----------------- ## ## Output variables. ## -## ----------------- ##" +## ----------------- ## +_ASBOX echo for ac_var in $ac_subst_vars do @@ -2501,9 +2501,11 @@ echo if test -n "$ac_subst_files"; then - $as_echo "## ------------------- ## + cat <<\_ASBOX +## ------------------- ## ## File substitutions. ## -## ------------------- ##" +## ------------------- ## +_ASBOX echo for ac_var in $ac_subst_files do @@ -2517,9 +2519,11 @@ fi if test -s confdefs.h; then - $as_echo "## ----------- ## + cat <<\_ASBOX +## ----------- ## ## confdefs.h. ## -## ----------- ##" +## ----------- ## +_ASBOX echo cat confdefs.h echo @@ -2574,12 +2578,7 @@ ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then - # We do not want a PATH search for config.site. - case $CONFIG_SITE in #(( - -*) ac_site_file1=./$CONFIG_SITE;; - */*) ac_site_file1=$CONFIG_SITE;; - *) ac_site_file1=./$CONFIG_SITE;; - esac + ac_site_file1=$CONFIG_SITE elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site @@ -2594,11 +2593,7 @@ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 - . "$ac_site_file" \ - || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 -$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "failed to load site script $ac_site_file -See \`config.log' for more details" "$LINENO" 5 ; } + . "$ac_site_file" fi done @@ -2674,7 +2669,7 @@ $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} - as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 + as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## @@ -2775,7 +2770,7 @@ UNIVERSALSDK=$enableval if test ! -d "${UNIVERSALSDK}" then - as_fn_error $? "--enable-universalsdk specifies non-existing SDK: ${UNIVERSALSDK}" "$LINENO" 5 + as_fn_error "--enable-universalsdk specifies non-existing SDK: ${UNIVERSALSDK}" "$LINENO" 5 fi ;; esac @@ -3167,7 +3162,7 @@ # If the user switches compilers, we can't believe the cache if test ! -z "$ac_cv_prog_CC" -a ! -z "$CC" -a "$CC" != "$ac_cv_prog_CC" then - as_fn_error $? "cached CC is different -- throw away $cache_file + as_fn_error "cached CC is different -- throw away $cache_file (it is also a good idea to do 'make clean' before compiling)" "$LINENO" 5 fi @@ -3477,8 +3472,8 @@ test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "no acceptable C compiler found in \$PATH -See \`config.log' for more details" "$LINENO" 5 ; } +as_fn_error "no acceptable C compiler found in \$PATH +See \`config.log' for more details." "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 @@ -3592,8 +3587,9 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "C compiler cannot create executables -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "C compiler cannot create executables +See \`config.log' for more details." "$LINENO" 5; }; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } @@ -3635,8 +3631,8 @@ else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of executables: cannot compile and link -See \`config.log' for more details" "$LINENO" 5 ; } +as_fn_error "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 @@ -3693,9 +3689,9 @@ else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot run C compiled programs. +as_fn_error "cannot run C compiled programs. If you meant to cross compile, use \`--host'. -See \`config.log' for more details" "$LINENO" 5 ; } +See \`config.log' for more details." "$LINENO" 5; } fi fi fi @@ -3746,8 +3742,8 @@ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "cannot compute suffix of object files: cannot compile -See \`config.log' for more details" "$LINENO" 5 ; } +as_fn_error "cannot compute suffix of object files: cannot compile +See \`config.log' for more details." "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi @@ -4200,7 +4196,7 @@ # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.i conftest.$ac_ext +rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. @@ -4216,11 +4212,11 @@ ac_preproc_ok=: break fi -rm -f conftest.err conftest.i conftest.$ac_ext +rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext +rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi @@ -4259,7 +4255,7 @@ # Broken: fails on valid input. continue fi -rm -f conftest.err conftest.i conftest.$ac_ext +rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. @@ -4275,18 +4271,18 @@ ac_preproc_ok=: break fi -rm -f conftest.err conftest.i conftest.$ac_ext +rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. -rm -f conftest.i conftest.err conftest.$ac_ext +rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error $? "C preprocessor \"$CPP\" fails sanity check -See \`config.log' for more details" "$LINENO" 5 ; } +as_fn_error "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." "$LINENO" 5; } fi ac_ext=c @@ -4347,7 +4343,7 @@ done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then - as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP @@ -4413,7 +4409,7 @@ done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then - as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP @@ -4545,7 +4541,8 @@ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -5169,22 +5166,16 @@ esac ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do - if test -f "$ac_dir/install-sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install-sh -c" - break - elif test -f "$ac_dir/install.sh"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/install.sh -c" - break - elif test -f "$ac_dir/shtool"; then - ac_aux_dir=$ac_dir - ac_install_sh="$ac_aux_dir/shtool install -c" - break - fi + for ac_t in install-sh install.sh shtool; do + if test -f "$ac_dir/$ac_t"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/$ac_t -c" + break 2 + fi + done done if test -z "$ac_aux_dir"; then - as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 + as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, @@ -5522,7 +5513,7 @@ ARCH_RUN_32BIT="/usr/bin/arch -i386 -ppc" else - as_fn_error $? "proper usage is --with-universal-arch=32-bit|64-bit|all|intel|3-way" "$LINENO" 5 + as_fn_error "proper usage is --with-universal-arch=32-bit|64-bit|all|intel|3-way" "$LINENO" 5 fi @@ -6016,7 +6007,8 @@ do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF @@ -6030,7 +6022,7 @@ as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } -if eval "test \"\${$as_ac_Header+set}\"" = set; then : +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -6057,7 +6049,8 @@ eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } -if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF @@ -6577,8 +6570,9 @@ if test "$ac_cv_type_int" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (int) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (int) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_int=0 fi @@ -6610,8 +6604,9 @@ if test "$ac_cv_type_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (long) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_long=0 fi @@ -6643,8 +6638,9 @@ if test "$ac_cv_type_void_p" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (void *) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (void *) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_void_p=0 fi @@ -6676,8 +6672,9 @@ if test "$ac_cv_type_short" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (short) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (short) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_short=0 fi @@ -6709,8 +6706,9 @@ if test "$ac_cv_type_float" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (float) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (float) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_float=0 fi @@ -6742,8 +6740,9 @@ if test "$ac_cv_type_double" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (double) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (double) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_double=0 fi @@ -6775,8 +6774,9 @@ if test "$ac_cv_type_fpos_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (fpos_t) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (fpos_t) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_fpos_t=0 fi @@ -6808,8 +6808,9 @@ if test "$ac_cv_type_size_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (size_t) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (size_t) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_size_t=0 fi @@ -6841,8 +6842,9 @@ if test "$ac_cv_type_pid_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (pid_t) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (pid_t) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_pid_t=0 fi @@ -6901,8 +6903,9 @@ if test "$ac_cv_type_long_long" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long long) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (long long) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_long_long=0 fi @@ -6962,8 +6965,9 @@ if test "$ac_cv_type_long_double" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (long double) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (long double) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_long_double=0 fi @@ -7024,8 +7028,9 @@ if test "$ac_cv_type__Bool" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (_Bool) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (_Bool) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof__Bool=0 fi @@ -7072,8 +7077,9 @@ if test "$ac_cv_type_uintptr_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (uintptr_t) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (uintptr_t) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_uintptr_t=0 fi @@ -7113,8 +7119,9 @@ if test "$ac_cv_type_off_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (off_t) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (off_t) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_off_t=0 fi @@ -7175,8 +7182,9 @@ if test "$ac_cv_type_time_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (time_t) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (time_t) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_time_t=0 fi @@ -7247,8 +7255,9 @@ if test "$ac_cv_type_pthread_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (pthread_t) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (pthread_t) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_pthread_t=0 fi @@ -7335,7 +7344,7 @@ MACOSX_DEFAULT_ARCH="ppc" ;; *) - as_fn_error $? "Unexpected output of 'arch' on OSX" "$LINENO" 5 + as_fn_error "Unexpected output of 'arch' on OSX" "$LINENO" 5 ;; esac else @@ -7347,7 +7356,7 @@ MACOSX_DEFAULT_ARCH="ppc64" ;; *) - as_fn_error $? "Unexpected output of 'arch' on OSX" "$LINENO" 5 + as_fn_error "Unexpected output of 'arch' on OSX" "$LINENO" 5 ;; esac @@ -7373,7 +7382,7 @@ $as_echo "yes" >&6; } if test $enable_shared = "yes" then - as_fn_error $? "Specifying both --enable-shared and --enable-framework is not supported, use only --enable-framework instead" "$LINENO" 5 + as_fn_error "Specifying both --enable-shared and --enable-framework is not supported, use only --enable-framework instead" "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 @@ -7526,8 +7535,8 @@ esac fi;; NetBSD*|DragonFly*) - LDSHARED="cc -shared" - LDCXXSHARED="c++ -shared";; + LDSHARED="$(CC) -shared" + LDCXXSHARED="$(CXX) -shared";; OpenUNIX*|UnixWare*) if test "$GCC" = "yes" ; then LDSHARED='$(CC) -shared' @@ -8169,12 +8178,12 @@ withval=$with_dbmliborder; if test x$with_dbmliborder = xyes then -as_fn_error $? "proper usage is --with-dbmliborder=db1:db2:..." "$LINENO" 5 +as_fn_error "proper usage is --with-dbmliborder=db1:db2:..." "$LINENO" 5 else for db in `echo $with_dbmliborder | sed 's/:/ /g'`; do if test x$db != xndbm && test x$db != xgdbm && test x$db != xbdb then - as_fn_error $? "proper usage is --with-dbmliborder=db1:db2:..." "$LINENO" 5 + as_fn_error "proper usage is --with-dbmliborder=db1:db2:..." "$LINENO" 5 fi done fi @@ -9173,7 +9182,7 @@ $as_echo "#define WITH_VALGRIND 1" >>confdefs.h else - as_fn_error $? "Valgrind support requested but headers not available" "$LINENO" 5 + as_fn_error "Valgrind support requested but headers not available" "$LINENO" 5 fi @@ -9267,7 +9276,8 @@ do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -10262,7 +10272,8 @@ do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -10271,44 +10282,25 @@ done -ac_fn_c_check_func "$LINENO" "dup2" "ac_cv_func_dup2" -if test "x$ac_cv_func_dup2" = x""yes; then : - $as_echo "#define HAVE_DUP2 1" >>confdefs.h - -else - case " $LIBOBJS " in - *" dup2.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS dup2.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "getcwd" "ac_cv_func_getcwd" -if test "x$ac_cv_func_getcwd" = x""yes; then : - $as_echo "#define HAVE_GETCWD 1" >>confdefs.h - -else - case " $LIBOBJS " in - *" getcwd.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS getcwd.$ac_objext" - ;; -esac - -fi - -ac_fn_c_check_func "$LINENO" "strdup" "ac_cv_func_strdup" -if test "x$ac_cv_func_strdup" = x""yes; then : - $as_echo "#define HAVE_STRDUP 1" >>confdefs.h +for ac_func in dup2 getcwd strdup +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF else case " $LIBOBJS " in - *" strdup.$ac_objext "* ) ;; - *) LIBOBJS="$LIBOBJS strdup.$ac_objext" + *" $ac_func.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" ;; esac fi +done for ac_func in getpgrp @@ -11521,7 +11513,7 @@ then LIBM=$withval { $as_echo "$as_me:${as_lineno-$LINENO}: result: set LIBM=\"$withval\"" >&5 $as_echo "set LIBM=\"$withval\"" >&6; } -else as_fn_error $? "proper usage is --with-libm=STRING" "$LINENO" 5 +else as_fn_error "proper usage is --with-libm=STRING" "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: default LIBM=\"$LIBM\"" >&5 @@ -11545,7 +11537,7 @@ then LIBC=$withval { $as_echo "$as_me:${as_lineno-$LINENO}: result: set LIBC=\"$withval\"" >&5 $as_echo "set LIBC=\"$withval\"" >&6; } -else as_fn_error $? "proper usage is --with-libc=STRING" "$LINENO" 5 +else as_fn_error "proper usage is --with-libc=STRING" "$LINENO" 5 fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: default LIBC=\"$LIBC\"" >&5 @@ -11795,7 +11787,8 @@ do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -11807,7 +11800,8 @@ do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" -if eval test \"x\$"$as_ac_var"\" = x"yes"; then : +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 _ACEOF @@ -12070,7 +12064,7 @@ 15|30) ;; *) - as_fn_error $? "bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30" "$LINENO" 5 ;; + as_fn_error "bad value $enable_big_digits for --enable-big-digits; value should be 15 or 30" "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_big_digits" >&5 $as_echo "$enable_big_digits" >&6; } @@ -12121,8 +12115,9 @@ if test "$ac_cv_type_wchar_t" = yes; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} -as_fn_error 77 "cannot compute sizeof (wchar_t) -See \`config.log' for more details" "$LINENO" 5 ; } +{ as_fn_set_status 77 +as_fn_error "cannot compute sizeof (wchar_t) +See \`config.log' for more details." "$LINENO" 5; }; } else ac_cv_sizeof_wchar_t=0 fi @@ -12491,8 +12486,8 @@ ;; #( *) - as_fn_error $? "unknown endianness - presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + as_fn_error "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; esac @@ -12753,7 +12748,7 @@ have_readline=no fi -rm -f conftest.err conftest.i conftest.$ac_ext +rm -f conftest.err conftest.$ac_ext if test $have_readline = yes then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -12927,7 +12922,7 @@ have_readline=no fi -rm -f conftest.err conftest.i conftest.$ac_ext +rm -f conftest.err conftest.$ac_ext if test $have_readline = yes then cat confdefs.h - <<_ACEOF >conftest.$ac_ext @@ -13743,7 +13738,7 @@ case $ac_sys_system in - OSF*) as_fn_error $? "OSF* systems are deprecated unless somebody volunteers. Check http://bugs.python.org/issue8606" "$LINENO" 5 ;; + OSF*) as_fn_error "OSF* systems are deprecated unless somebody volunteers. Check http://bugs.python.org/issue8606" "$LINENO" 5 ;; esac ac_fn_c_check_func "$LINENO" "pipe2" "ac_cv_func_pipe2" @@ -13861,7 +13856,6 @@ ac_libobjs= ac_ltlibobjs= -U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' @@ -14024,19 +14018,19 @@ (unset CDPATH) >/dev/null 2>&1 && unset CDPATH -# as_fn_error STATUS ERROR [LINENO LOG_FD] -# ---------------------------------------- +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the -# script with STATUS, using 1 if that was 0. +# script with status $?, using 1 if that was 0. as_fn_error () { - as_status=$1; test $as_status -eq 0 && as_status=1 - if test "$4"; then - as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack - $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 fi - $as_echo "$as_me: error: $2" >&2 + $as_echo "$as_me: error: $1" >&2 as_fn_exit $as_status } # as_fn_error @@ -14232,7 +14226,7 @@ test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" - } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" } # as_fn_mkdir_p @@ -14286,7 +14280,7 @@ # values after options handling. ac_log=" This file was extended by python $as_me 3.2, which was -generated by GNU Autoconf 2.67. Invocation command line was +generated by GNU Autoconf 2.65. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -14310,8 +14304,8 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" +config_files="`echo $ac_config_files`" +config_headers="`echo $ac_config_headers`" _ACEOF @@ -14348,10 +14342,10 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ python config.status 3.2 -configured by $0, generated by GNU Autoconf 2.67, +configured by $0, generated by GNU Autoconf 2.65, with options \\"\$ac_cs_config\\" -Copyright (C) 2010 Free Software Foundation, Inc. +Copyright (C) 2009 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -14367,16 +14361,11 @@ while test $# != 0 do case $1 in - --*=?*) + --*=*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; - --*=) - ac_option=`expr "X$1" : 'X\([^=]*\)='` - ac_optarg= - ac_shift=: - ;; *) ac_option=$1 ac_optarg=$2 @@ -14398,7 +14387,6 @@ $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; - '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; @@ -14411,7 +14399,7 @@ ac_need_defaults=false;; --he | --h) # Conflict between --help and --header - as_fn_error $? "ambiguous option: \`$1' + as_fn_error "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; @@ -14420,7 +14408,7 @@ ac_cs_silent=: ;; # This is an error. - -*) as_fn_error $? "unrecognized option: \`$1' + -*) as_fn_error "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" @@ -14479,7 +14467,7 @@ "Misc/python.pc") CONFIG_FILES="$CONFIG_FILES Misc/python.pc" ;; "Modules/ld_so_aix") CONFIG_FILES="$CONFIG_FILES Modules/ld_so_aix" ;; - *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5 ;; + *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done @@ -14516,7 +14504,7 @@ { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") -} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 +} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. @@ -14533,7 +14521,7 @@ fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then - ac_cs_awk_cr='\\r' + ac_cs_awk_cr='\r' else ac_cs_awk_cr=$ac_cr fi @@ -14547,18 +14535,18 @@ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 -ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi @@ -14647,28 +14635,20 @@ else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ - || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 + || as_fn_error "could not setup config files machinery" "$LINENO" 5 _ACEOF -# VPATH may cause trouble with some makes, so we remove sole $(srcdir), -# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then - ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ -h -s/// -s/^/:/ -s/[ ]*$/:/ -s/:\$(srcdir):/:/g -s/:\${srcdir}:/:/g -s/:@srcdir@:/:/g -s/^:*// + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ s/:*$// -x -s/\(=[ ]*\).*/\1/ -G -s/\n// s/^[^=]*=[ ]*$// }' fi @@ -14696,7 +14676,7 @@ if test -z "$ac_t"; then break elif $ac_last_try; then - as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 + as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi @@ -14781,7 +14761,7 @@ _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 - as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 + as_fn_error "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" @@ -14794,7 +14774,7 @@ esac case $ac_mode$ac_tag in :[FHL]*:*);; - :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5 ;; + :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac @@ -14822,7 +14802,7 @@ [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || - as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5 ;; + as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" @@ -14849,7 +14829,7 @@ case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac @@ -14980,22 +14960,22 @@ $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + || as_fn_error "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&5 +which seems to be undefined. Please make sure it is defined." >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' -which seems to be undefined. Please make sure it is defined" >&2;} +which seems to be undefined. Please make sure it is defined." >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; :H) # @@ -15006,19 +14986,19 @@ $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" } >"$tmp/config.h" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + || as_fn_error "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$tmp/config.h" "$ac_file" \ - || as_fn_error $? "could not create $ac_file" "$LINENO" 5 + || as_fn_error "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ - || as_fn_error $? "could not create -" "$LINENO" 5 + || as_fn_error "could not create -" "$LINENO" 5 fi ;; @@ -15038,7 +15018,7 @@ ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || - as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 + as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. @@ -15059,7 +15039,7 @@ exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. - $ac_cs_success || as_fn_exit 1 + $ac_cs_success || as_fn_exit $? fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 Modified: python/branches/py3k/configure.in ============================================================================== --- python/branches/py3k/configure.in (original) +++ python/branches/py3k/configure.in Sun Jan 2 20:34:03 2011 @@ -1750,8 +1750,8 @@ esac fi;; NetBSD*|DragonFly*) - LDSHARED="cc -shared" - LDCXXSHARED="c++ -shared";; + LDSHARED="$(CC) -shared" + LDCXXSHARED="$(CXX) -shared";; OpenUNIX*|UnixWare*) if test "$GCC" = "yes" ; then LDSHARED='$(CC) -shared' From python-checkins at python.org Sun Jan 2 20:37:46 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 20:37:46 +0100 (CET) Subject: [Python-checkins] r87640 - in python/branches/release27-maint: Misc/ACKS Misc/NEWS configure configure.in Message-ID: <20110102193746.19FDEEE986@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 20:37:45 2011 New Revision: 87640 Log: Merged revisions 87639 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87639 | antoine.pitrou | 2011-01-02 20:34:03 +0100 (dim., 02 janv. 2011) | 4 lines Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD and DragonFly BSD. Patch by Nicolas Joly. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Misc/ACKS python/branches/release27-maint/Misc/NEWS python/branches/release27-maint/configure python/branches/release27-maint/configure.in Modified: python/branches/release27-maint/Misc/ACKS ============================================================================== --- python/branches/release27-maint/Misc/ACKS (original) +++ python/branches/release27-maint/Misc/ACKS Sun Jan 2 20:37:45 2011 @@ -397,6 +397,7 @@ Fredrik Johansson Gregory K. Johnson Simon Johnston +Nicolas Joly Evan Jones Jeremy Jones Richard Jones Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Sun Jan 2 20:37:45 2011 @@ -92,6 +92,12 @@ - Issue #678250: Make mmap flush a noop on ACCESS_READ and ACCESS_COPY. +Build +----- + +- Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD + and DragonFly BSD. Patch by Nicolas Joly. + Tests ----- Modified: python/branches/release27-maint/configure ============================================================================== --- python/branches/release27-maint/configure (original) +++ python/branches/release27-maint/configure Sun Jan 2 20:37:45 2011 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 86076 . +# From configure.in Revision: 86848 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65 for python 2.7. # @@ -1934,11 +1934,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default - enum { N = $2 / 2 - 1 }; int main () { -static int test_array [1 - 2 * !(0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; +static int test_array [1 - 2 * !(enum { N = $2 / 2 - 1 }; + 0 < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1))]; test_array [0] = 0 ; @@ -1949,11 +1949,11 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $ac_includes_default - enum { N = $2 / 2 - 1 }; int main () { -static int test_array [1 - 2 * !(($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) +static int test_array [1 - 2 * !(enum { N = $2 / 2 - 1 }; + ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 1) < ($ac_type) ((((($ac_type) 1 << N) << N) - 1) * 2 + 2))]; test_array [0] = 0 @@ -7649,8 +7649,8 @@ esac fi;; NetBSD*|DragonFly*) - LDSHARED="cc -shared" - LDCXXSHARED="c++ -shared";; + LDSHARED="$(CC) -shared" + LDCXXSHARED="$(CXX) -shared";; OpenUNIX*|UnixWare*) if test "$GCC" = "yes" ; then LDSHARED='$(CC) -shared' @@ -14309,8 +14309,8 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" +config_files="`echo $ac_config_files`" +config_headers="`echo $ac_config_headers`" _ACEOF Modified: python/branches/release27-maint/configure.in ============================================================================== --- python/branches/release27-maint/configure.in (original) +++ python/branches/release27-maint/configure.in Sun Jan 2 20:37:45 2011 @@ -1875,8 +1875,8 @@ esac fi;; NetBSD*|DragonFly*) - LDSHARED="cc -shared" - LDCXXSHARED="c++ -shared";; + LDSHARED="$(CC) -shared" + LDCXXSHARED="$(CXX) -shared";; OpenUNIX*|UnixWare*) if test "$GCC" = "yes" ; then LDSHARED='$(CC) -shared' From python-checkins at python.org Sun Jan 2 20:38:30 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 20:38:30 +0100 (CET) Subject: [Python-checkins] r87641 - in python/branches/release31-maint: Misc/ACKS Misc/NEWS configure configure.in Message-ID: <20110102193830.88C31EE986@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 20:38:30 2011 New Revision: 87641 Log: Merged revisions 87639 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87639 | antoine.pitrou | 2011-01-02 20:34:03 +0100 (dim., 02 janv. 2011) | 4 lines Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD and DragonFly BSD. Patch by Nicolas Joly. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Misc/ACKS python/branches/release31-maint/Misc/NEWS python/branches/release31-maint/configure python/branches/release31-maint/configure.in Modified: python/branches/release31-maint/Misc/ACKS ============================================================================== --- python/branches/release31-maint/Misc/ACKS (original) +++ python/branches/release31-maint/Misc/ACKS Sun Jan 2 20:38:30 2011 @@ -393,6 +393,7 @@ Gregory K. Johnson Simon Johnston Thomas Jollans +Nicolas Joly Evan Jones Jeremy Jones Richard Jones Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Sun Jan 2 20:38:30 2011 @@ -86,6 +86,12 @@ - Issue #678250: Make mmap flush a noop on ACCESS_READ and ACCESS_COPY. +Build +----- + +- Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD + and DragonFly BSD. Patch by Nicolas Joly. + Tests ----- Modified: python/branches/release31-maint/configure ============================================================================== --- python/branches/release31-maint/configure (original) +++ python/branches/release31-maint/configure Sun Jan 2 20:38:30 2011 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 86044 . +# From configure.in Revision: 86752 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65 for python 3.1. # @@ -757,8 +757,7 @@ LDFLAGS LIBS CPPFLAGS -CPP -CPPFLAGS' +CPP' # Initialize some variables set by options. @@ -7564,7 +7563,7 @@ ;; esac fi;; - NetBSD*|DragonFly*) LDSHARED="cc -shared ${LDFLAGS}";; + NetBSD*|DragonFly*) LDSHARED="$(CC) -shared ${LDFLAGS}";; OpenUNIX*|UnixWare*) if test "$GCC" = "yes" then LDSHARED='$(CC) -shared' @@ -13923,8 +13922,8 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. -config_files="$ac_config_files" -config_headers="$ac_config_headers" +config_files="`echo $ac_config_files`" +config_headers="`echo $ac_config_headers`" _ACEOF Modified: python/branches/release31-maint/configure.in ============================================================================== --- python/branches/release31-maint/configure.in (original) +++ python/branches/release31-maint/configure.in Sun Jan 2 20:38:30 2011 @@ -1814,7 +1814,7 @@ ;; esac fi;; - NetBSD*|DragonFly*) LDSHARED="cc -shared ${LDFLAGS}";; + NetBSD*|DragonFly*) LDSHARED="$(CC) -shared ${LDFLAGS}";; OpenUNIX*|UnixWare*) if test "$GCC" = "yes" then LDSHARED='$(CC) -shared' From python-checkins at python.org Sun Jan 2 20:50:36 2011 From: python-checkins at python.org (victor.stinner) Date: Sun, 2 Jan 2011 20:50:36 +0100 (CET) Subject: [Python-checkins] r87642 - in python/branches/py3k: Lib/encodings/aliases.py Misc/NEWS Message-ID: <20110102195036.471BBEE986@mail.python.org> Author: victor.stinner Date: Sun Jan 2 20:50:36 2011 New Revision: 87642 Log: Issue #10807: Remove base64, bz2, hex, quopri, rot13, uu and zlib codecs from the codec aliases. They are still accessible via codecs.lookup(). Modified: python/branches/py3k/Lib/encodings/aliases.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/encodings/aliases.py ============================================================================== --- python/branches/py3k/Lib/encodings/aliases.py (original) +++ python/branches/py3k/Lib/encodings/aliases.py Sun Jan 2 20:50:36 2011 @@ -33,9 +33,9 @@ 'us' : 'ascii', 'us_ascii' : 'ascii', - # base64_codec codec - 'base64' : 'base64_codec', - 'base_64' : 'base64_codec', + ## base64_codec codec + #'base64' : 'base64_codec', + #'base_64' : 'base64_codec', # big5 codec 'big5_tw' : 'big5', @@ -45,8 +45,8 @@ 'big5_hkscs' : 'big5hkscs', 'hkscs' : 'big5hkscs', - # bz2_codec codec - 'bz2' : 'bz2_codec', + ## bz2_codec codec + #'bz2' : 'bz2_codec', # cp037 codec '037' : 'cp037', @@ -248,8 +248,8 @@ 'cp936' : 'gbk', 'ms936' : 'gbk', - # hex_codec codec - 'hex' : 'hex_codec', + ## hex_codec codec + #'hex' : 'hex_codec', # hp_roman8 codec 'roman8' : 'hp_roman8', @@ -450,13 +450,13 @@ 'cp154' : 'ptcp154', 'cyrillic_asian' : 'ptcp154', - # quopri_codec codec - 'quopri' : 'quopri_codec', - 'quoted_printable' : 'quopri_codec', - 'quotedprintable' : 'quopri_codec', + ## quopri_codec codec + #'quopri' : 'quopri_codec', + #'quoted_printable' : 'quopri_codec', + #'quotedprintable' : 'quopri_codec', - # rot_13 codec - 'rot13' : 'rot_13', + ## rot_13 codec + #'rot13' : 'rot_13', # shift_jis codec 'csshiftjis' : 'shift_jis', @@ -518,12 +518,12 @@ 'utf8_ucs2' : 'utf_8', 'utf8_ucs4' : 'utf_8', - # uu_codec codec - 'uu' : 'uu_codec', + ## uu_codec codec + #'uu' : 'uu_codec', - # zlib_codec codec - 'zip' : 'zlib_codec', - 'zlib' : 'zlib_codec', + ## zlib_codec codec + #'zip' : 'zlib_codec', + #'zlib' : 'zlib_codec', # temporary mac CJK aliases, will be replaced by proper codecs in 3.1 'x_mac_japanese' : 'shift_jis', Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sun Jan 2 20:50:36 2011 @@ -20,6 +20,9 @@ Library ------- +- Issue #10807: Remove base64, bz2, hex, quopri, rot13, uu and zlib codecs from + the codec aliases. They are still accessible via codecs.lookup(). + - Issue #10801: In zipfile, support different encodings for the header and the filenames. From python-checkins at python.org Sun Jan 2 21:04:52 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 21:04:52 +0100 (CET) Subject: [Python-checkins] r87643 - in python/branches/release27-maint: Lib/test/test_os.py Lib/test/test_posix.py Misc/NEWS Modules/posixmodule.c Message-ID: <20110102200452.BDB93EE986@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 21:04:52 2011 New Revision: 87643 Log: Issue #4662: os.tempnam(), os.tmpfile() and os.tmpnam() now raise a py3k DeprecationWarning. Modified: python/branches/release27-maint/Lib/test/test_os.py python/branches/release27-maint/Lib/test/test_posix.py python/branches/release27-maint/Misc/NEWS python/branches/release27-maint/Modules/posixmodule.c Modified: python/branches/release27-maint/Lib/test/test_os.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_os.py (original) +++ python/branches/release27-maint/Lib/test/test_os.py Sun Jan 2 21:04:52 2011 @@ -80,16 +80,18 @@ def test_tempnam(self): if not hasattr(os, "tempnam"): return - warnings.filterwarnings("ignore", "tempnam", RuntimeWarning, - r"test_os$") - self.check_tempfile(os.tempnam()) - - name = os.tempnam(test_support.TESTFN) - self.check_tempfile(name) - - name = os.tempnam(test_support.TESTFN, "pfx") - self.assertTrue(os.path.basename(name)[:3] == "pfx") - self.check_tempfile(name) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "tempnam", RuntimeWarning, + r"test_os$") + warnings.filterwarnings("ignore", "tempnam", DeprecationWarning) + self.check_tempfile(os.tempnam()) + + name = os.tempnam(test_support.TESTFN) + self.check_tempfile(name) + + name = os.tempnam(test_support.TESTFN, "pfx") + self.assertTrue(os.path.basename(name)[:3] == "pfx") + self.check_tempfile(name) def test_tmpfile(self): if not hasattr(os, "tmpfile"): @@ -108,63 +110,69 @@ # test that a subsequent call to os.tmpfile() raises the same error. If # it doesn't, assume we're on XP or below and the user running the test # has administrative privileges, and proceed with the test as normal. - if sys.platform == 'win32': - name = '\\python_test_os_test_tmpfile.txt' - if os.path.exists(name): - os.remove(name) - try: - fp = open(name, 'w') - except IOError, first: - # open() failed, assert tmpfile() fails in the same way. - # Although open() raises an IOError and os.tmpfile() raises an - # OSError(), 'args' will be (13, 'Permission denied') in both - # cases. + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "tmpfile", DeprecationWarning) + + if sys.platform == 'win32': + name = '\\python_test_os_test_tmpfile.txt' + if os.path.exists(name): + os.remove(name) try: - fp = os.tmpfile() - except OSError, second: - self.assertEqual(first.args, second.args) + fp = open(name, 'w') + except IOError, first: + # open() failed, assert tmpfile() fails in the same way. + # Although open() raises an IOError and os.tmpfile() raises an + # OSError(), 'args' will be (13, 'Permission denied') in both + # cases. + try: + fp = os.tmpfile() + except OSError, second: + self.assertEqual(first.args, second.args) + else: + self.fail("expected os.tmpfile() to raise OSError") + return else: - self.fail("expected os.tmpfile() to raise OSError") - return - else: - # open() worked, therefore, tmpfile() should work. Close our - # dummy file and proceed with the test as normal. - fp.close() - os.remove(name) - - fp = os.tmpfile() - fp.write("foobar") - fp.seek(0,0) - s = fp.read() - fp.close() - self.assertTrue(s == "foobar") + # open() worked, therefore, tmpfile() should work. Close our + # dummy file and proceed with the test as normal. + fp.close() + os.remove(name) + + fp = os.tmpfile() + fp.write("foobar") + fp.seek(0,0) + s = fp.read() + fp.close() + self.assertTrue(s == "foobar") def test_tmpnam(self): if not hasattr(os, "tmpnam"): return - warnings.filterwarnings("ignore", "tmpnam", RuntimeWarning, - r"test_os$") - name = os.tmpnam() - if sys.platform in ("win32",): - # The Windows tmpnam() seems useless. From the MS docs: - # - # The character string that tmpnam creates consists of - # the path prefix, defined by the entry P_tmpdir in the - # file STDIO.H, followed by a sequence consisting of the - # digit characters '0' through '9'; the numerical value - # of this string is in the range 1 - 65,535. Changing the - # definitions of L_tmpnam or P_tmpdir in STDIO.H does not - # change the operation of tmpnam. - # - # The really bizarre part is that, at least under MSVC6, - # P_tmpdir is "\\". That is, the path returned refers to - # the root of the current drive. That's a terrible place to - # put temp files, and, depending on privileges, the user - # may not even be able to open a file in the root directory. - self.assertFalse(os.path.exists(name), - "file already exists for temporary file") - else: - self.check_tempfile(name) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "tmpnam", RuntimeWarning, + r"test_os$") + warnings.filterwarnings("ignore", "tmpnam", DeprecationWarning) + + name = os.tmpnam() + if sys.platform in ("win32",): + # The Windows tmpnam() seems useless. From the MS docs: + # + # The character string that tmpnam creates consists of + # the path prefix, defined by the entry P_tmpdir in the + # file STDIO.H, followed by a sequence consisting of the + # digit characters '0' through '9'; the numerical value + # of this string is in the range 1 - 65,535. Changing the + # definitions of L_tmpnam or P_tmpdir in STDIO.H does not + # change the operation of tmpnam. + # + # The really bizarre part is that, at least under MSVC6, + # P_tmpdir is "\\". That is, the path returned refers to + # the root of the current drive. That's a terrible place to + # put temp files, and, depending on privileges, the user + # may not even be able to open a file in the root directory. + self.assertFalse(os.path.exists(name), + "file already exists for temporary file") + else: + self.check_tempfile(name) # Test attributes on return values from os.*stat* family. class StatAttributeTests(unittest.TestCase): Modified: python/branches/release27-maint/Lib/test/test_posix.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_posix.py (original) +++ python/branches/release27-maint/Lib/test/test_posix.py Sun Jan 2 21:04:52 2011 @@ -38,11 +38,13 @@ "getpid", "getpgrp", "getppid", "getuid", ] - for name in NO_ARG_FUNCTIONS: - posix_func = getattr(posix, name, None) - if posix_func is not None: - posix_func() - self.assertRaises(TypeError, posix_func, 1) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "", DeprecationWarning) + for name in NO_ARG_FUNCTIONS: + posix_func = getattr(posix, name, None) + if posix_func is not None: + posix_func() + self.assertRaises(TypeError, posix_func, 1) if hasattr(posix, 'getresuid'): def test_getresuid(self): @@ -290,14 +292,18 @@ def test_tempnam(self): if hasattr(posix, 'tempnam'): - self.assertTrue(posix.tempnam()) - self.assertTrue(posix.tempnam(os.curdir)) - self.assertTrue(posix.tempnam(os.curdir, 'blah')) + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "tempnam", DeprecationWarning) + self.assertTrue(posix.tempnam()) + self.assertTrue(posix.tempnam(os.curdir)) + self.assertTrue(posix.tempnam(os.curdir, 'blah')) def test_tmpfile(self): if hasattr(posix, 'tmpfile'): - fp = posix.tmpfile() - fp.close() + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "tmpfile", DeprecationWarning) + fp = posix.tmpfile() + fp.close() def test_utime(self): if hasattr(posix, 'utime'): Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Sun Jan 2 21:04:52 2011 @@ -22,6 +22,9 @@ Library ------- +- Issue #4662: os.tempnam(), os.tmpfile() and os.tmpnam() now raise a py3k + DeprecationWarning. + - Subclasses of collections.OrderedDict now work correctly with __missing__. - Issue 10753 - Characters ';','=' and ',' in the PATH_INFO environment Modified: python/branches/release27-maint/Modules/posixmodule.c ============================================================================== --- python/branches/release27-maint/Modules/posixmodule.c (original) +++ python/branches/release27-maint/Modules/posixmodule.c Sun Jan 2 21:04:52 2011 @@ -7295,6 +7295,10 @@ "tempnam is a potential security risk to your program") < 0) return NULL; + if (PyErr_WarnPy3k("tempnam has been removed in 3.x; " + "use the tempfile module", 1) < 0) + return NULL; + #ifdef MS_WINDOWS name = _tempnam(dir, pfx); #else @@ -7319,6 +7323,10 @@ { FILE *fp; + if (PyErr_WarnPy3k("tmpfile has been removed in 3.x; " + "use the tempfile module", 1) < 0) + return NULL; + fp = tmpfile(); if (fp == NULL) return posix_error(); @@ -7342,6 +7350,10 @@ "tmpnam is a potential security risk to your program") < 0) return NULL; + if (PyErr_WarnPy3k("tmpnam has been removed in 3.x; " + "use the tempfile module", 1) < 0) + return NULL; + #ifdef USE_TMPNAM_R name = tmpnam_r(buffer); #else From python-checkins at python.org Sun Jan 2 21:05:11 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 21:05:11 +0100 (CET) Subject: [Python-checkins] r87644 - python/branches/release27-maint/Misc/NEWS Message-ID: <20110102200511.BEA29EE986@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 21:05:11 2011 New Revision: 87644 Log: Typo Modified: python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Sun Jan 2 21:05:11 2011 @@ -1227,7 +1227,7 @@ with a non-empty format string. This is an effort to future-proof user code. If a derived class does not currently implement __format__ but later adds its own __format__, it would most likely break user code that had - supplied a format string. This will be changed to a DeprecationWaring in + supplied a format string. This will be changed to a DeprecationWarning in Python 3.3 and it will be an error in Python 3.4. - Issue #8268: Old-style classes (not just instances) now support weak From python-checkins at python.org Sun Jan 2 21:06:13 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 21:06:13 +0100 (CET) Subject: [Python-checkins] r87645 - python/branches/release27-maint/Modules/posixmodule.c Message-ID: <20110102200613.147ECEE986@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 21:06:12 2011 New Revision: 87645 Log: Fix indentation Modified: python/branches/release27-maint/Modules/posixmodule.c Modified: python/branches/release27-maint/Modules/posixmodule.c ============================================================================== --- python/branches/release27-maint/Modules/posixmodule.c (original) +++ python/branches/release27-maint/Modules/posixmodule.c Sun Jan 2 21:06:12 2011 @@ -7305,7 +7305,7 @@ name = tempnam(dir, pfx); #endif if (name == NULL) - return PyErr_NoMemory(); + return PyErr_NoMemory(); result = PyString_FromString(name); free(name); return result; @@ -7329,7 +7329,7 @@ fp = tmpfile(); if (fp == NULL) - return posix_error(); + return posix_error(); return PyFile_FromFile(fp, "", "w+b", fclose); } #endif @@ -7360,16 +7360,16 @@ name = tmpnam(buffer); #endif if (name == NULL) { - PyObject *err = Py_BuildValue("is", 0, + PyObject *err = Py_BuildValue("is", 0, #ifdef USE_TMPNAM_R - "unexpected NULL from tmpnam_r" + "unexpected NULL from tmpnam_r" #else - "unexpected NULL from tmpnam" + "unexpected NULL from tmpnam" #endif - ); - PyErr_SetObject(PyExc_OSError, err); - Py_XDECREF(err); - return NULL; + ); + PyErr_SetObject(PyExc_OSError, err); + Py_XDECREF(err); + return NULL; } return PyString_FromString(buffer); } From python-checkins at python.org Sun Jan 2 21:45:22 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 21:45:22 +0100 (CET) Subject: [Python-checkins] r87646 - in python/branches/py3k: configure configure.in Message-ID: <20110102204522.27A45EE9DD@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 21:45:21 2011 New Revision: 87646 Log: Fix bad quoting in r87639. Caught by Arfrever. Modified: python/branches/py3k/configure python/branches/py3k/configure.in Modified: python/branches/py3k/configure ============================================================================== --- python/branches/py3k/configure (original) +++ python/branches/py3k/configure Sun Jan 2 21:45:21 2011 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 87577 . +# From configure.in Revision: 87639 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65 for python 3.2. # @@ -7535,8 +7535,8 @@ esac fi;; NetBSD*|DragonFly*) - LDSHARED="$(CC) -shared" - LDCXXSHARED="$(CXX) -shared";; + LDSHARED='$(CC) -shared' + LDCXXSHARED='$(CXX) -shared';; OpenUNIX*|UnixWare*) if test "$GCC" = "yes" ; then LDSHARED='$(CC) -shared' Modified: python/branches/py3k/configure.in ============================================================================== --- python/branches/py3k/configure.in (original) +++ python/branches/py3k/configure.in Sun Jan 2 21:45:21 2011 @@ -1750,8 +1750,8 @@ esac fi;; NetBSD*|DragonFly*) - LDSHARED="$(CC) -shared" - LDCXXSHARED="$(CXX) -shared";; + LDSHARED='$(CC) -shared' + LDCXXSHARED='$(CXX) -shared';; OpenUNIX*|UnixWare*) if test "$GCC" = "yes" ; then LDSHARED='$(CC) -shared' From python-checkins at python.org Sun Jan 2 21:46:43 2011 From: python-checkins at python.org (stefan.krah) Date: Sun, 2 Jan 2011 21:46:43 +0100 (CET) Subject: [Python-checkins] r87647 - python/branches/py3k-cdecimal/Lib/test/decimal_tests.py Message-ID: <20110102204643.639B6EE9CF@mail.python.org> Author: stefan.krah Date: Sun Jan 2 21:46:43 2011 New Revision: 87647 Log: Fix deprecation warning. Modified: python/branches/py3k-cdecimal/Lib/test/decimal_tests.py Modified: python/branches/py3k-cdecimal/Lib/test/decimal_tests.py ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/decimal_tests.py (original) +++ python/branches/py3k-cdecimal/Lib/test/decimal_tests.py Sun Jan 2 21:46:43 2011 @@ -488,7 +488,7 @@ if id in cdecimal_result_diff: # XXX t = cdecimal_result_diff[id] - self.assert_(result == t[0] and ans == t[1]) + self.assertTrue(result == t[0] and ans == t[1]) else: self.assertEqual(result, ans, 'Incorrect answer for ' + s + ' -- got ' + result) From python-checkins at python.org Sun Jan 2 21:48:22 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Sun, 2 Jan 2011 21:48:22 +0100 (CET) Subject: [Python-checkins] r87648 - in python/branches/py3k: Lib/test/test_time.py Modules/timemodule.c Message-ID: <20110102204822.6D728F0BA@mail.python.org> Author: alexander.belopolsky Date: Sun Jan 2 21:48:22 2011 New Revision: 87648 Log: Issue #8013: Fixed time.asctime segfault when OS's asctime fails Modified: python/branches/py3k/Lib/test/test_time.py python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Sun Jan 2 21:48:22 2011 @@ -122,6 +122,9 @@ def test_asctime(self): time.asctime(time.gmtime(self.t)) self.assertRaises(TypeError, time.asctime, 0) + self.assertRaises(TypeError, time.asctime, ()) + self.assertRaises(ValueError, time.asctime, + (12345, 1, 0, 0, 0, 0, 0, 0, 0)) def test_asctime_bounding_check(self): self._bounds_checking(time.asctime) Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Sun Jan 2 21:48:22 2011 @@ -620,6 +620,10 @@ } else if (!gettmarg(tup, &buf) || !checktm(&buf)) return NULL; p = asctime(&buf); + if (p == NULL) { + PyErr_SetString(PyExc_ValueError, "invalid time"); + return NULL; + } if (p[24] == '\n') p[24] = '\0'; return PyUnicode_FromString(p); From python-checkins at python.org Sun Jan 2 21:51:34 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 21:51:34 +0100 (CET) Subject: [Python-checkins] r87650 - in python/branches/release27-maint: configure configure.in Message-ID: <20110102205134.EB9D7EE98C@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 21:51:34 2011 New Revision: 87650 Log: Merged revisions 87646 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87646 | antoine.pitrou | 2011-01-02 21:45:21 +0100 (dim., 02 janv. 2011) | 3 lines Fix bad quoting in r87639. Caught by Arfrever. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/configure python/branches/release27-maint/configure.in Modified: python/branches/release27-maint/configure ============================================================================== --- python/branches/release27-maint/configure (original) +++ python/branches/release27-maint/configure Sun Jan 2 21:51:34 2011 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 86848 . +# From configure.in Revision: 87640 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65 for python 2.7. # @@ -7649,8 +7649,8 @@ esac fi;; NetBSD*|DragonFly*) - LDSHARED="$(CC) -shared" - LDCXXSHARED="$(CXX) -shared";; + LDSHARED='$(CC) -shared' + LDCXXSHARED='$(CXX) -shared';; OpenUNIX*|UnixWare*) if test "$GCC" = "yes" ; then LDSHARED='$(CC) -shared' Modified: python/branches/release27-maint/configure.in ============================================================================== --- python/branches/release27-maint/configure.in (original) +++ python/branches/release27-maint/configure.in Sun Jan 2 21:51:34 2011 @@ -1875,8 +1875,8 @@ esac fi;; NetBSD*|DragonFly*) - LDSHARED="$(CC) -shared" - LDCXXSHARED="$(CXX) -shared";; + LDSHARED='$(CC) -shared' + LDCXXSHARED='$(CXX) -shared';; OpenUNIX*|UnixWare*) if test "$GCC" = "yes" ; then LDSHARED='$(CC) -shared' From python-checkins at python.org Sun Jan 2 21:52:48 2011 From: python-checkins at python.org (gregory.p.smith) Date: Sun, 2 Jan 2011 21:52:48 +0100 (CET) Subject: [Python-checkins] r87651 - python/branches/py3k/Modules/_posixsubprocess.c Message-ID: <20110102205248.DB072EE98C@mail.python.org> Author: gregory.p.smith Date: Sun Jan 2 21:52:48 2011 New Revision: 87651 Log: issue10802: fallback to pipe+fcntl when the pipe2 syscall fails with errno ENOSYS. Modified: python/branches/py3k/Modules/_posixsubprocess.c Modified: python/branches/py3k/Modules/_posixsubprocess.c ============================================================================== --- python/branches/py3k/Modules/_posixsubprocess.c (original) +++ python/branches/py3k/Modules/_posixsubprocess.c Sun Jan 2 21:52:48 2011 @@ -415,27 +415,39 @@ Py_BEGIN_ALLOW_THREADS res = pipe2(fds, O_CLOEXEC); Py_END_ALLOW_THREADS -#else - /* We hold the GIL which offers some protection from other code calling - * fork() before the CLOEXEC flags have been set but we can't guarantee - * anything without pipe2(). */ - long oldflags; - - res = pipe(fds); - - if (res == 0) { - oldflags = fcntl(fds[0], F_GETFD, 0); - if (oldflags < 0) res = oldflags; - } - if (res == 0) - res = fcntl(fds[0], F_SETFD, oldflags | FD_CLOEXEC); - - if (res == 0) { - oldflags = fcntl(fds[1], F_GETFD, 0); - if (oldflags < 0) res = oldflags; + if (res != 0 && errno == ENOSYS) + { + if (PyErr_WarnEx( + PyExc_RuntimeWarning, + "pipe2 set errno ENOSYS; falling " + "back to non-atomic pipe+fcntl.", 1) != 0) { + return NULL; + } + { +#endif + /* We hold the GIL which offers some protection from other code calling + * fork() before the CLOEXEC flags have been set but we can't guarantee + * anything without pipe2(). */ + long oldflags; + + res = pipe(fds); + + if (res == 0) { + oldflags = fcntl(fds[0], F_GETFD, 0); + if (oldflags < 0) res = oldflags; + } + if (res == 0) + res = fcntl(fds[0], F_SETFD, oldflags | FD_CLOEXEC); + + if (res == 0) { + oldflags = fcntl(fds[1], F_GETFD, 0); + if (oldflags < 0) res = oldflags; + } + if (res == 0) + res = fcntl(fds[1], F_SETFD, oldflags | FD_CLOEXEC); +#ifdef HAVE_PIPE2 + } } - if (res == 0) - res = fcntl(fds[1], F_SETFD, oldflags | FD_CLOEXEC); #endif if (res != 0) return PyErr_SetFromErrno(PyExc_OSError); From python-checkins at python.org Sun Jan 2 22:43:19 2011 From: python-checkins at python.org (brian.quinlan) Date: Sun, 2 Jan 2011 22:43:19 +0100 (CET) Subject: [Python-checkins] r87652 - python/branches/py3k-futures-on-windows/Lib/test/test_concurrent_futures.py Message-ID: <20110102214319.71A7EEE99E@mail.python.org> Author: brian.quinlan Date: Sun Jan 2 22:43:19 2011 New Revision: 87652 Log: Remove 'Call' abstraction that uses Events/Semaphores to force particular execution order. Modified: python/branches/py3k-futures-on-windows/Lib/test/test_concurrent_futures.py Modified: python/branches/py3k-futures-on-windows/Lib/test/test_concurrent_futures.py ============================================================================== --- python/branches/py3k-futures-on-windows/Lib/test/test_concurrent_futures.py (original) +++ python/branches/py3k-futures-on-windows/Lib/test/test_concurrent_futures.py Sun Jan 2 22:43:19 2011 @@ -27,6 +27,7 @@ LOGGER, STDERR_HANDLER, wait) import concurrent.futures.process + def create_future(state=PENDING, exception=None, result=None): f = Future() f._state = state @@ -34,6 +35,7 @@ f._result = result return f + PENDING_FUTURE = create_future(state=PENDING) RUNNING_FUTURE = create_future(state=RUNNING) CANCELLED_FUTURE = create_future(state=CANCELLED) @@ -41,110 +43,15 @@ EXCEPTION_FUTURE = create_future(state=FINISHED, exception=IOError()) SUCCESSFUL_FUTURE = create_future(state=FINISHED, result=42) + def mul(x, y): return x * y -class Call(object): - """A call that can be submitted to a future.Executor for testing. - - The call signals when it is called and waits for an event before finishing. - """ - CALL_LOCKS = {} - def _create_event(self): - if sys.platform.startswith('win'): - class SECURITY_ATTRIBUTES(ctypes.Structure): - _fields_ = [("nLength", ctypes.wintypes.DWORD), - ("lpSecurityDescriptor", ctypes.wintypes.LPVOID), - ("bInheritHandle", ctypes.wintypes.BOOL)] - - s = SECURITY_ATTRIBUTES() - s.nLength = ctypes.sizeof(s) - s.lpSecurityDescriptor = None - s.bInheritHandle = True - - handle = ctypes.windll.kernel32.CreateEventA(ctypes.pointer(s), - True, - False, - None) - assert handle is not None - return handle - else: - event = multiprocessing.Event() - self.CALL_LOCKS[id(event)] = event - return id(event) - - def _wait_on_event(self, handle): - if sys.platform.startswith('win'): - # WaitForSingleObject returns 0 if handle is signaled. - r = ctypes.windll.kernel32.WaitForSingleObject(handle, 60 * 1000) - if r != 0: - message = ( - 'WaitForSingleObject({}, ...) failed with {}, ' - 'GetLastError() = {}'.format( - handle, r, ctypes.GetLastError())) - logging.critical(message) - assert False, message - else: - self.CALL_LOCKS[handle].wait() - - def _signal_event(self, handle): - if sys.platform.startswith('win'): - r = ctypes.windll.kernel32.SetEvent(handle) # Returns 0 on failure. - if r == 0: - message = ( - 'SetEvent({}) failed with {}, GetLastError() = {}'.format( - handle, r, ctypes.GetLastError())) - logging.critical(message) - assert False, message - else: - self.CALL_LOCKS[handle].set() - - def __init__(self, manual_finish=False, result=42): - self._called_event = self._create_event() - self._can_finish = self._create_event() - - self._result = result - if not manual_finish: - self._signal_event(self._can_finish) +def sleep_and_raise(t): + time.sleep(t) + raise Exception('this is an exception') - def wait_on_called(self): - self._wait_on_event(self._called_event) - - def set_can(self): - self._signal_event(self._can_finish) - - def __call__(self): - self._signal_event(self._called_event) - self._wait_on_event(self._can_finish) - - return self._result - - def close(self): - self.set_can() - if sys.platform.startswith('win'): - ctypes.windll.kernel32.CloseHandle(self._called_event) - ctypes.windll.kernel32.CloseHandle(self._can_finish) - self._called_event = None - self._can_finish = None - else: - del self.CALL_LOCKS[self._called_event] - del self.CALL_LOCKS[self._can_finish] - -class ExceptionCall(Call): - def __call__(self): - self._signal_event(self._called_event) - self._wait_on_event(self._can_finish) - raise ZeroDivisionError() - -class MapCall(Call): - def __init__(self, result=42): - super().__init__(manual_finish=True, result=result) - - def __call__(self, manual_finish): - if manual_finish: - super().__call__() - return self._result class ExecutorShutdownTest(unittest.TestCase): def test_run_after_shutdown(self): @@ -154,28 +61,6 @@ pow, 2, 5) - def _start_some_futures(self): - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) - call3 = Call(manual_finish=True) - - try: - self.executor.submit(call1) - self.executor.submit(call2) - self.executor.submit(call3) - - call1.wait_on_called() - call2.wait_on_called() - call3.wait_on_called() - - call1.set_can() - call2.set_can() - call3.set_can() - finally: - call1.close() - call2.close() - call3.close() - class ThreadPoolShutdownTest(ExecutorShutdownTest): def setUp(self): self.executor = futures.ThreadPoolExecutor(max_workers=5) @@ -184,7 +69,9 @@ self.executor.shutdown(wait=True) def test_threads_terminate(self): - self._start_some_futures() + self.executor.submit(mul, 21, 2) + self.executor.submit(mul, 6, 7) + self.executor.submit(mul, 3, 14) self.assertEqual(len(self.executor._threads), 3) self.executor.shutdown() for t in self.executor._threads: @@ -216,7 +103,9 @@ self.executor.shutdown(wait=True) def test_processes_terminate(self): - self._start_some_futures() + self.executor.submit(mul, 21, 2) + self.executor.submit(mul, 6, 7) + self.executor.submit(mul, 3, 14) self.assertEqual(len(self.executor._processes), 5) processes = self.executor._processes self.executor.shutdown() @@ -226,11 +115,11 @@ def test_context_manager_shutdown(self): with futures.ProcessPoolExecutor(max_workers=5) as e: - executor = e + processes = e._processes self.assertEqual(list(e.map(abs, range(-5, 5))), [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]) - for p in self.executor._processes: + for p in processes: p.join() def test_del_shutdown(self): @@ -244,305 +133,171 @@ for p in processes: p.join() + class WaitTests(unittest.TestCase): def test_first_completed(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() - - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) - - t = threading.Thread(target=wait_test) - t.start() - done, not_done = futures.wait( - [CANCELLED_FUTURE, future1, future2], - return_when=futures.FIRST_COMPLETED) + future1 = self.executor.submit(mul, 21, 2) + future2 = self.executor.submit(time.sleep, 5) - self.assertEqual(set([future1]), done) - self.assertEqual(set([CANCELLED_FUTURE, future2]), not_done) - finally: - call1.close() - call2.close() - - def test_first_completed_one_already_completed(self): - call1 = Call(manual_finish=True) - try: - future1 = self.executor.submit(call1) + done, not_done = futures.wait( + [CANCELLED_FUTURE, future1, future2], + return_when=futures.FIRST_COMPLETED) + + self.assertEqual(set([future1]), done) + self.assertEqual(set([CANCELLED_FUTURE, future2]), not_done) + + def test_first_completed_some_already_completed(self): + future1 = self.executor.submit(time.sleep, 2) + + finished, pending = futures.wait( + [CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE, future1], + return_when=futures.FIRST_COMPLETED) - finished, pending = futures.wait( - [SUCCESSFUL_FUTURE, future1], - return_when=futures.FIRST_COMPLETED) - - self.assertEqual(set([SUCCESSFUL_FUTURE]), finished) - self.assertEqual(set([future1]), pending) - finally: - call1.close() + self.assertEqual( + set([CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE]), + finished) + self.assertEqual(set([future1]), pending) def test_first_exception(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() - call2.set_can() - - call1 = Call(manual_finish=True) - call2 = ExceptionCall(manual_finish=True) - call3 = Call(manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) - future3 = self.executor.submit(call3) - - t = threading.Thread(target=wait_test) - t.start() - finished, pending = futures.wait( - [future1, future2, future3], - return_when=futures.FIRST_EXCEPTION) + future1 = self.executor.submit(mul, 2, 21) + future2 = self.executor.submit(sleep_and_raise, 5) + future3 = self.executor.submit(time.sleep, 10) + + finished, pending = futures.wait( + [future1, future2, future3], + return_when=futures.FIRST_EXCEPTION) - self.assertEqual(set([future1, future2]), finished) - self.assertEqual(set([future3]), pending) - finally: - call1.close() - call2.close() - call3.close() + self.assertEqual(set([future1, future2]), finished) + self.assertEqual(set([future3]), pending) def test_first_exception_some_already_complete(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() - - call1 = ExceptionCall(manual_finish=True) - call2 = Call(manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) - - t = threading.Thread(target=wait_test) - t.start() - finished, pending = futures.wait( - [SUCCESSFUL_FUTURE, - CANCELLED_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - future1, future2], - return_when=futures.FIRST_EXCEPTION) - - self.assertEqual(set([SUCCESSFUL_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - future1]), finished) - self.assertEqual(set([CANCELLED_FUTURE, future2]), pending) - + future1 = self.executor.submit(divmod, 21, 0) + future2 = self.executor.submit(time.sleep, 5) - finally: - call1.close() - call2.close() + finished, pending = futures.wait( + [SUCCESSFUL_FUTURE, + CANCELLED_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + future1, future2], + return_when=futures.FIRST_EXCEPTION) + + self.assertEqual(set([SUCCESSFUL_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + future1]), finished) + self.assertEqual(set([CANCELLED_FUTURE, future2]), pending) def test_first_exception_one_already_failed(self): - call1 = Call(manual_finish=True) - try: - future1 = self.executor.submit(call1) + future1 = self.executor.submit(time.sleep, 2) - finished, pending = futures.wait( - [EXCEPTION_FUTURE, future1], - return_when=futures.FIRST_EXCEPTION) + finished, pending = futures.wait( + [EXCEPTION_FUTURE, future1], + return_when=futures.FIRST_EXCEPTION) - self.assertEqual(set([EXCEPTION_FUTURE]), finished) - self.assertEqual(set([future1]), pending) - finally: - call1.close() + self.assertEqual(set([EXCEPTION_FUTURE]), finished) + self.assertEqual(set([future1]), pending) def test_all_completed(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() - call2.set_can() - - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) + future1 = self.executor.submit(divmod, 2, 0) + future2 = self.executor.submit(mul, 2, 21) - t = threading.Thread(target=wait_test) - t.start() - finished, pending = futures.wait( - [future1, future2], - return_when=futures.ALL_COMPLETED) - - self.assertEqual(set([future1, future2]), finished) - self.assertEqual(set(), pending) - finally: - call1.close() - call2.close() - - def test_all_completed_some_already_completed(self): - def wait_test(): - while not future1._waiters: - pass - - future4.cancel() - call1.set_can() - call2.set_can() - call3.set_can() - - self.assertLessEqual( - futures.process.EXTRA_QUEUED_CALLS, - 1, - 'this test assumes that future4 will be cancelled before it is ' - 'queued to run - which might not be the case if ' - 'ProcessPoolExecutor is too aggresive in scheduling futures') - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) - call3 = Call(manual_finish=True) - call4 = Call(manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) - future3 = self.executor.submit(call3) - future4 = self.executor.submit(call4) - - t = threading.Thread(target=wait_test) - t.start() - finished, pending = futures.wait( - [SUCCESSFUL_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - future1, future2, future3, future4], - return_when=futures.ALL_COMPLETED) - - self.assertEqual(set([SUCCESSFUL_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - future1, future2, future3, future4]), - finished) - self.assertEqual(set(), pending) - finally: - call1.close() - call2.close() - call3.close() - call4.close() - - def test_timeout(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() - - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) - - t = threading.Thread(target=wait_test) - t.start() - finished, pending = futures.wait( - [CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1, future2], - timeout=5, - return_when=futures.ALL_COMPLETED) - - self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1]), finished) - self.assertEqual(set([future2]), pending) - - - finally: - call1.close() - call2.close() + finished, pending = futures.wait( + [SUCCESSFUL_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + future1, + future2], + return_when=futures.ALL_COMPLETED) + + self.assertEqual(set([SUCCESSFUL_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + future1, + future2]), finished) + self.assertEqual(set(), pending) class ThreadPoolWaitTests(WaitTests): def setUp(self): self.executor = futures.ThreadPoolExecutor(max_workers=1) + # Make sure that the executor is ready to do work before running the + # tests. This should reduce the probability of timeouts in the tests. + self.executor.submit(mul, 21, 2).result() def tearDown(self): self.executor.shutdown(wait=True) + class ProcessPoolWaitTests(WaitTests): def setUp(self): self.executor = futures.ProcessPoolExecutor(max_workers=1) + # Make sure that the executor is ready to do work before running the + # tests. This should reduce the probability of timeouts in the tests. + self.executor.submit(mul, 21, 2).result() def tearDown(self): self.executor.shutdown(wait=True) + class AsCompletedTests(unittest.TestCase): # TODO(brian at sweetapp.com): Should have a test with a non-zero timeout. def test_no_timeout(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() - call2.set_can() + future1 = self.executor.submit(mul, 2, 21) + future2 = self.executor.submit(mul, 7, 6) - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) + completed = set(futures.as_completed( + [CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE, + future1, future2])) + self.assertEqual(set( + [CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE, + future1, future2]), + completed) - t = threading.Thread(target=wait_test) - t.start() - completed = set(futures.as_completed( - [CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1, future2])) - self.assertEqual(set( + def test_zero_timeout(self): + future1 = self.executor.submit(time.sleep, 2) + completed_futures = set() + try: + for future in futures.as_completed( [CANCELLED_AND_NOTIFIED_FUTURE, EXCEPTION_FUTURE, SUCCESSFUL_FUTURE, - future1, future2]), - completed) - finally: - call1.close() - call2.close() + future1], + timeout=0): + completed_futures.add(future) + except futures.TimeoutError: + pass + + self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE]), + completed_futures) - def test_zero_timeout(self): - call1 = Call(manual_finish=True) - try: - future1 = self.executor.submit(call1) - completed_futures = set() - try: - for future in futures.as_completed( - [CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1], - timeout=0): - completed_futures.add(future) - except futures.TimeoutError: - pass - - self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE]), - completed_futures) - finally: - call1.close() class ThreadPoolAsCompletedTests(AsCompletedTests): def setUp(self): self.executor = futures.ThreadPoolExecutor(max_workers=1) + # Make sure that the executor is ready to do work before running the + # tests. This should reduce the probability of timeouts in the tests. + self.executor.submit(mul, 21, 2).result() def tearDown(self): self.executor.shutdown(wait=True) + class ProcessPoolAsCompletedTests(AsCompletedTests): def setUp(self): self.executor = futures.ProcessPoolExecutor(max_workers=1) + # Make sure that the executor is ready to do work before running the + # tests. This should reduce the probability of timeouts in the tests. + self.executor.submit(mul, 21, 2).result() def tearDown(self): self.executor.shutdown(wait=True) + class ExecutorTest(unittest.TestCase): # Executor.shutdown() and context manager usage is tested by # ExecutorShutdownTest. @@ -567,21 +322,18 @@ def test_map_timeout(self): results = [] - timeout_call = MapCall() try: - try: - for i in self.executor.map(timeout_call, - [False, False, True], - timeout=5): - results.append(i) - except futures.TimeoutError: - pass - else: - self.fail('expected TimeoutError') - finally: - timeout_call.close() + for i in self.executor.map(time.sleep, + [0, 0, 10], + timeout=5): + results.append(i) + except futures.TimeoutError: + pass + else: + self.fail('expected TimeoutError') + + self.assertEqual([None, None], results) - self.assertEqual([42, 42], results) class ThreadPoolExecutorTest(ExecutorTest): def setUp(self): @@ -590,6 +342,7 @@ def tearDown(self): self.executor.shutdown(wait=True) + class ProcessPoolExecutorTest(ExecutorTest): def setUp(self): self.executor = futures.ProcessPoolExecutor(max_workers=1) @@ -597,6 +350,7 @@ def tearDown(self): self.executor.shutdown(wait=True) + class FutureTests(unittest.TestCase): def test_done_callback_with_result(self): callback_result = None From python-checkins at python.org Sun Jan 2 23:06:54 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 23:06:54 +0100 (CET) Subject: [Python-checkins] r87653 - python/branches/py3k/Doc/library/socket.rst Message-ID: <20110102220654.198ADEE9B7@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 23:06:53 2011 New Revision: 87653 Log: Clarify behaviour of close() and shutdown() on sockets. Modified: python/branches/py3k/Doc/library/socket.rst Modified: python/branches/py3k/Doc/library/socket.rst ============================================================================== --- python/branches/py3k/Doc/library/socket.rst (original) +++ python/branches/py3k/Doc/library/socket.rst Sun Jan 2 23:06:53 2011 @@ -552,6 +552,12 @@ remote end will receive no more data (after queued data is flushed). Sockets are automatically closed when they are garbage-collected. + .. note:: + :meth:`close()` releases the resource associated with a connection but + does not necessarily close the connection immediately. If you want + to close the connection in a timely fashion, call :meth:`shutdown()` + before :meth:`close()`. + .. method:: socket.connect(address) From python-checkins at python.org Sun Jan 2 23:09:27 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 23:09:27 +0100 (CET) Subject: [Python-checkins] r87654 - python/branches/py3k/Doc/library/ssl.rst Message-ID: <20110102220927.ABA64EE99D@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 23:09:27 2011 New Revision: 87654 Log: Add a shutdown() call in the server example. Modified: python/branches/py3k/Doc/library/ssl.rst Modified: python/branches/py3k/Doc/library/ssl.rst ============================================================================== --- python/branches/py3k/Doc/library/ssl.rst (original) +++ python/branches/py3k/Doc/library/ssl.rst Sun Jan 2 23:09:27 2011 @@ -888,6 +888,7 @@ try: deal_with_client(connstream) finally: + connstream.shutdown(socket.SHUT_RDWR) connstream.close() Then you'll read data from the ``connstream`` and do something with it till you From python-checkins at python.org Sun Jan 2 23:12:23 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 23:12:23 +0100 (CET) Subject: [Python-checkins] r87655 - in python/branches/py3k/Doc/library: socket.rst ssl.rst Message-ID: <20110102221223.26AA1EE9B7@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 23:12:22 2011 New Revision: 87655 Log: Some nits. Modified: python/branches/py3k/Doc/library/socket.rst python/branches/py3k/Doc/library/ssl.rst Modified: python/branches/py3k/Doc/library/socket.rst ============================================================================== --- python/branches/py3k/Doc/library/socket.rst (original) +++ python/branches/py3k/Doc/library/socket.rst Sun Jan 2 23:12:22 2011 @@ -25,6 +25,15 @@ is implicit on send operations. +.. seealso:: + + Module :mod:`socketserver` + Classes that simplify writing network servers. + + Module :mod:`ssl` + A TLS/SSL wrapper for socket objects. + + Socket families --------------- @@ -517,12 +526,6 @@ same as ``type(socket(...))``. -.. seealso:: - - Module :mod:`socketserver` - Classes that simplify writing network servers. - - .. _socket-objects: Socket Objects Modified: python/branches/py3k/Doc/library/ssl.rst ============================================================================== --- python/branches/py3k/Doc/library/ssl.rst (original) +++ python/branches/py3k/Doc/library/ssl.rst Sun Jan 2 23:12:22 2011 @@ -1,8 +1,8 @@ -:mod:`ssl` --- SSL wrapper for socket objects -============================================= +:mod:`ssl` --- TLS/SSL wrapper for socket objects +================================================= .. module:: ssl - :synopsis: SSL wrapper for socket objects + :synopsis: TLS/SSL wrapper for socket objects .. moduleauthor:: Bill Janssen .. sectionauthor:: Bill Janssen From python-checkins at python.org Sun Jan 2 23:16:10 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Sun, 2 Jan 2011 23:16:10 +0100 (CET) Subject: [Python-checkins] r87656 - python/branches/py3k/Lib/test/test_time.py Message-ID: <20110102221610.9044FEE9B4@mail.python.org> Author: alexander.belopolsky Date: Sun Jan 2 23:16:10 2011 New Revision: 87656 Log: Issue #8013: Fixed test Modified: python/branches/py3k/Lib/test/test_time.py Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Sun Jan 2 23:16:10 2011 @@ -123,8 +123,15 @@ time.asctime(time.gmtime(self.t)) self.assertRaises(TypeError, time.asctime, 0) self.assertRaises(TypeError, time.asctime, ()) - self.assertRaises(ValueError, time.asctime, - (12345, 1, 0, 0, 0, 0, 0, 0, 0)) + # XXX: Posix compiant asctime should refuse to convert + # year > 9999, but Linux implementation does not. + # self.assertRaises(ValueError, time.asctime, + # (12345, 1, 0, 0, 0, 0, 0, 0, 0)) + # XXX: For now, just make sure we don't have a crash: + try: + time.asctime((12345, 1, 0, 0, 0, 0, 0, 0, 0)) + except ValueError: + pass def test_asctime_bounding_check(self): self._bounds_checking(time.asctime) From python-checkins at python.org Sun Jan 2 23:33:43 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 2 Jan 2011 23:33:43 +0100 (CET) Subject: [Python-checkins] r87657 - in python/branches/py3k: Lib/test/test_time.py Modules/timemodule.c Message-ID: <20110102223343.7A298EE986@mail.python.org> Author: georg.brandl Date: Sun Jan 2 23:33:43 2011 New Revision: 87657 Log: #8013 follow-up: * In asctime and ctime, properly remove the newline if the year has more than four digits * Consistent error message for both functions * Fix the test comments and add a check for the removed newline Modified: python/branches/py3k/Lib/test/test_time.py python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Sun Jan 2 23:33:43 2011 @@ -123,19 +123,33 @@ time.asctime(time.gmtime(self.t)) self.assertRaises(TypeError, time.asctime, 0) self.assertRaises(TypeError, time.asctime, ()) - # XXX: Posix compiant asctime should refuse to convert - # year > 9999, but Linux implementation does not. - # self.assertRaises(ValueError, time.asctime, - # (12345, 1, 0, 0, 0, 0, 0, 0, 0)) - # XXX: For now, just make sure we don't have a crash: + # XXX: POSIX-compliant asctime should refuse to convert year > 9999, + # but glibc implementation does not. For now, just check it doesn't + # segfault as it did before, and the result contains no newline. try: - time.asctime((12345, 1, 0, 0, 0, 0, 0, 0, 0)) + result = time.asctime((12345, 1, 0, 0, 0, 0, 0, 0, 0)) except ValueError: + # for POSIX-compliant runtimes pass + else: + self.assertNotIn('\n', result) def test_asctime_bounding_check(self): self._bounds_checking(time.asctime) + def test_ctime(self): + # XXX: POSIX-compliant ctime should refuse to convert year > 9999, + # but glibc implementation does not. For now, just check it doesn't + # segfault as it did before, and the result contains no newline. + try: + result = time.ctime(1e12) + except ValueError: + # for POSIX-compliant runtimes (or 32-bit systems, where time_t + # cannot hold timestamps with a five-digit year) + pass + else: + self.assertNotIn('\n', result) + @unittest.skipIf(not hasattr(time, "tzset"), "time module has no attribute tzset") def test_tzset(self): Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Sun Jan 2 23:33:43 2011 @@ -611,7 +611,7 @@ { PyObject *tup = NULL; struct tm buf; - char *p; + char *p, *q; if (!PyArg_UnpackTuple(args, "asctime", 0, 1, &tup)) return NULL; if (tup == NULL) { @@ -621,11 +621,14 @@ return NULL; p = asctime(&buf); if (p == NULL) { - PyErr_SetString(PyExc_ValueError, "invalid time"); + PyErr_SetString(PyExc_ValueError, "unconvertible time"); return NULL; } - if (p[24] == '\n') - p[24] = '\0'; + /* Replace a terminating newline by a null byte, normally at position 24. + * It can occur later if the year has more than four digits. */ + for (q = p+24; *q != '\0'; q++) + if (*q == '\n') + *q = '\0'; return PyUnicode_FromString(p); } @@ -641,7 +644,7 @@ { PyObject *ot = NULL; time_t tt; - char *p; + char *p, *q; if (!PyArg_UnpackTuple(args, "ctime", 0, 1, &ot)) return NULL; @@ -660,8 +663,11 @@ PyErr_SetString(PyExc_ValueError, "unconvertible time"); return NULL; } - if (p[24] == '\n') - p[24] = '\0'; + /* Replace a terminating newline by a null byte, normally at position 24. + * It can occur later if the year has more than four digits. */ + for (q = p+24; *q != '\0'; q++) + if (*q == '\n') + *q = '\0'; return PyUnicode_FromString(p); } From python-checkins at python.org Sun Jan 2 23:36:00 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 23:36:00 +0100 (CET) Subject: [Python-checkins] r87658 - in python/branches/release31-maint: Doc/library/socket.rst Doc/library/ssl.rst Message-ID: <20110102223600.05A31EE986@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 23:35:59 2011 New Revision: 87658 Log: Merged revisions 87653-87655 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87653 | antoine.pitrou | 2011-01-02 23:06:53 +0100 (dim., 02 janv. 2011) | 3 lines Clarify behaviour of close() and shutdown() on sockets. ........ r87654 | antoine.pitrou | 2011-01-02 23:09:27 +0100 (dim., 02 janv. 2011) | 3 lines Add a shutdown() call in the server example. ........ r87655 | antoine.pitrou | 2011-01-02 23:12:22 +0100 (dim., 02 janv. 2011) | 3 lines Some nits. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Doc/library/socket.rst python/branches/release31-maint/Doc/library/ssl.rst Modified: python/branches/release31-maint/Doc/library/socket.rst ============================================================================== --- python/branches/release31-maint/Doc/library/socket.rst (original) +++ python/branches/release31-maint/Doc/library/socket.rst Sun Jan 2 23:35:59 2011 @@ -26,6 +26,15 @@ is implicit on send operations. +.. seealso:: + + Module :mod:`socketserver` + Classes that simplify writing network servers. + + Module :mod:`ssl` + A TLS/SSL wrapper for socket objects. + + Socket families --------------- @@ -487,12 +496,6 @@ same as ``type(socket(...))``. -.. seealso:: - - Module :mod:`socketserver` - Classes that simplify writing network servers. - - .. _socket-objects: Socket Objects @@ -522,6 +525,12 @@ remote end will receive no more data (after queued data is flushed). Sockets are automatically closed when they are garbage-collected. + .. note:: + :meth:`close()` releases the resource associated with a connection but + does not necessarily close the connection immediately. If you want + to close the connection in a timely fashion, call :meth:`shutdown()` + before :meth:`close()`. + .. method:: socket.connect(address) Modified: python/branches/release31-maint/Doc/library/ssl.rst ============================================================================== --- python/branches/release31-maint/Doc/library/ssl.rst (original) +++ python/branches/release31-maint/Doc/library/ssl.rst Sun Jan 2 23:35:59 2011 @@ -1,8 +1,8 @@ -:mod:`ssl` --- SSL wrapper for socket objects -============================================= +:mod:`ssl` --- TLS/SSL wrapper for socket objects +================================================= .. module:: ssl - :synopsis: SSL wrapper for socket objects + :synopsis: TLS/SSL wrapper for socket objects .. moduleauthor:: Bill Janssen .. sectionauthor:: Bill Janssen @@ -537,13 +537,17 @@ for it:: while True: - newsocket, fromaddr = bindsocket.accept() - connstream = ssl.wrap_socket(newsocket, - server_side=True, - certfile="mycertfile", - keyfile="mykeyfile", - ssl_version=ssl.PROTOCOL_TLSv1) - deal_with_client(connstream) + newsocket, fromaddr = bindsocket.accept() + connstream = ssl.wrap_socket(newsocket, + server_side=True, + certfile="mycertfile", + keyfile="mykeyfile", + ssl_version=ssl.PROTOCOL_TLSv1) + try: + deal_with_client(connstream) + finally: + connstream.shutdown(socket.SHUT_RDWR) + connstream.close() Then you'd read data from the ``connstream`` and do something with it till you are finished with the client (or the client is finished with you):: @@ -559,7 +563,6 @@ break data = connstream.read() # finished with client - connstream.close() And go back to listening for new client connections. From python-checkins at python.org Sun Jan 2 23:39:10 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 2 Jan 2011 23:39:10 +0100 (CET) Subject: [Python-checkins] r87659 - in python/branches/release27-maint: Doc/library/socket.rst Doc/library/ssl.rst Message-ID: <20110102223910.4AE09EE986@mail.python.org> Author: antoine.pitrou Date: Sun Jan 2 23:39:10 2011 New Revision: 87659 Log: Merged revisions 87653-87655 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87653 | antoine.pitrou | 2011-01-02 23:06:53 +0100 (dim., 02 janv. 2011) | 3 lines Clarify behaviour of close() and shutdown() on sockets. ........ r87654 | antoine.pitrou | 2011-01-02 23:09:27 +0100 (dim., 02 janv. 2011) | 3 lines Add a shutdown() call in the server example. ........ r87655 | antoine.pitrou | 2011-01-02 23:12:22 +0100 (dim., 02 janv. 2011) | 3 lines Some nits. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Doc/library/socket.rst python/branches/release27-maint/Doc/library/ssl.rst Modified: python/branches/release27-maint/Doc/library/socket.rst ============================================================================== --- python/branches/release27-maint/Doc/library/socket.rst (original) +++ python/branches/release27-maint/Doc/library/socket.rst Sun Jan 2 23:39:10 2011 @@ -515,6 +515,9 @@ Module :mod:`SocketServer` Classes that simplify writing network servers. + Module :mod:`ssl` + A TLS/SSL wrapper for socket objects. + .. _socket-objects: @@ -551,6 +554,12 @@ remote end will receive no more data (after queued data is flushed). Sockets are automatically closed when they are garbage-collected. + .. note:: + :meth:`close()` releases the resource associated with a connection but + does not necessarily close the connection immediately. If you want + to close the connection in a timely fashion, call :meth:`shutdown()` + before :meth:`close()`. + .. method:: socket.connect(address) Modified: python/branches/release27-maint/Doc/library/ssl.rst ============================================================================== --- python/branches/release27-maint/Doc/library/ssl.rst (original) +++ python/branches/release27-maint/Doc/library/ssl.rst Sun Jan 2 23:39:10 2011 @@ -1,8 +1,8 @@ -:mod:`ssl` --- SSL wrapper for socket objects -============================================= +:mod:`ssl` --- TLS/SSL wrapper for socket objects +================================================= .. module:: ssl - :synopsis: SSL wrapper for socket objects + :synopsis: TLS/SSL wrapper for socket objects .. moduleauthor:: Bill Janssen @@ -582,13 +582,17 @@ for it:: while True: - newsocket, fromaddr = bindsocket.accept() - connstream = ssl.wrap_socket(newsocket, - server_side=True, - certfile="mycertfile", - keyfile="mykeyfile", - ssl_version=ssl.PROTOCOL_TLSv1) - deal_with_client(connstream) + newsocket, fromaddr = bindsocket.accept() + connstream = ssl.wrap_socket(newsocket, + server_side=True, + certfile="mycertfile", + keyfile="mykeyfile", + ssl_version=ssl.PROTOCOL_TLSv1) + try: + deal_with_client(connstream) + finally: + connstream.shutdown(socket.SHUT_RDWR) + connstream.close() Then you'd read data from the ``connstream`` and do something with it till you are finished with the client (or the client is finished with you):: @@ -604,7 +608,6 @@ break data = connstream.read() # finished with client - connstream.close() And go back to listening for new client connections. From python-checkins at python.org Sun Jan 2 23:55:12 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 2 Jan 2011 23:55:12 +0100 (CET) Subject: [Python-checkins] r87660 - python/branches/release31-maint/Lib/logging/handlers.py Message-ID: <20110102225512.A342DEE9B0@mail.python.org> Author: georg.brandl Date: Sun Jan 2 23:55:12 2011 New Revision: 87660 Log: #10810: fix missing import. Modified: python/branches/release31-maint/Lib/logging/handlers.py Modified: python/branches/release31-maint/Lib/logging/handlers.py ============================================================================== --- python/branches/release31-maint/Lib/logging/handlers.py (original) +++ python/branches/release31-maint/Lib/logging/handlers.py Sun Jan 2 23:55:12 2011 @@ -25,7 +25,7 @@ """ import logging, socket, os, pickle, struct, time, re -from stat import ST_DEV, ST_INO +from stat import ST_DEV, ST_INO, ST_MTIME try: import codecs From python-checkins at python.org Mon Jan 3 00:00:58 2011 From: python-checkins at python.org (brian.quinlan) Date: Mon, 3 Jan 2011 00:00:58 +0100 (CET) Subject: [Python-checkins] r87661 - python/branches/py3k-futures-on-windows/Lib/test/test_concurrent_futures.py Message-ID: <20110102230058.473F3EE988@mail.python.org> Author: brian.quinlan Date: Mon Jan 3 00:00:58 2011 New Revision: 87661 Log: Removes some obsolete imports. Modified: python/branches/py3k-futures-on-windows/Lib/test/test_concurrent_futures.py Modified: python/branches/py3k-futures-on-windows/Lib/test/test_concurrent_futures.py ============================================================================== --- python/branches/py3k-futures-on-windows/Lib/test/test_concurrent_futures.py (original) +++ python/branches/py3k-futures-on-windows/Lib/test/test_concurrent_futures.py Mon Jan 3 00:00:58 2011 @@ -11,16 +11,11 @@ import io import logging -import multiprocessing import sys import threading import time import unittest -if sys.platform.startswith('win'): - import ctypes - import ctypes.wintypes - from concurrent import futures from concurrent.futures._base import ( PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED, Future, From python-checkins at python.org Mon Jan 3 00:09:41 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 3 Jan 2011 00:09:41 +0100 (CET) Subject: [Python-checkins] r87662 - in python/branches/release31-maint: Lib/test/test_time.py Modules/timemodule.c Message-ID: <20110102230941.52432EE986@mail.python.org> Author: alexander.belopolsky Date: Mon Jan 3 00:09:41 2011 New Revision: 87662 Log: Merged revisions 87648,87656 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87648 | alexander.belopolsky | 2011-01-02 15:48:22 -0500 (Sun, 02 Jan 2011) | 1 line Issue #8013: Fixed time.asctime segfault when OS's asctime fails ........ r87656 | alexander.belopolsky | 2011-01-02 17:16:10 -0500 (Sun, 02 Jan 2011) | 1 line Issue #8013: Fixed test ........ Modified: python/branches/release31-maint/Lib/test/test_time.py python/branches/release31-maint/Modules/timemodule.c Modified: python/branches/release31-maint/Lib/test/test_time.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_time.py (original) +++ python/branches/release31-maint/Lib/test/test_time.py Mon Jan 3 00:09:41 2011 @@ -124,6 +124,16 @@ def test_asctime(self): time.asctime(time.gmtime(self.t)) self.assertRaises(TypeError, time.asctime, 0) + self.assertRaises(TypeError, time.asctime, ()) + # XXX: Posix compiant asctime should refuse to convert + # year > 9999, but Linux implementation does not. + # self.assertRaises(ValueError, time.asctime, + # (12345, 1, 0, 0, 0, 0, 0, 0, 0)) + # XXX: For now, just make sure we don't have a crash: + try: + time.asctime((12345, 1, 0, 0, 0, 0, 0, 0, 0)) + except ValueError: + pass @unittest.skipIf(not hasattr(time, "tzset"), "time module has no attribute tzset") Modified: python/branches/release31-maint/Modules/timemodule.c ============================================================================== --- python/branches/release31-maint/Modules/timemodule.c (original) +++ python/branches/release31-maint/Modules/timemodule.c Mon Jan 3 00:09:41 2011 @@ -643,6 +643,10 @@ } else if (!gettmarg(tup, &buf)) return NULL; p = asctime(&buf); + if (p == NULL) { + PyErr_SetString(PyExc_ValueError, "invalid time"); + return NULL; + } if (p[24] == '\n') p[24] = '\0'; return PyUnicode_FromString(p); From python-checkins at python.org Mon Jan 3 00:23:54 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 3 Jan 2011 00:23:54 +0100 (CET) Subject: [Python-checkins] r87663 - in python/branches/release27-maint: Lib/test/test_time.py Modules/timemodule.c Message-ID: <20110102232354.9CC40EE986@mail.python.org> Author: alexander.belopolsky Date: Mon Jan 3 00:23:54 2011 New Revision: 87663 Log: Merged revisions 87648,87656 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87648 | alexander.belopolsky | 2011-01-02 15:48:22 -0500 (Sun, 02 Jan 2011) | 1 line Issue #8013: Fixed time.asctime segfault when OS's asctime fails ........ r87656 | alexander.belopolsky | 2011-01-02 17:16:10 -0500 (Sun, 02 Jan 2011) | 1 line Issue #8013: Fixed test ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/test/test_time.py python/branches/release27-maint/Modules/timemodule.c Modified: python/branches/release27-maint/Lib/test/test_time.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_time.py (original) +++ python/branches/release27-maint/Lib/test/test_time.py Mon Jan 3 00:23:54 2011 @@ -114,6 +114,16 @@ def test_asctime(self): time.asctime(time.gmtime(self.t)) self.assertRaises(TypeError, time.asctime, 0) + self.assertRaises(TypeError, time.asctime, ()) + # XXX: Posix compiant asctime should refuse to convert + # year > 9999, but Linux implementation does not. + # self.assertRaises(ValueError, time.asctime, + # (12345, 1, 0, 0, 0, 0, 0, 0, 0)) + # XXX: For now, just make sure we don't have a crash: + try: + time.asctime((12345, 1, 0, 0, 0, 0, 0, 0, 0)) + except ValueError: + pass @unittest.skipIf(not hasattr(time, "tzset"), "time module has no attribute tzset") Modified: python/branches/release27-maint/Modules/timemodule.c ============================================================================== --- python/branches/release27-maint/Modules/timemodule.c (original) +++ python/branches/release27-maint/Modules/timemodule.c Mon Jan 3 00:23:54 2011 @@ -572,6 +572,10 @@ } else if (!gettmarg(tup, &buf)) return NULL; p = asctime(&buf); + if (p == NULL) { + PyErr_SetString(PyExc_ValueError, "invalid time"); + return NULL; + } if (p[24] == '\n') p[24] = '\0'; return PyString_FromString(p); From python-checkins at python.org Mon Jan 3 00:26:13 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 3 Jan 2011 00:26:13 +0100 (CET) Subject: [Python-checkins] r87664 - in python/branches/release26-maint: Lib/test/test_time.py Modules/timemodule.c Message-ID: <20110102232613.0C979D35E@mail.python.org> Author: alexander.belopolsky Date: Mon Jan 3 00:26:12 2011 New Revision: 87664 Log: Merged revisions 87663 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/release27-maint ................ r87663 | alexander.belopolsky | 2011-01-02 18:23:54 -0500 (Sun, 02 Jan 2011) | 13 lines Merged revisions 87648,87656 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87648 | alexander.belopolsky | 2011-01-02 15:48:22 -0500 (Sun, 02 Jan 2011) | 1 line Issue #8013: Fixed time.asctime segfault when OS's asctime fails ........ r87656 | alexander.belopolsky | 2011-01-02 17:16:10 -0500 (Sun, 02 Jan 2011) | 1 line Issue #8013: Fixed test ........ ................ Modified: python/branches/release26-maint/ (props changed) python/branches/release26-maint/Lib/test/test_time.py python/branches/release26-maint/Modules/timemodule.c Modified: python/branches/release26-maint/Lib/test/test_time.py ============================================================================== --- python/branches/release26-maint/Lib/test/test_time.py (original) +++ python/branches/release26-maint/Lib/test/test_time.py Mon Jan 3 00:26:12 2011 @@ -119,6 +119,16 @@ def test_asctime(self): time.asctime(time.gmtime(self.t)) self.assertRaises(TypeError, time.asctime, 0) + self.assertRaises(TypeError, time.asctime, ()) + # XXX: Posix compiant asctime should refuse to convert + # year > 9999, but Linux implementation does not. + # self.assertRaises(ValueError, time.asctime, + # (12345, 1, 0, 0, 0, 0, 0, 0, 0)) + # XXX: For now, just make sure we don't have a crash: + try: + time.asctime((12345, 1, 0, 0, 0, 0, 0, 0, 0)) + except ValueError: + pass def test_tzset(self): if not hasattr(time, "tzset"): Modified: python/branches/release26-maint/Modules/timemodule.c ============================================================================== --- python/branches/release26-maint/Modules/timemodule.c (original) +++ python/branches/release26-maint/Modules/timemodule.c Mon Jan 3 00:26:12 2011 @@ -546,6 +546,10 @@ } else if (!gettmarg(tup, &buf)) return NULL; p = asctime(&buf); + if (p == NULL) { + PyErr_SetString(PyExc_ValueError, "invalid time"); + return NULL; + } if (p[24] == '\n') p[24] = '\0'; return PyString_FromString(p); From python-checkins at python.org Mon Jan 3 01:07:01 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 3 Jan 2011 01:07:01 +0100 (CET) Subject: [Python-checkins] r87665 - in python/branches/py3k: Lib/concurrent/futures/process.py Lib/test/test_concurrent_futures.py Misc/NEWS Message-ID: <20110103000701.64E15EE986@mail.python.org> Author: martin.v.loewis Date: Mon Jan 3 01:07:01 2011 New Revision: 87665 Log: Issue #10798: Reject supporting concurrent.futures if the system has too few POSIX semaphores. Modified: python/branches/py3k/Lib/concurrent/futures/process.py python/branches/py3k/Lib/test/test_concurrent_futures.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/concurrent/futures/process.py ============================================================================== --- python/branches/py3k/Lib/concurrent/futures/process.py (original) +++ python/branches/py3k/Lib/concurrent/futures/process.py Mon Jan 3 01:07:01 2011 @@ -244,6 +244,31 @@ else: work_item.future.set_result(result_item.result) +_system_limits_checked = False +_system_limited = None +def _check_system_limits(): + global _system_limits_checked, _system_limited + if _system_limits_checked: + if _system_limited: + raise NotImplementedError(_system_limited) + _system_limits_checked = True + try: + import os + nsems_max = os.sysconf("SC_SEM_NSEMS_MAX") + except (AttributeError, ValueError): + # sysconf not available or setting not available + return + if nsems_max == -1: + # indetermine limit, assume that limit is determined + # by available memory only + return + if nsems_max >= 256: + # minimum number of semaphores available + # according to POSIX + return + _system_limited = "system provides too few semaphores (%d available, 256 necessary)" % nsems_max + raise NotImplementedError(_system_limited) + class ProcessPoolExecutor(_base.Executor): def __init__(self, max_workers=None): """Initializes a new ProcessPoolExecutor instance. @@ -253,6 +278,7 @@ execute the given calls. If None or not given then as many worker processes will be created as the machine has processors. """ + _check_system_limits() _remove_dead_thread_references() if max_workers is None: Modified: python/branches/py3k/Lib/test/test_concurrent_futures.py ============================================================================== --- python/branches/py3k/Lib/test/test_concurrent_futures.py (original) +++ python/branches/py3k/Lib/test/test_concurrent_futures.py Mon Jan 3 01:07:01 2011 @@ -69,7 +69,7 @@ assert handle is not None return handle else: - event = multiprocessing.Event() + event = self.Event[0]() self.CALL_LOCKS[id(event)] = event return id(event) @@ -99,7 +99,8 @@ else: self.CALL_LOCKS[handle].set() - def __init__(self, manual_finish=False, result=42): + def __init__(self, Event, manual_finish=False, result=42): + self.Event = Event self._called_event = self._create_event() self._can_finish = self._create_event() @@ -138,8 +139,8 @@ raise ZeroDivisionError() class MapCall(Call): - def __init__(self, result=42): - super().__init__(manual_finish=True, result=result) + def __init__(self, Event, result=42): + super().__init__(Event, manual_finish=True, result=result) def __call__(self, manual_finish): if manual_finish: @@ -155,9 +156,9 @@ def _start_some_futures(self): - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) - call3 = Call(manual_finish=True) + call1 = Call(self.Event, manual_finish=True) + call2 = Call(self.Event, manual_finish=True) + call3 = Call(self.Event, manual_finish=True) try: self.executor.submit(call1) @@ -176,13 +177,28 @@ call2.close() call3.close() -class ThreadPoolShutdownTest(ExecutorShutdownTest): +class ThreadPoolMixin: + # wrap in tuple to prevent creation of instance methods + Event = (threading.Event,) def setUp(self): self.executor = futures.ThreadPoolExecutor(max_workers=5) def tearDown(self): self.executor.shutdown(wait=True) +class ProcessPoolMixin: + # wrap in tuple to prevent creation of instance methods + Event = (multiprocessing.Event,) + def setUp(self): + try: + self.executor = futures.ProcessPoolExecutor(max_workers=5) + except NotImplementedError as e: + self.skipTest(str(e)) + + def tearDown(self): + self.executor.shutdown(wait=True) + +class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest): def test_threads_terminate(self): self._start_some_futures() self.assertEqual(len(self.executor._threads), 3) @@ -208,13 +224,7 @@ for t in threads: t.join() -class ProcessPoolShutdownTest(ExecutorShutdownTest): - def setUp(self): - self.executor = futures.ProcessPoolExecutor(max_workers=5) - - def tearDown(self): - self.executor.shutdown(wait=True) - +class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest): def test_processes_terminate(self): self._start_some_futures() self.assertEqual(len(self.executor._processes), 5) @@ -251,8 +261,8 @@ pass call1.set_can() - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) + call1 = Call(self.Event, manual_finish=True) + call2 = Call(self.Event, manual_finish=True) try: future1 = self.executor.submit(call1) future2 = self.executor.submit(call2) @@ -270,7 +280,7 @@ call2.close() def test_first_completed_one_already_completed(self): - call1 = Call(manual_finish=True) + call1 = Call(self.Event, manual_finish=True) try: future1 = self.executor.submit(call1) @@ -290,9 +300,9 @@ call1.set_can() call2.set_can() - call1 = Call(manual_finish=True) - call2 = ExceptionCall(manual_finish=True) - call3 = Call(manual_finish=True) + call1 = Call(self.Event, manual_finish=True) + call2 = ExceptionCall(self.Event, manual_finish=True) + call3 = Call(self.Event, manual_finish=True) try: future1 = self.executor.submit(call1) future2 = self.executor.submit(call2) @@ -317,8 +327,8 @@ pass call1.set_can() - call1 = ExceptionCall(manual_finish=True) - call2 = Call(manual_finish=True) + call1 = ExceptionCall(self.Event, manual_finish=True) + call2 = Call(self.Event, manual_finish=True) try: future1 = self.executor.submit(call1) future2 = self.executor.submit(call2) @@ -343,7 +353,7 @@ call2.close() def test_first_exception_one_already_failed(self): - call1 = Call(manual_finish=True) + call1 = Call(self.Event, manual_finish=True) try: future1 = self.executor.submit(call1) @@ -363,8 +373,8 @@ call1.set_can() call2.set_can() - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) + call1 = Call(self.Event, manual_finish=True) + call2 = Call(self.Event, manual_finish=True) try: future1 = self.executor.submit(call1) future2 = self.executor.submit(call2) @@ -397,10 +407,10 @@ 'this test assumes that future4 will be cancelled before it is ' 'queued to run - which might not be the case if ' 'ProcessPoolExecutor is too aggresive in scheduling futures') - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) - call3 = Call(manual_finish=True) - call4 = Call(manual_finish=True) + call1 = Call(self.Event, manual_finish=True) + call2 = Call(self.Event, manual_finish=True) + call3 = Call(self.Event, manual_finish=True) + call4 = Call(self.Event, manual_finish=True) try: future1 = self.executor.submit(call1) future2 = self.executor.submit(call2) @@ -432,8 +442,8 @@ pass call1.set_can() - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) + call1 = Call(self.Event, manual_finish=True) + call2 = Call(self.Event, manual_finish=True) try: future1 = self.executor.submit(call1) future2 = self.executor.submit(call2) @@ -460,19 +470,11 @@ call2.close() -class ThreadPoolWaitTests(WaitTests): - def setUp(self): - self.executor = futures.ThreadPoolExecutor(max_workers=1) +class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests): + pass - def tearDown(self): - self.executor.shutdown(wait=True) - -class ProcessPoolWaitTests(WaitTests): - def setUp(self): - self.executor = futures.ProcessPoolExecutor(max_workers=1) - - def tearDown(self): - self.executor.shutdown(wait=True) +class ProcessPoolWaitTests(ProcessPoolMixin, WaitTests): + pass class AsCompletedTests(unittest.TestCase): # TODO(brian at sweetapp.com): Should have a test with a non-zero timeout. @@ -483,8 +485,8 @@ call1.set_can() call2.set_can() - call1 = Call(manual_finish=True) - call2 = Call(manual_finish=True) + call1 = Call(self.Event, manual_finish=True) + call2 = Call(self.Event, manual_finish=True) try: future1 = self.executor.submit(call1) future2 = self.executor.submit(call2) @@ -507,7 +509,7 @@ call2.close() def test_zero_timeout(self): - call1 = Call(manual_finish=True) + call1 = Call(self.Event, manual_finish=True) try: future1 = self.executor.submit(call1) completed_futures = set() @@ -529,19 +531,11 @@ finally: call1.close() -class ThreadPoolAsCompletedTests(AsCompletedTests): - def setUp(self): - self.executor = futures.ThreadPoolExecutor(max_workers=1) - - def tearDown(self): - self.executor.shutdown(wait=True) +class ThreadPoolAsCompletedTests(ThreadPoolMixin, AsCompletedTests): + pass -class ProcessPoolAsCompletedTests(AsCompletedTests): - def setUp(self): - self.executor = futures.ProcessPoolExecutor(max_workers=1) - - def tearDown(self): - self.executor.shutdown(wait=True) +class ProcessPoolAsCompletedTests(ProcessPoolMixin, AsCompletedTests): + pass class ExecutorTest(unittest.TestCase): # Executor.shutdown() and context manager usage is tested by @@ -567,7 +561,7 @@ def test_map_timeout(self): results = [] - timeout_call = MapCall() + timeout_call = MapCall(self.Event) try: try: for i in self.executor.map(timeout_call, @@ -583,19 +577,11 @@ self.assertEqual([42, 42], results) -class ThreadPoolExecutorTest(ExecutorTest): - def setUp(self): - self.executor = futures.ThreadPoolExecutor(max_workers=1) - - def tearDown(self): - self.executor.shutdown(wait=True) +class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest): + pass -class ProcessPoolExecutorTest(ExecutorTest): - def setUp(self): - self.executor = futures.ProcessPoolExecutor(max_workers=1) - - def tearDown(self): - self.executor.shutdown(wait=True) +class ProcessPoolExecutorTest(ProcessPoolMixin, ExecutorTest): + pass class FutureTests(unittest.TestCase): def test_done_callback_with_result(self): Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 3 01:07:01 2011 @@ -20,6 +20,9 @@ Library ------- +- Issue #10798: Reject supporting concurrent.futures if the system has too + few POSIX semaphores. + - Issue #10807: Remove base64, bz2, hex, quopri, rot13, uu and zlib codecs from the codec aliases. They are still accessible via codecs.lookup(). From python-checkins at python.org Mon Jan 3 01:19:11 2011 From: python-checkins at python.org (amaury.forgeotdarc) Date: Mon, 3 Jan 2011 01:19:11 +0100 (CET) Subject: [Python-checkins] r87666 - in python/branches/py3k: Lib/test/test_os.py Misc/NEWS Modules/posixmodule.c Message-ID: <20110103001911.EEE33EE986@mail.python.org> Author: amaury.forgeotdarc Date: Mon Jan 3 01:19:11 2011 New Revision: 87666 Log: #8278: In the Windows implementation of stat() and utime(), use time_t instead of int. This gives support for dates after 2038, at least when compiled with VS2003 or later, where time_t is 64bit. Modified: python/branches/py3k/Lib/test/test_os.py python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/posixmodule.c Modified: python/branches/py3k/Lib/test/test_os.py ============================================================================== --- python/branches/py3k/Lib/test/test_os.py (original) +++ python/branches/py3k/Lib/test/test_os.py Mon Jan 3 01:19:11 2011 @@ -365,6 +365,11 @@ os.utime(self.fname, (t1, t1)) self.assertEqual(os.stat(self.fname).st_mtime, t1) + def test_large_time(self): + t1 = 5000000000 # some day in 2128 + os.utime(self.fname, (t1, t1)) + self.assertEqual(os.stat(self.fname).st_mtime, t1) + def test_1686475(self): # Verify that an open file can be stat'ed try: Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 3 01:19:11 2011 @@ -8,6 +8,9 @@ Core and Builtins ----------------- +- Issue #8278: On Windows and with a NTFS filesystem, os.stat() and os.utime() + can now handle dates after 2038. + - Issue #10780: PyErr_SetFromWindowsErrWithFilename() and PyErr_SetExcFromWindowsErrWithFilename() decode the filename from the filesystem encoding instead of UTF-8. Modified: python/branches/py3k/Modules/posixmodule.c ============================================================================== --- python/branches/py3k/Modules/posixmodule.c (original) +++ python/branches/py3k/Modules/posixmodule.c Mon Jan 3 01:19:11 2011 @@ -976,18 +976,18 @@ int st_gid; int st_rdev; __int64 st_size; - int st_atime; + time_t st_atime; int st_atime_nsec; - int st_mtime; + time_t st_mtime; int st_mtime_nsec; - int st_ctime; + time_t st_ctime; int st_ctime_nsec; }; static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */ static void -FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, int *time_out, int* nsec_out) +FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) { /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */ /* Cannot simply cast and dereference in_ptr, @@ -995,12 +995,11 @@ __int64 in; memcpy(&in, in_ptr, sizeof(in)); *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ - /* XXX Win32 supports time stamps past 2038; we currently don't */ - *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, int); + *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); } static void -time_t_to_FILE_TIME(int time_in, int nsec_in, FILETIME *out_ptr) +time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) { /* XXX endianness */ __int64 out; @@ -3138,15 +3137,19 @@ #endif /* HAVE_UNAME */ static int -extract_time(PyObject *t, long* sec, long* usec) +extract_time(PyObject *t, time_t* sec, long* usec) { - long intval; + time_t intval; if (PyFloat_Check(t)) { double tval = PyFloat_AsDouble(t); - PyObject *intobj = Py_TYPE(t)->tp_as_number->nb_int(t); + PyObject *intobj = PyNumber_Long(t); if (!intobj) return -1; +#if SIZEOF_TIME_T > SIZEOF_LONG + intval = PyLong_AsUnsignedLongLongMask(intobj); +#else intval = PyLong_AsLong(intobj); +#endif Py_DECREF(intobj); if (intval == -1 && PyErr_Occurred()) return -1; @@ -3158,7 +3161,11 @@ *usec = 0; return 0; } +#if SIZEOF_TIME_T > SIZEOF_LONG + intval = PyLong_AsUnsignedLongLongMask(t); +#else intval = PyLong_AsLong(t); +#endif if (intval == -1 && PyErr_Occurred()) return -1; *sec = intval; @@ -3182,7 +3189,8 @@ PyObject *oapath; char *apath; HANDLE hFile; - long atimesec, mtimesec, ausec, musec; + time_t atimesec, mtimesec; + long ausec, musec; FILETIME atime, mtime; PyObject *result = NULL; @@ -3258,7 +3266,8 @@ PyObject *opath; char *path; - long atime, mtime, ausec, musec; + time_t atime, mtime; + long ausec, musec; int res; PyObject* arg; From python-checkins at python.org Mon Jan 3 01:20:00 2011 From: python-checkins at python.org (martin.v.loewis) Date: Mon, 3 Jan 2011 01:20:00 +0100 (CET) Subject: [Python-checkins] r87667 - python/branches/py3k/Lib/test/test_concurrent_futures.py Message-ID: <20110103002000.25061EE986@mail.python.org> Author: martin.v.loewis Date: Mon Jan 3 01:19:59 2011 New Revision: 87667 Log: Skip hanging test. Modified: python/branches/py3k/Lib/test/test_concurrent_futures.py Modified: python/branches/py3k/Lib/test/test_concurrent_futures.py ============================================================================== --- python/branches/py3k/Lib/test/test_concurrent_futures.py (original) +++ python/branches/py3k/Lib/test/test_concurrent_futures.py Mon Jan 3 01:19:59 2011 @@ -391,6 +391,7 @@ call1.close() call2.close() + @unittest.skip # XXX skip the test for now as it hangs def test_all_completed_some_already_completed(self): def wait_test(): while not future1._waiters: From python-checkins at python.org Mon Jan 3 01:40:04 2011 From: python-checkins at python.org (amaury.forgeotdarc) Date: Mon, 3 Jan 2011 01:40:04 +0100 (CET) Subject: [Python-checkins] r87668 - in python/branches/release31-maint: Lib/test/test_os.py Misc/NEWS Modules/posixmodule.c Message-ID: <20110103004004.8AB34EE986@mail.python.org> Author: amaury.forgeotdarc Date: Mon Jan 3 01:40:04 2011 New Revision: 87668 Log: Merged revisions 87666 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87666 | amaury.forgeotdarc | 2011-01-03 01:19:11 +0100 (lun., 03 janv. 2011) | 4 lines #8278: In the Windows implementation of stat() and utime(), use time_t instead of int. This gives support for dates after 2038, at least when compiled with VS2003 or later, where time_t is 64bit. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/test/test_os.py python/branches/release31-maint/Misc/NEWS python/branches/release31-maint/Modules/posixmodule.c Modified: python/branches/release31-maint/Lib/test/test_os.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_os.py (original) +++ python/branches/release31-maint/Lib/test/test_os.py Mon Jan 3 01:40:04 2011 @@ -352,6 +352,11 @@ os.utime(self.fname, (t1, t1)) self.assertEqual(os.stat(self.fname).st_mtime, t1) + def test_large_time(self): + t1 = 5000000000 # some day in 2128 + os.utime(self.fname, (t1, t1)) + self.assertEqual(os.stat(self.fname).st_mtime, t1) + def test_1686475(self): # Verify that an open file can be stat'ed try: Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Mon Jan 3 01:40:04 2011 @@ -10,6 +10,9 @@ Core and Builtins ----------------- +- Issue #8278: On Windows and with a NTFS filesystem, os.stat() and os.utime() + can now handle dates after 2038. + - Issue #4236: PyModule_Create2 now checks the import machinery directly rather than the Py_IsInitialized flag, avoiding a Fatal Python error in certain circumstances when an import is done in __del__. Modified: python/branches/release31-maint/Modules/posixmodule.c ============================================================================== --- python/branches/release31-maint/Modules/posixmodule.c (original) +++ python/branches/release31-maint/Modules/posixmodule.c Mon Jan 3 01:40:04 2011 @@ -939,18 +939,18 @@ int st_gid; int st_rdev; __int64 st_size; - int st_atime; + time_t st_atime; int st_atime_nsec; - int st_mtime; + time_t st_mtime; int st_mtime_nsec; - int st_ctime; + time_t st_ctime; int st_ctime_nsec; }; static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */ static void -FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, int *time_out, int* nsec_out) +FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) { /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */ /* Cannot simply cast and dereference in_ptr, @@ -958,12 +958,11 @@ __int64 in; memcpy(&in, in_ptr, sizeof(in)); *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ - /* XXX Win32 supports time stamps past 2038; we currently don't */ - *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, int); + *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); } static void -time_t_to_FILE_TIME(int time_in, int nsec_in, FILETIME *out_ptr) +time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) { /* XXX endianness */ __int64 out; @@ -2912,15 +2911,19 @@ #endif /* HAVE_UNAME */ static int -extract_time(PyObject *t, long* sec, long* usec) +extract_time(PyObject *t, time_t* sec, long* usec) { - long intval; + time_t intval; if (PyFloat_Check(t)) { double tval = PyFloat_AsDouble(t); - PyObject *intobj = Py_TYPE(t)->tp_as_number->nb_int(t); + PyObject *intobj = PyNumber_Long(t); if (!intobj) return -1; +#if SIZEOF_TIME_T > SIZEOF_LONG + intval = PyLong_AsUnsignedLongLongMask(intobj); +#else intval = PyLong_AsLong(intobj); +#endif Py_DECREF(intobj); if (intval == -1 && PyErr_Occurred()) return -1; @@ -2932,7 +2935,11 @@ *usec = 0; return 0; } +#if SIZEOF_TIME_T > SIZEOF_LONG + intval = PyLong_AsUnsignedLongLongMask(t); +#else intval = PyLong_AsLong(t); +#endif if (intval == -1 && PyErr_Occurred()) return -1; *sec = intval; @@ -2956,7 +2963,8 @@ PyObject *oapath; char *apath; HANDLE hFile; - long atimesec, mtimesec, ausec, musec; + time_t atimesec, mtimesec; + long ausec, musec; FILETIME atime, mtime; PyObject *result = NULL; @@ -3033,7 +3041,8 @@ PyObject *opath; char *path; - long atime, mtime, ausec, musec; + time_t atime, mtime; + long ausec, musec; int res; PyObject* arg; From python-checkins at python.org Mon Jan 3 01:50:57 2011 From: python-checkins at python.org (amaury.forgeotdarc) Date: Mon, 3 Jan 2011 01:50:57 +0100 (CET) Subject: [Python-checkins] r87669 - in python/branches/release27-maint: Lib/test/test_os.py Misc/NEWS Modules/posixmodule.c Message-ID: <20110103005057.A6ACEEE986@mail.python.org> Author: amaury.forgeotdarc Date: Mon Jan 3 01:50:57 2011 New Revision: 87669 Log: Merged revisions 87666 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87666 | amaury.forgeotdarc | 2011-01-03 01:19:11 +0100 (lun., 03 janv. 2011) | 4 lines #8278: In the Windows implementation of stat() and utime(), use time_t instead of int. This gives support for dates after 2038, at least when compiled with VS2003 or later, where time_t is 64bit. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/test/test_os.py python/branches/release27-maint/Misc/NEWS python/branches/release27-maint/Modules/posixmodule.c Modified: python/branches/release27-maint/Lib/test/test_os.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_os.py (original) +++ python/branches/release27-maint/Lib/test/test_os.py Mon Jan 3 01:50:57 2011 @@ -322,6 +322,11 @@ os.utime(self.fname, (t1, t1)) self.assertEqual(os.stat(self.fname).st_mtime, t1) + def test_large_time(self): + t1 = 5000000000 # some day in 2128 + os.utime(self.fname, (t1, t1)) + self.assertEqual(os.stat(self.fname).st_mtime, t1) + def test_1686475(self): # Verify that an open file can be stat'ed try: Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Mon Jan 3 01:50:57 2011 @@ -9,6 +9,9 @@ Core and Builtins ----------------- +- Issue #8278: On Windows and with a NTFS filesystem, os.stat() and os.utime() + can now handle dates after 2038. + - Issue #4236: Py_InitModule4 now checks the import machinery directly rather than the Py_IsInitialized flag, avoiding a Fatal Python error in certain circumstances when an import is done in __del__. Modified: python/branches/release27-maint/Modules/posixmodule.c ============================================================================== --- python/branches/release27-maint/Modules/posixmodule.c (original) +++ python/branches/release27-maint/Modules/posixmodule.c Mon Jan 3 01:50:57 2011 @@ -858,18 +858,18 @@ int st_gid; int st_rdev; __int64 st_size; - int st_atime; + time_t st_atime; int st_atime_nsec; - int st_mtime; + time_t st_mtime; int st_mtime_nsec; - int st_ctime; + time_t st_ctime; int st_ctime_nsec; }; static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */ static void -FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, int *time_out, int* nsec_out) +FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) { /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */ /* Cannot simply cast and dereference in_ptr, @@ -877,12 +877,11 @@ __int64 in; memcpy(&in, in_ptr, sizeof(in)); *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ - /* XXX Win32 supports time stamps past 2038; we currently don't */ - *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, int); + *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); } static void -time_t_to_FILE_TIME(int time_in, int nsec_in, FILETIME *out_ptr) +time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) { /* XXX endianness */ __int64 out; @@ -2727,15 +2726,19 @@ #endif /* HAVE_UNAME */ static int -extract_time(PyObject *t, long* sec, long* usec) +extract_time(PyObject *t, time_t* sec, long* usec) { - long intval; + time_t intval; if (PyFloat_Check(t)) { double tval = PyFloat_AsDouble(t); - PyObject *intobj = Py_TYPE(t)->tp_as_number->nb_int(t); + PyObject *intobj = PyNumber_Long(t); if (!intobj) return -1; +#if SIZEOF_TIME_T > SIZEOF_LONG + intval = PyInt_AsUnsignedLongLongMask(intobj); +#else intval = PyInt_AsLong(intobj); +#endif Py_DECREF(intobj); if (intval == -1 && PyErr_Occurred()) return -1; @@ -2747,7 +2750,11 @@ *usec = 0; return 0; } +#if SIZEOF_TIME_T > SIZEOF_LONG + intval = PyInt_AsUnsignedLongLongMask(t); +#else intval = PyInt_AsLong(t); +#endif if (intval == -1 && PyErr_Occurred()) return -1; *sec = intval; @@ -2770,7 +2777,8 @@ wchar_t *wpath = NULL; char *apath = NULL; HANDLE hFile; - long atimesec, mtimesec, ausec, musec; + time_t atimesec, mtimesec; + long ausec, musec; FILETIME atime, mtime; PyObject *result = NULL; @@ -2844,7 +2852,8 @@ #else /* MS_WINDOWS */ char *path = NULL; - long atime, mtime, ausec, musec; + time_t atime, mtime; + long ausec, musec; int res; PyObject* arg; From python-checkins at python.org Mon Jan 3 02:01:03 2011 From: python-checkins at python.org (brian.quinlan) Date: Mon, 3 Jan 2011 02:01:03 +0100 (CET) Subject: [Python-checkins] r87670 - python/branches/py3k-futures-on-windows Message-ID: <20110103010103.DBC4AEE98F@mail.python.org> Author: brian.quinlan Date: Mon Jan 3 02:01:03 2011 New Revision: 87670 Log: svnmerge init Modified: python/branches/py3k-futures-on-windows/ (props changed) From python-checkins at python.org Mon Jan 3 03:12:02 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 3 Jan 2011 03:12:02 +0100 (CET) Subject: [Python-checkins] r87671 - in python/branches/py3k: Lib/test/test_collections.py Modules/_collectionsmodule.c Message-ID: <20110103021202.5BFF4EE9AF@mail.python.org> Author: raymond.hettinger Date: Mon Jan 3 03:12:02 2011 New Revision: 87671 Log: Make C helper function more closely match the pure python version, and add tests. Modified: python/branches/py3k/Lib/test/test_collections.py python/branches/py3k/Modules/_collectionsmodule.c Modified: python/branches/py3k/Lib/test/test_collections.py ============================================================================== --- python/branches/py3k/Lib/test/test_collections.py (original) +++ python/branches/py3k/Lib/test/test_collections.py Mon Jan 3 03:12:02 2011 @@ -3,7 +3,7 @@ import unittest, doctest, operator import inspect from test import support -from collections import namedtuple, Counter, OrderedDict +from collections import namedtuple, Counter, OrderedDict, _count_elements from test import mapping_tests import pickle, copy from random import randrange, shuffle @@ -775,6 +775,19 @@ c.subtract('aaaabbcce') self.assertEqual(c, Counter(a=-1, b=0, c=-1, d=1, e=-1)) + def test_helper_function(self): + # two paths, one for real dicts and one for other mappings + elems = list('abracadabra') + + d = dict() + _count_elements(d, elems) + self.assertEqual(d, {'a': 5, 'r': 2, 'b': 2, 'c': 1, 'd': 1}) + + m = OrderedDict() + _count_elements(m, elems) + self.assertEqual(m, + OrderedDict([('a', 5), ('b', 2), ('r', 2), ('c', 1), ('d', 1)])) + class TestOrderedDict(unittest.TestCase): def test_init(self): Modified: python/branches/py3k/Modules/_collectionsmodule.c ============================================================================== --- python/branches/py3k/Modules/_collectionsmodule.c (original) +++ python/branches/py3k/Modules/_collectionsmodule.c Mon Jan 3 03:12:02 2011 @@ -1536,41 +1536,68 @@ if (!PyArg_UnpackTuple(args, "_count_elements", 2, 2, &mapping, &iterable)) return NULL; - if (!PyDict_Check(mapping)) { - PyErr_SetString(PyExc_TypeError, - "Expected mapping argument to be a dictionary"); - return NULL; - } - it = PyObject_GetIter(iterable); if (it == NULL) return NULL; + one = PyLong_FromLong(1); if (one == NULL) { Py_DECREF(it); return NULL; } - while (1) { - key = PyIter_Next(it); - if (key == NULL) { - if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) - PyErr_Clear(); - break; + + if (PyDict_CheckExact(mapping)) { + while (1) { + key = PyIter_Next(it); + if (key == NULL) { + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + else + break; + } + oldval = PyDict_GetItem(mapping, key); + if (oldval == NULL) { + if (PyDict_SetItem(mapping, key, one) == -1) + break; + } else { + newval = PyNumber_Add(oldval, one); + if (newval == NULL) + break; + if (PyDict_SetItem(mapping, key, newval) == -1) + break; + Py_CLEAR(newval); + } + Py_DECREF(key); } - oldval = PyDict_GetItem(mapping, key); - if (oldval == NULL) { - if (PyDict_SetItem(mapping, key, one) == -1) - break; - } else { - newval = PyNumber_Add(oldval, one); - if (newval == NULL) - break; - if (PyDict_SetItem(mapping, key, newval) == -1) + } else { + while (1) { + key = PyIter_Next(it); + if (key == NULL) { + if (PyErr_Occurred() && PyErr_ExceptionMatches(PyExc_StopIteration)) + PyErr_Clear(); + else + break; + } + oldval = PyObject_GetItem(mapping, key); + if (oldval == NULL) { + if (!PyErr_Occurred() || !PyErr_ExceptionMatches(PyExc_KeyError)) + break; + PyErr_Clear(); + Py_INCREF(one); + newval = one; + } else { + newval = PyNumber_Add(oldval, one); + Py_DECREF(oldval); + if (newval == NULL) + break; + } + if (PyObject_SetItem(mapping, key, newval) == -1) break; Py_CLEAR(newval); + Py_DECREF(key); } - Py_DECREF(key); } + Py_DECREF(it); Py_XDECREF(key); Py_XDECREF(newval); From python-checkins at python.org Mon Jan 3 03:44:14 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 3 Jan 2011 03:44:14 +0100 (CET) Subject: [Python-checkins] r87672 - python/branches/py3k/Lib/collections.py Message-ID: <20110103024414.BCBCBEE988@mail.python.org> Author: raymond.hettinger Date: Mon Jan 3 03:44:14 2011 New Revision: 87672 Log: Supply a reduce method for pickling. Modified: python/branches/py3k/Lib/collections.py Modified: python/branches/py3k/Lib/collections.py ============================================================================== --- python/branches/py3k/Lib/collections.py (original) +++ python/branches/py3k/Lib/collections.py Mon Jan 3 03:44:14 2011 @@ -539,6 +539,9 @@ 'Like dict.copy() but returns a Counter instance instead of a dict.' return Counter(self) + def __reduce__(self): + return self.__class__, (dict(self),) + def __delitem__(self, elem): 'Like dict.__delitem__() but does not raise KeyError for missing values.' if elem in self: From python-checkins at python.org Mon Jan 3 03:56:40 2011 From: python-checkins at python.org (brian.quinlan) Date: Mon, 3 Jan 2011 03:56:40 +0100 (CET) Subject: [Python-checkins] r87673 - python/branches/py3k/Lib/test/test_concurrent_futures.py Message-ID: <20110103025640.1BCDEEE9A8@mail.python.org> Author: brian.quinlan Date: Mon Jan 3 03:56:39 2011 New Revision: 87673 Log: Removes the 'Call' class which is used to control execution order and is unreliable on Windows Modified: python/branches/py3k/Lib/test/test_concurrent_futures.py Modified: python/branches/py3k/Lib/test/test_concurrent_futures.py ============================================================================== --- python/branches/py3k/Lib/test/test_concurrent_futures.py (original) +++ python/branches/py3k/Lib/test/test_concurrent_futures.py Mon Jan 3 03:56:39 2011 @@ -9,24 +9,16 @@ # without thread support. test.support.import_module('threading') -import io -import logging -import multiprocessing -import sys import threading import time import unittest -if sys.platform.startswith('win'): - import ctypes - import ctypes.wintypes - from concurrent import futures from concurrent.futures._base import ( - PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED, Future, - LOGGER, wait) + PENDING, RUNNING, CANCELLED, CANCELLED_AND_NOTIFIED, FINISHED, Future) import concurrent.futures.process + def create_future(state=PENDING, exception=None, result=None): f = Future() f._state = state @@ -34,6 +26,7 @@ f._result = result return f + PENDING_FUTURE = create_future(state=PENDING) RUNNING_FUTURE = create_future(state=RUNNING) CANCELLED_FUTURE = create_future(state=CANCELLED) @@ -41,166 +34,65 @@ EXCEPTION_FUTURE = create_future(state=FINISHED, exception=IOError()) SUCCESSFUL_FUTURE = create_future(state=FINISHED, result=42) + def mul(x, y): return x * y -class Call(object): - """A call that can be submitted to a future.Executor for testing. - - The call signals when it is called and waits for an event before finishing. - """ - CALL_LOCKS = {} - def _create_event(self): - if sys.platform.startswith('win'): - class SECURITY_ATTRIBUTES(ctypes.Structure): - _fields_ = [("nLength", ctypes.wintypes.DWORD), - ("lpSecurityDescriptor", ctypes.wintypes.LPVOID), - ("bInheritHandle", ctypes.wintypes.BOOL)] - - s = SECURITY_ATTRIBUTES() - s.nLength = ctypes.sizeof(s) - s.lpSecurityDescriptor = None - s.bInheritHandle = True - - handle = ctypes.windll.kernel32.CreateEventA(ctypes.pointer(s), - True, - False, - None) - assert handle is not None - return handle - else: - event = self.Event[0]() - self.CALL_LOCKS[id(event)] = event - return id(event) - - def _wait_on_event(self, handle): - if sys.platform.startswith('win'): - # WaitForSingleObject returns 0 if handle is signaled. - r = ctypes.windll.kernel32.WaitForSingleObject(handle, 60 * 1000) - if r != 0: - message = ( - 'WaitForSingleObject({}, ...) failed with {}, ' - 'GetLastError() = {}'.format( - handle, r, ctypes.GetLastError())) - logging.critical(message) - assert False, message - else: - self.CALL_LOCKS[handle].wait() - - def _signal_event(self, handle): - if sys.platform.startswith('win'): - r = ctypes.windll.kernel32.SetEvent(handle) # Returns 0 on failure. - if r == 0: - message = ( - 'SetEvent({}) failed with {}, GetLastError() = {}'.format( - handle, r, ctypes.GetLastError())) - logging.critical(message) - assert False, message - else: - self.CALL_LOCKS[handle].set() - - def __init__(self, Event, manual_finish=False, result=42): - self.Event = Event - self._called_event = self._create_event() - self._can_finish = self._create_event() - self._result = result +def sleep_and_raise(t): + time.sleep(t) + raise Exception('this is an exception') - if not manual_finish: - self._signal_event(self._can_finish) - def wait_on_called(self): - self._wait_on_event(self._called_event) - - def set_can(self): - self._signal_event(self._can_finish) - - def __call__(self): - self._signal_event(self._called_event) - self._wait_on_event(self._can_finish) - - return self._result - - def close(self): - self.set_can() - if sys.platform.startswith('win'): - ctypes.windll.kernel32.CloseHandle(self._called_event) - ctypes.windll.kernel32.CloseHandle(self._can_finish) - self._called_event = None - self._can_finish = None - else: - del self.CALL_LOCKS[self._called_event] - del self.CALL_LOCKS[self._can_finish] - -class ExceptionCall(Call): - def __call__(self): - self._signal_event(self._called_event) - self._wait_on_event(self._can_finish) - raise ZeroDivisionError() - -class MapCall(Call): - def __init__(self, Event, result=42): - super().__init__(Event, manual_finish=True, result=result) - - def __call__(self, manual_finish): - if manual_finish: - super().__call__() - return self._result - -class ExecutorShutdownTest(unittest.TestCase): - def test_run_after_shutdown(self): - self.executor.shutdown() - self.assertRaises(RuntimeError, - self.executor.submit, - pow, 2, 5) +class ExecutorMixin: + worker_count = 5 + def _prime_executor(self): + # Make sure that the executor is ready to do work before running the + # tests. This should reduce the probability of timeouts in the tests. + futures = [self.executor.submit(time.sleep, 0.1) + for _ in range(self.worker_count)] + for f in futures: + f.result() - def _start_some_futures(self): - call1 = Call(self.Event, manual_finish=True) - call2 = Call(self.Event, manual_finish=True) - call3 = Call(self.Event, manual_finish=True) - try: - self.executor.submit(call1) - self.executor.submit(call2) - self.executor.submit(call3) - - call1.wait_on_called() - call2.wait_on_called() - call3.wait_on_called() - - call1.set_can() - call2.set_can() - call3.set_can() - finally: - call1.close() - call2.close() - call3.close() - -class ThreadPoolMixin: - # wrap in tuple to prevent creation of instance methods - Event = (threading.Event,) +class ThreadPoolMixin(ExecutorMixin): def setUp(self): self.executor = futures.ThreadPoolExecutor(max_workers=5) + self._prime_executor() def tearDown(self): self.executor.shutdown(wait=True) -class ProcessPoolMixin: - # wrap in tuple to prevent creation of instance methods - Event = (multiprocessing.Event,) + +class ProcessPoolMixin(ExecutorMixin): def setUp(self): try: self.executor = futures.ProcessPoolExecutor(max_workers=5) except NotImplementedError as e: self.skipTest(str(e)) + self._prime_executor() def tearDown(self): self.executor.shutdown(wait=True) + +class ExecutorShutdownTest(unittest.TestCase): + def test_run_after_shutdown(self): + self.executor.shutdown() + self.assertRaises(RuntimeError, + self.executor.submit, + pow, 2, 5) + + class ThreadPoolShutdownTest(ThreadPoolMixin, ExecutorShutdownTest): + def _prime_executor(self): + pass + def test_threads_terminate(self): - self._start_some_futures() + self.executor.submit(mul, 21, 2) + self.executor.submit(mul, 6, 7) + self.executor.submit(mul, 3, 14) self.assertEqual(len(self.executor._threads), 3) self.executor.shutdown() for t in self.executor._threads: @@ -224,9 +116,15 @@ for t in threads: t.join() + class ProcessPoolShutdownTest(ProcessPoolMixin, ExecutorShutdownTest): + def _prime_executor(self): + pass + def test_processes_terminate(self): - self._start_some_futures() + self.executor.submit(mul, 21, 2) + self.executor.submit(mul, 6, 7) + self.executor.submit(mul, 3, 14) self.assertEqual(len(self.executor._processes), 5) processes = self.executor._processes self.executor.shutdown() @@ -236,11 +134,11 @@ def test_context_manager_shutdown(self): with futures.ProcessPoolExecutor(max_workers=5) as e: - executor = e + processes = e._processes self.assertEqual(list(e.map(abs, range(-5, 5))), [5, 4, 3, 2, 1, 0, 1, 2, 3, 4]) - for p in self.executor._processes: + for p in processes: p.join() def test_del_shutdown(self): @@ -256,288 +154,158 @@ class WaitTests(unittest.TestCase): def test_first_completed(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() - - call1 = Call(self.Event, manual_finish=True) - call2 = Call(self.Event, manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) + future1 = self.executor.submit(mul, 21, 2) + future2 = self.executor.submit(time.sleep, 5) - t = threading.Thread(target=wait_test) - t.start() - done, not_done = futures.wait( - [CANCELLED_FUTURE, future1, future2], - return_when=futures.FIRST_COMPLETED) - - self.assertEqual(set([future1]), done) - self.assertEqual(set([CANCELLED_FUTURE, future2]), not_done) - finally: - call1.close() - call2.close() - - def test_first_completed_one_already_completed(self): - call1 = Call(self.Event, manual_finish=True) - try: - future1 = self.executor.submit(call1) + done, not_done = futures.wait( + [CANCELLED_FUTURE, future1, future2], + return_when=futures.FIRST_COMPLETED) + + self.assertEqual(set([future1]), done) + self.assertEqual(set([CANCELLED_FUTURE, future2]), not_done) + + def test_first_completed_some_already_completed(self): + future1 = self.executor.submit(time.sleep, 2) + + finished, pending = futures.wait( + [CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE, future1], + return_when=futures.FIRST_COMPLETED) - finished, pending = futures.wait( - [SUCCESSFUL_FUTURE, future1], - return_when=futures.FIRST_COMPLETED) - - self.assertEqual(set([SUCCESSFUL_FUTURE]), finished) - self.assertEqual(set([future1]), pending) - finally: - call1.close() + self.assertEqual( + set([CANCELLED_AND_NOTIFIED_FUTURE, SUCCESSFUL_FUTURE]), + finished) + self.assertEqual(set([future1]), pending) def test_first_exception(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() - call2.set_can() - - call1 = Call(self.Event, manual_finish=True) - call2 = ExceptionCall(self.Event, manual_finish=True) - call3 = Call(self.Event, manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) - future3 = self.executor.submit(call3) - - t = threading.Thread(target=wait_test) - t.start() - finished, pending = futures.wait( - [future1, future2, future3], - return_when=futures.FIRST_EXCEPTION) - - self.assertEqual(set([future1, future2]), finished) - self.assertEqual(set([future3]), pending) - finally: - call1.close() - call2.close() - call3.close() + future1 = self.executor.submit(mul, 2, 21) + future2 = self.executor.submit(sleep_and_raise, 5) + future3 = self.executor.submit(time.sleep, 10) + + finished, pending = futures.wait( + [future1, future2, future3], + return_when=futures.FIRST_EXCEPTION) - def test_first_exception_some_already_complete(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() + self.assertEqual(set([future1, future2]), finished) + self.assertEqual(set([future3]), pending) - call1 = ExceptionCall(self.Event, manual_finish=True) - call2 = Call(self.Event, manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) + def test_first_exception_some_already_complete(self): + future1 = self.executor.submit(divmod, 21, 0) + future2 = self.executor.submit(time.sleep, 5) - t = threading.Thread(target=wait_test) - t.start() - finished, pending = futures.wait( - [SUCCESSFUL_FUTURE, - CANCELLED_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - future1, future2], - return_when=futures.FIRST_EXCEPTION) - - self.assertEqual(set([SUCCESSFUL_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - future1]), finished) - self.assertEqual(set([CANCELLED_FUTURE, future2]), pending) - - - finally: - call1.close() - call2.close() + finished, pending = futures.wait( + [SUCCESSFUL_FUTURE, + CANCELLED_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + future1, future2], + return_when=futures.FIRST_EXCEPTION) + + self.assertEqual(set([SUCCESSFUL_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + future1]), finished) + self.assertEqual(set([CANCELLED_FUTURE, future2]), pending) def test_first_exception_one_already_failed(self): - call1 = Call(self.Event, manual_finish=True) - try: - future1 = self.executor.submit(call1) + future1 = self.executor.submit(time.sleep, 2) - finished, pending = futures.wait( - [EXCEPTION_FUTURE, future1], - return_when=futures.FIRST_EXCEPTION) - - self.assertEqual(set([EXCEPTION_FUTURE]), finished) - self.assertEqual(set([future1]), pending) - finally: - call1.close() + finished, pending = futures.wait( + [EXCEPTION_FUTURE, future1], + return_when=futures.FIRST_EXCEPTION) - def test_all_completed(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() - call2.set_can() + self.assertEqual(set([EXCEPTION_FUTURE]), finished) + self.assertEqual(set([future1]), pending) - call1 = Call(self.Event, manual_finish=True) - call2 = Call(self.Event, manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) + def test_all_completed(self): + future1 = self.executor.submit(divmod, 2, 0) + future2 = self.executor.submit(mul, 2, 21) - t = threading.Thread(target=wait_test) - t.start() - finished, pending = futures.wait( - [future1, future2], - return_when=futures.ALL_COMPLETED) - - self.assertEqual(set([future1, future2]), finished) - self.assertEqual(set(), pending) - finally: - call1.close() - call2.close() - - @unittest.skip # XXX skip the test for now as it hangs - def test_all_completed_some_already_completed(self): - def wait_test(): - while not future1._waiters: - pass - - future4.cancel() - call1.set_can() - call2.set_can() - call3.set_can() - - self.assertLessEqual( - futures.process.EXTRA_QUEUED_CALLS, - 1, - 'this test assumes that future4 will be cancelled before it is ' - 'queued to run - which might not be the case if ' - 'ProcessPoolExecutor is too aggresive in scheduling futures') - call1 = Call(self.Event, manual_finish=True) - call2 = Call(self.Event, manual_finish=True) - call3 = Call(self.Event, manual_finish=True) - call4 = Call(self.Event, manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) - future3 = self.executor.submit(call3) - future4 = self.executor.submit(call4) - - t = threading.Thread(target=wait_test) - t.start() - finished, pending = futures.wait( - [SUCCESSFUL_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - future1, future2, future3, future4], - return_when=futures.ALL_COMPLETED) - - self.assertEqual(set([SUCCESSFUL_FUTURE, - CANCELLED_AND_NOTIFIED_FUTURE, - future1, future2, future3, future4]), - finished) - self.assertEqual(set(), pending) - finally: - call1.close() - call2.close() - call3.close() - call4.close() + finished, pending = futures.wait( + [SUCCESSFUL_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + future1, + future2], + return_when=futures.ALL_COMPLETED) + + self.assertEqual(set([SUCCESSFUL_FUTURE, + CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + future1, + future2]), finished) + self.assertEqual(set(), pending) def test_timeout(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() - - call1 = Call(self.Event, manual_finish=True) - call2 = Call(self.Event, manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) - - t = threading.Thread(target=wait_test) - t.start() - finished, pending = futures.wait( - [CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1, future2], - timeout=5, - return_when=futures.ALL_COMPLETED) - - self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1]), finished) - self.assertEqual(set([future2]), pending) - + future1 = self.executor.submit(mul, 6, 7) + future2 = self.executor.submit(time.sleep, 10) - finally: - call1.close() - call2.close() + finished, pending = futures.wait( + [CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE, + future1, future2], + timeout=5, + return_when=futures.ALL_COMPLETED) + + self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE, + future1]), finished) + self.assertEqual(set([future2]), pending) class ThreadPoolWaitTests(ThreadPoolMixin, WaitTests): pass + class ProcessPoolWaitTests(ProcessPoolMixin, WaitTests): pass + class AsCompletedTests(unittest.TestCase): # TODO(brian at sweetapp.com): Should have a test with a non-zero timeout. def test_no_timeout(self): - def wait_test(): - while not future1._waiters: - pass - call1.set_can() - call2.set_can() + future1 = self.executor.submit(mul, 2, 21) + future2 = self.executor.submit(mul, 7, 6) - call1 = Call(self.Event, manual_finish=True) - call2 = Call(self.Event, manual_finish=True) - try: - future1 = self.executor.submit(call1) - future2 = self.executor.submit(call2) + completed = set(futures.as_completed( + [CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE, + future1, future2])) + self.assertEqual(set( + [CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE, + future1, future2]), + completed) - t = threading.Thread(target=wait_test) - t.start() - completed = set(futures.as_completed( - [CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1, future2])) - self.assertEqual(set( + def test_zero_timeout(self): + future1 = self.executor.submit(time.sleep, 2) + completed_futures = set() + try: + for future in futures.as_completed( [CANCELLED_AND_NOTIFIED_FUTURE, EXCEPTION_FUTURE, SUCCESSFUL_FUTURE, - future1, future2]), - completed) - finally: - call1.close() - call2.close() + future1], + timeout=0): + completed_futures.add(future) + except futures.TimeoutError: + pass + + self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, + EXCEPTION_FUTURE, + SUCCESSFUL_FUTURE]), + completed_futures) - def test_zero_timeout(self): - call1 = Call(self.Event, manual_finish=True) - try: - future1 = self.executor.submit(call1) - completed_futures = set() - try: - for future in futures.as_completed( - [CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE, - future1], - timeout=0): - completed_futures.add(future) - except futures.TimeoutError: - pass - - self.assertEqual(set([CANCELLED_AND_NOTIFIED_FUTURE, - EXCEPTION_FUTURE, - SUCCESSFUL_FUTURE]), - completed_futures) - finally: - call1.close() class ThreadPoolAsCompletedTests(ThreadPoolMixin, AsCompletedTests): pass + class ProcessPoolAsCompletedTests(ProcessPoolMixin, AsCompletedTests): pass + class ExecutorTest(unittest.TestCase): # Executor.shutdown() and context manager usage is tested by # ExecutorShutdownTest. @@ -562,28 +330,27 @@ def test_map_timeout(self): results = [] - timeout_call = MapCall(self.Event) try: - try: - for i in self.executor.map(timeout_call, - [False, False, True], - timeout=5): - results.append(i) - except futures.TimeoutError: - pass - else: - self.fail('expected TimeoutError') - finally: - timeout_call.close() + for i in self.executor.map(time.sleep, + [0, 0, 10], + timeout=5): + results.append(i) + except futures.TimeoutError: + pass + else: + self.fail('expected TimeoutError') + + self.assertEqual([None, None], results) - self.assertEqual([42, 42], results) class ThreadPoolExecutorTest(ThreadPoolMixin, ExecutorTest): pass + class ProcessPoolExecutorTest(ProcessPoolMixin, ExecutorTest): pass + class FutureTests(unittest.TestCase): def test_done_callback_with_result(self): callback_result = None From solipsis at pitrou.net Mon Jan 3 04:54:45 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 03 Jan 2011 04:54:45 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r87671): sum=0 Message-ID: py3k results for svn r87671 (hg cset efcccbb0beb4) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflognBBJ5u', '-x'] From python-checkins at python.org Mon Jan 3 09:50:48 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 3 Jan 2011 09:50:48 +0100 (CET) Subject: [Python-checkins] r87675 - python/branches/release31-maint/Lib/collections.py Message-ID: <20110103085048.90687EE993@mail.python.org> Author: raymond.hettinger Date: Mon Jan 3 09:50:48 2011 New Revision: 87675 Log: Backport r87672 and r87615, improving tests, using super() instead of direct parent references, and using __reduce__ method for pickling. Modified: python/branches/release31-maint/Lib/collections.py Modified: python/branches/release31-maint/Lib/collections.py ============================================================================== --- python/branches/release31-maint/Lib/collections.py (original) +++ python/branches/release31-maint/Lib/collections.py Mon Jan 3 09:50:48 2011 @@ -298,16 +298,16 @@ or multiset. Elements are stored as dictionary keys and their counts are stored as dictionary values. - >>> c = Counter('abracadabra') # count elements from a string + >>> c = Counter('abcdeabcdabcaba') # count elements from a string >>> c.most_common(3) # three most common elements - [('a', 5), ('r', 2), ('b', 2)] + [('a', 5), ('b', 4), ('c', 3)] >>> sorted(c) # list all unique elements - ['a', 'b', 'c', 'd', 'r'] + ['a', 'b', 'c', 'd', 'e'] >>> ''.join(sorted(c.elements())) # list elements with repetitions - 'aaaaabbcdrr' + 'aaaaabbbbcccdde' >>> sum(c.values()) # total of all counts - 11 + 15 >>> c['a'] # count of letter 'a' 5 @@ -315,8 +315,8 @@ ... c[elem] += 1 # by adding 1 to each element's count >>> c['a'] # now there are seven 'a' 7 - >>> del c['r'] # remove all 'r' - >>> c['r'] # now there are zero 'r' + >>> del c['b'] # remove all 'b' + >>> c['b'] # now there are zero 'b' 0 >>> d = Counter('simsalabim') # make another counter @@ -355,6 +355,7 @@ >>> c = Counter(a=4, b=2) # a new counter from keyword args ''' + super().__init__() self.update(iterable, **kwds) def __missing__(self, key): @@ -366,8 +367,8 @@ '''List the n most common elements and their counts from the most common to the least. If n is None, then list all element counts. - >>> Counter('abracadabra').most_common(3) - [('a', 5), ('r', 2), ('b', 2)] + >>> Counter('abcdeabcdabcaba').most_common(3) + [('a', 5), ('b', 4), ('c', 3)] ''' # Emulate Bag.sortedByCount from Smalltalk @@ -433,7 +434,7 @@ for elem, count in iterable.items(): self[elem] = count + self_get(elem, 0) else: - dict.update(self, iterable) # fast path when counter is empty + super().update(iterable) # fast path when counter is empty else: self_get = self.get for elem in iterable: @@ -445,10 +446,13 @@ 'Like dict.copy() but returns a Counter instance instead of a dict.' return Counter(self) + def __reduce__(self): + return self.__class__, (dict(self),) + def __delitem__(self, elem): 'Like dict.__delitem__() but does not raise KeyError for missing values.' if elem in self: - dict.__delitem__(self, elem) + super().__delitem__(elem) def __repr__(self): if not self: From python-checkins at python.org Mon Jan 3 09:59:18 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 3 Jan 2011 09:59:18 +0100 (CET) Subject: [Python-checkins] r87676 - python/branches/release27-maint/Lib/collections.py Message-ID: <20110103085918.6A791EE9A7@mail.python.org> Author: raymond.hettinger Date: Mon Jan 3 09:59:18 2011 New Revision: 87676 Log: Backport r87672 and r87615, improving tests, using super() instead of direct parent references, and using __reduce__ method for pickling. Modified: python/branches/release27-maint/Lib/collections.py Modified: python/branches/release27-maint/Lib/collections.py ============================================================================== --- python/branches/release27-maint/Lib/collections.py (original) +++ python/branches/release27-maint/Lib/collections.py Mon Jan 3 09:59:18 2011 @@ -344,16 +344,16 @@ or multiset. Elements are stored as dictionary keys and their counts are stored as dictionary values. - >>> c = Counter('abracadabra') # count elements from a string + >>> c = Counter('abcdeabcdabcaba') # count elements from a string >>> c.most_common(3) # three most common elements - [('a', 5), ('r', 2), ('b', 2)] + [('a', 5), ('b', 4), ('c', 3)] >>> sorted(c) # list all unique elements - ['a', 'b', 'c', 'd', 'r'] + ['a', 'b', 'c', 'd', 'e'] >>> ''.join(sorted(c.elements())) # list elements with repetitions - 'aaaaabbcdrr' + 'aaaaabbbbcccdde' >>> sum(c.values()) # total of all counts - 11 + 15 >>> c['a'] # count of letter 'a' 5 @@ -361,8 +361,8 @@ ... c[elem] += 1 # by adding 1 to each element's count >>> c['a'] # now there are seven 'a' 7 - >>> del c['r'] # remove all 'r' - >>> c['r'] # now there are zero 'r' + >>> del c['b'] # remove all 'b' + >>> c['b'] # now there are zero 'b' 0 >>> d = Counter('simsalabim') # make another counter @@ -401,6 +401,7 @@ >>> c = Counter(a=4, b=2) # a new counter from keyword args ''' + super(Counter, self).__init__() self.update(iterable, **kwds) def __missing__(self, key): @@ -412,8 +413,8 @@ '''List the n most common elements and their counts from the most common to the least. If n is None, then list all element counts. - >>> Counter('abracadabra').most_common(3) - [('a', 5), ('r', 2), ('b', 2)] + >>> Counter('abcdeabcdabcaba').most_common(3) + [('a', 5), ('b', 4), ('c', 3)] ''' # Emulate Bag.sortedByCount from Smalltalk @@ -479,7 +480,7 @@ for elem, count in iterable.iteritems(): self[elem] = self_get(elem, 0) + count else: - dict.update(self, iterable) # fast path when counter is empty + super(Counter, self).update(iterable) # fast path when counter is empty else: self_get = self.get for elem in iterable: @@ -518,10 +519,13 @@ 'Like dict.copy() but returns a Counter instance instead of a dict.' return Counter(self) + def __reduce__(self): + return self.__class__, (dict(self),) + def __delitem__(self, elem): 'Like dict.__delitem__() but does not raise KeyError for missing values.' if elem in self: - dict.__delitem__(self, elem) + super(Counter, self).__delitem__(elem) def __repr__(self): if not self: From python-checkins at python.org Mon Jan 3 10:47:10 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 3 Jan 2011 10:47:10 +0100 (CET) Subject: [Python-checkins] r87677 - python/branches/py3k/py3rsa.py Message-ID: <20110103094710.07327EE993@mail.python.org> Author: senthil.kumaran Date: Mon Jan 3 10:47:09 2011 New Revision: 87677 Log: py3k implmentation of RSA algorithm, Added: python/branches/py3k/py3rsa.py (contents, props changed) Added: python/branches/py3k/py3rsa.py ============================================================================== --- (empty file) +++ python/branches/py3k/py3rsa.py Mon Jan 3 10:47:09 2011 @@ -0,0 +1,181 @@ +# Copyright (c) 2010 Russell Dias +# Licensed under the MIT licence. +# http://www.inversezen.com +# +# This is an implementation of the RSA public key +# encryption written in Python by Russell Dias + +__author__ = 'Russell Dias // inversezen.com' +# Py3k port done by Senthil (senthil at uthcode.com) +__date__ = '05/12/2010' +__version__ = '0.0.1' + +import random +from math import log + +def gcd(u, v): + """ The Greatest Common Divisor, returns + the largest positive integer that divides + u with v without a remainder. + """ + while v: + u, v = u, u % v + return u + +def eec(u, v): + """ The Extended Eculidean Algorithm + For u and v this algorithm finds (u1, u2, u3) + such that uu1 + vu2 = u3 = gcd(u, v) + + We also use auxiliary vectors (v1, v2, v3) and + (tmp1, tmp2, tmp3) + """ + (u1, u2, u3) = (1, 0, u) + (v1, v2, v3) = (0, 1, v) + while (v3 != 0): + quotient = u3 // v3 + tmp1 = u1 - quotient * v1 + tmp2 = u2 - quotient * v2 + tmp3 = u3 - quotient * v3 + (u1, u2, u3) = (v1, v2, v3) + (v1, v2, v3) = (tmp1, tmp2, tmp3) + return u3, u1, u2 + +def stringEncode(string): + """ Brandon Sterne's algorithm to convert + string to long + """ + message = 0 + messageCount = len(string) - 1 + + for letter in string: + message += (256**messageCount) * ord(letter) + messageCount -= 1 + return message + +def stringDecode(number): + """ Convert long back to string + """ + + letters = [] + text = '' + integer = int(log(number, 256)) + + while(integer >= 0): + letter = number // (256**integer) + letters.append(chr(letter)) + number -= letter * (256**integer) + integer -= 1 + for char in letters: + text += char + + return text + +def split_to_odd(n): + """ Return values 2 ^ k, such that 2^k*q = n; + or an odd integer to test for primiality + Let n be an odd prime. Then n-1 is even, + where k is a positive integer. + """ + k = 0 + while (n > 0) and (n % 2 == 0): + k += 1 + n >>= 1 + return (k, n) + +def prime(a, q, k, n): + if pow(a, q, n) == 1: + return True + elif (n - 1) in [pow(a, q*(2**j), n) for j in range(k)]: + return True + else: + return False + +def miller_rabin(n, trials): + """ + There is still a small chance that n will return a + false positive. To reduce risk, it is recommended to use + more trials. + """ + # 2^k * q = n - 1; q is an odd int + (k, q) = split_to_odd(n - 1) + + for trial in range(trials): + a = random.randint(2, n-1) + if not prime(a, q, k, n): + return False + return True + +def get_prime(k): + """ Generate prime of size k bits, with 50 tests + to ensure accuracy. + """ + prime = 0 + while (prime == 0): + prime = random.randrange(pow(2,k//2-1) + 1, pow(2, k//2), 2) + if not miller_rabin(prime, 50): + prime = 0 + return prime + +def modular_inverse(a, m): + """ To calculate the decryption exponent such that + (d * e) mod phi(N) = 1 OR g == 1 in our implementation. + Where m is Phi(n) (PHI = (p-1) * (q-1) ) + + s % m or d (decryption exponent) is the multiplicative inverse of + the encryption exponent e. + """ + g, s, t = eec(a, m) + if g == 1: + return s % m + else: + return None + +def key_gen(bits): + """ The public encryption exponent e, + can be an artibrary prime number. + + Obviously, the higher the number, + the more secure the key pairs are. + """ + e = 17 + p = get_prime(bits) + q = get_prime(bits) + d = modular_inverse(e, (p-1)*(q-1)) + return p*q,d,e + +def write_to_file(e, d, n): + """ Write our public and private keys to file + """ + public = open("publicKey", "w") + public.write(str(e)) + public.write("\n") + public.write(str(n)) + public.close() + + private = open("privateKey", "w") + private.write(str(d)) + private.write("\n") + private.write(str(n)) + private.close() + + +if __name__ == '__main__': + bits = input("Enter the size of your key pairs, in bits: ") + + n, d, e = key_gen(int(bits)) + + #Write keys to file + write_to_file(e, d, n) + + print("Your keys pairs have been saved to file") + + m = input("Enter the message you would like to encrypt: ") + + m = stringEncode(m) + encrypted = pow(m, e, n) + + print("Your encrypted message is: %s" % encrypted) + decrypted = pow(encrypted, d, n) + message = stringDecode(decrypted) + print("You message decrypted is: %s" % message) From orsenthil at gmail.com Mon Jan 3 10:57:53 2011 From: orsenthil at gmail.com (Senthil Kumaran) Date: Mon, 3 Jan 2011 17:57:53 +0800 Subject: [Python-checkins] r87677 - python/branches/py3k/py3rsa.py In-Reply-To: <20110103094710.07327EE993@mail.python.org> References: <20110103094710.07327EE993@mail.python.org> Message-ID: Sorry Folks. I commited to a wrong respository. I was testing it against the latest version py3k and I thought i moved it back to my original respository. Apologize for the trouble and I shall remove it immediately. -- Senthil On Mon, Jan 3, 2011 at 5:47 PM, senthil.kumaran wrote: > Author: senthil.kumaran > Date: Mon Jan ?3 10:47:09 2011 > New Revision: 87677 > > Log: > py3k implmentation of RSA algorithm, > > > > Added: > ? python/branches/py3k/py3rsa.py ? (contents, props changed) > > Added: python/branches/py3k/py3rsa.py > ============================================================================== > --- (empty file) > +++ python/branches/py3k/py3rsa.py ? ? ?Mon Jan ?3 10:47:09 2011 > @@ -0,0 +1,181 @@ > +# Copyright (c) 2010 Russell Dias > +# Licensed under the MIT licence. > +# http://www.inversezen.com > +# > +# This is an implementation of the RSA public key > +# encryption written in Python by Russell Dias > + > +__author__ = 'Russell Dias // inversezen.com' > +# Py3k port done by Senthil (senthil at uthcode.com) > +__date__ = '05/12/2010' > +__version__ = '0.0.1' > + > +import random > +from math import log > + > +def gcd(u, v): > + ? ?""" The Greatest Common Divisor, returns > + ? ? ? ?the largest positive integer that divides > + ? ? ? ?u with v without a remainder. > + ? ?""" > + ? ?while v: > + ? ? ? ?u, v = u, u % v > + ? ?return u > + > +def eec(u, v): > + ? ?""" The Extended Eculidean Algorithm > + ? ? ? ?For u and v this algorithm finds (u1, u2, u3) > + ? ? ? ?such that uu1 + vu2 = u3 = gcd(u, v) > + > + ? ? ? ?We also use auxiliary vectors (v1, v2, v3) and > + ? ? ? ?(tmp1, tmp2, tmp3) > + ? ?""" > + ? ?(u1, u2, u3) = (1, 0, u) > + ? ?(v1, v2, v3) = (0, 1, v) > + ? ?while (v3 != 0): > + ? ? ? ?quotient = u3 // v3 > + ? ? ? ?tmp1 = u1 - quotient * v1 > + ? ? ? ?tmp2 = u2 - quotient * v2 > + ? ? ? ?tmp3 = u3 - quotient * v3 > + ? ? ? ?(u1, u2, u3) = (v1, v2, v3) > + ? ? ? ?(v1, v2, v3) = (tmp1, tmp2, tmp3) > + ? ?return u3, u1, u2 > + > +def stringEncode(string): > + ? ?""" Brandon Sterne's algorithm to convert > + ? ? ? ?string to long > + ? ?""" > + ? ?message = 0 > + ? ?messageCount = len(string) - 1 > + > + ? ?for letter in string: > + ? ? ? ?message += (256**messageCount) * ord(letter) > + ? ? ? ?messageCount -= 1 > + ? ?return message > + > +def stringDecode(number): > + ? ?""" Convert long back to string > + ? ?""" > + > + ? ?letters = [] > + ? ?text = '' > + ? ?integer = int(log(number, 256)) > + > + ? ?while(integer >= 0): > + ? ? ? ?letter = number // (256**integer) > + ? ? ? ?letters.append(chr(letter)) > + ? ? ? ?number -= letter * (256**integer) > + ? ? ? ?integer -= 1 > + ? ?for char in letters: > + ? ? ? ?text += char > + > + ? ?return text > + > +def split_to_odd(n): > + ? ?""" Return values 2 ^ k, such that 2^k*q = n; > + ? ? ? ?or an odd integer to test for primiality > + ? ? ? ?Let n be an odd prime. Then n-1 is even, > + ? ? ? ?where k is a positive integer. > + ? ?""" > + ? ?k = 0 > + ? ?while (n > 0) and (n % 2 == 0): > + ? ? ? ?k += 1 > + ? ? ? ?n >>= 1 > + ? ?return (k, n) > + > +def prime(a, q, k, n): > + ? ?if pow(a, q, n) == 1: > + ? ? ? ?return True > + ? ?elif (n - 1) in [pow(a, q*(2**j), n) for j in range(k)]: > + ? ? ? ?return True > + ? ?else: > + ? ? ? ?return False > + > +def miller_rabin(n, trials): > + ? ?""" > + ? ? ? ?There is still a small chance that n will return a > + ? ? ? ?false positive. To reduce risk, it is recommended to use > + ? ? ? ?more trials. > + ? ?""" > + ? ?# 2^k * q = n - 1; q is an odd int > + ? ?(k, q) = split_to_odd(n - 1) > + > + ? ?for trial in range(trials): > + ? ? ? ?a = random.randint(2, n-1) > + ? ? ? ?if not prime(a, q, k, n): > + ? ? ? ? ? ?return False > + ? ?return True > + > +def get_prime(k): > + ? ?""" Generate prime of size k bits, with 50 tests > + ? ? ? ?to ensure accuracy. > + ? ?""" > + ? ?prime = 0 > + ? ?while (prime == 0): > + ? ? ? ?prime = random.randrange(pow(2,k//2-1) + 1, pow(2, k//2), 2) > + ? ? ? ?if not miller_rabin(prime, 50): > + ? ? ? ? ? ?prime = 0 > + ? ?return prime > + > +def modular_inverse(a, m): > + ? ?""" To calculate the decryption exponent such that > + ? ? ? ?(d * e) mod phi(N) = 1 OR g == 1 in our implementation. > + ? ? ? ?Where m is Phi(n) (PHI = (p-1) * (q-1) ) > + > + ? ? ? ?s % m or d (decryption exponent) is the multiplicative inverse of > + ? ? ? ?the encryption exponent e. > + ? ?""" > + ? ?g, s, t = eec(a, m) > + ? ?if g == 1: > + ? ? ? ?return s % m > + ? ?else: > + ? ? ? ?return None > + > +def key_gen(bits): > + ? ?""" The public encryption exponent e, > + ? ? ? ?can be an artibrary prime number. > + > + ? ? ? ?Obviously, the higher the number, > + ? ? ? ?the more secure the key pairs are. > + ? ?""" > + ? ?e = 17 > + ? ?p = get_prime(bits) > + ? ?q = get_prime(bits) > + ? ?d = modular_inverse(e, (p-1)*(q-1)) > + ? ?return p*q,d,e > + > +def write_to_file(e, d, n): > + ? ?""" Write our public and private keys to file > + ? ?""" > + ? ?public = open("publicKey", "w") > + ? ?public.write(str(e)) > + ? ?public.write("\n") > + ? ?public.write(str(n)) > + ? ?public.close() > + > + ? ?private = open("privateKey", "w") > + ? ?private.write(str(d)) > + ? ?private.write("\n") > + ? ?private.write(str(n)) > + ? ?private.close() > + > + > +if __name__ == '__main__': > + ? ?bits = input("Enter the size of your key pairs, in bits: ") > + > + ? ?n, d, e = key_gen(int(bits)) > + > + ? ?#Write keys to file > + ? ?write_to_file(e, d, n) > + > + ? ?print("Your keys pairs have been saved to file") > + > + ? ?m = input("Enter the message you would like to encrypt: ") > + > + ? ?m = stringEncode(m) > + ? ?encrypted = pow(m, e, n) > + > + ? ?print("Your encrypted message is: %s" % encrypted) > + ? ?decrypted = pow(encrypted, d, n) > + ? ?message = stringDecode(decrypted) > + ? ?print("You message decrypted is: %s" % message) > _______________________________________________ > Python-checkins mailing list > Python-checkins at python.org > http://mail.python.org/mailman/listinfo/python-checkins > -- Senthil From python-checkins at python.org Mon Jan 3 11:11:08 2011 From: python-checkins at python.org (senthil.kumaran) Date: Mon, 3 Jan 2011 11:11:08 +0100 (CET) Subject: [Python-checkins] r87678 - python/branches/py3k/py3rsa.py Message-ID: <20110103101108.1421CEE99A@mail.python.org> Author: senthil.kumaran Date: Mon Jan 3 11:11:07 2011 New Revision: 87678 Log: Reverting the mistaken commit r87677. Checked in py3rsa.py by mistake. Removed: python/branches/py3k/py3rsa.py Deleted: python/branches/py3k/py3rsa.py ============================================================================== --- python/branches/py3k/py3rsa.py Mon Jan 3 11:11:07 2011 +++ (empty file) @@ -1,181 +0,0 @@ -# Copyright (c) 2010 Russell Dias -# Licensed under the MIT licence. -# http://www.inversezen.com -# -# This is an implementation of the RSA public key -# encryption written in Python by Russell Dias - -__author__ = 'Russell Dias // inversezen.com' -# Py3k port done by Senthil (senthil at uthcode.com) -__date__ = '05/12/2010' -__version__ = '0.0.1' - -import random -from math import log - -def gcd(u, v): - """ The Greatest Common Divisor, returns - the largest positive integer that divides - u with v without a remainder. - """ - while v: - u, v = u, u % v - return u - -def eec(u, v): - """ The Extended Eculidean Algorithm - For u and v this algorithm finds (u1, u2, u3) - such that uu1 + vu2 = u3 = gcd(u, v) - - We also use auxiliary vectors (v1, v2, v3) and - (tmp1, tmp2, tmp3) - """ - (u1, u2, u3) = (1, 0, u) - (v1, v2, v3) = (0, 1, v) - while (v3 != 0): - quotient = u3 // v3 - tmp1 = u1 - quotient * v1 - tmp2 = u2 - quotient * v2 - tmp3 = u3 - quotient * v3 - (u1, u2, u3) = (v1, v2, v3) - (v1, v2, v3) = (tmp1, tmp2, tmp3) - return u3, u1, u2 - -def stringEncode(string): - """ Brandon Sterne's algorithm to convert - string to long - """ - message = 0 - messageCount = len(string) - 1 - - for letter in string: - message += (256**messageCount) * ord(letter) - messageCount -= 1 - return message - -def stringDecode(number): - """ Convert long back to string - """ - - letters = [] - text = '' - integer = int(log(number, 256)) - - while(integer >= 0): - letter = number // (256**integer) - letters.append(chr(letter)) - number -= letter * (256**integer) - integer -= 1 - for char in letters: - text += char - - return text - -def split_to_odd(n): - """ Return values 2 ^ k, such that 2^k*q = n; - or an odd integer to test for primiality - Let n be an odd prime. Then n-1 is even, - where k is a positive integer. - """ - k = 0 - while (n > 0) and (n % 2 == 0): - k += 1 - n >>= 1 - return (k, n) - -def prime(a, q, k, n): - if pow(a, q, n) == 1: - return True - elif (n - 1) in [pow(a, q*(2**j), n) for j in range(k)]: - return True - else: - return False - -def miller_rabin(n, trials): - """ - There is still a small chance that n will return a - false positive. To reduce risk, it is recommended to use - more trials. - """ - # 2^k * q = n - 1; q is an odd int - (k, q) = split_to_odd(n - 1) - - for trial in range(trials): - a = random.randint(2, n-1) - if not prime(a, q, k, n): - return False - return True - -def get_prime(k): - """ Generate prime of size k bits, with 50 tests - to ensure accuracy. - """ - prime = 0 - while (prime == 0): - prime = random.randrange(pow(2,k//2-1) + 1, pow(2, k//2), 2) - if not miller_rabin(prime, 50): - prime = 0 - return prime - -def modular_inverse(a, m): - """ To calculate the decryption exponent such that - (d * e) mod phi(N) = 1 OR g == 1 in our implementation. - Where m is Phi(n) (PHI = (p-1) * (q-1) ) - - s % m or d (decryption exponent) is the multiplicative inverse of - the encryption exponent e. - """ - g, s, t = eec(a, m) - if g == 1: - return s % m - else: - return None - -def key_gen(bits): - """ The public encryption exponent e, - can be an artibrary prime number. - - Obviously, the higher the number, - the more secure the key pairs are. - """ - e = 17 - p = get_prime(bits) - q = get_prime(bits) - d = modular_inverse(e, (p-1)*(q-1)) - return p*q,d,e - -def write_to_file(e, d, n): - """ Write our public and private keys to file - """ - public = open("publicKey", "w") - public.write(str(e)) - public.write("\n") - public.write(str(n)) - public.close() - - private = open("privateKey", "w") - private.write(str(d)) - private.write("\n") - private.write(str(n)) - private.close() - - -if __name__ == '__main__': - bits = input("Enter the size of your key pairs, in bits: ") - - n, d, e = key_gen(int(bits)) - - #Write keys to file - write_to_file(e, d, n) - - print("Your keys pairs have been saved to file") - - m = input("Enter the message you would like to encrypt: ") - - m = stringEncode(m) - encrypted = pow(m, e, n) - - print("Your encrypted message is: %s" % encrypted) - decrypted = pow(encrypted, d, n) - message = stringDecode(decrypted) - print("You message decrypted is: %s" % message) From python-checkins at python.org Mon Jan 3 13:55:11 2011 From: python-checkins at python.org (michael.foord) Date: Mon, 3 Jan 2011 13:55:11 +0100 (CET) Subject: [Python-checkins] r87679 - python/branches/py3k/Doc/library/unittest.rst Message-ID: <20110103125511.B7551EE9A0@mail.python.org> Author: michael.foord Date: Mon Jan 3 13:55:11 2011 New Revision: 87679 Log: Issue 10786: unittest documentation update. Modified: python/branches/py3k/Doc/library/unittest.rst Modified: python/branches/py3k/Doc/library/unittest.rst ============================================================================== --- python/branches/py3k/Doc/library/unittest.rst (original) +++ python/branches/py3k/Doc/library/unittest.rst Mon Jan 3 13:55:11 2011 @@ -1870,9 +1870,10 @@ instead of repeatedly creating new instances. -.. class:: TextTestRunner(stream=sys.stderr, descriptions=True, verbosity=1, runnerclass=None, warnings=None) +.. class:: TextTestRunner(stream=None, descriptions=True, verbosity=1, runnerclass=None, warnings=None) - A basic test runner implementation which prints results on standard error. It + A basic test runner implementation that outputs results to a stream. If *stream* + is `None`, the default, `sys.stderr` is used as the output stream. This class has a few configurable parameters, but is essentially very simple. Graphical applications which run test suites should provide alternate implementations. @@ -1885,6 +1886,13 @@ messages. This behavior can be overridden using the :option:`-Wd` or :option:`-Wa` options and leaving *warnings* to ``None``. + .. versionchanged:: 3.2 + Added the ``warnings`` argument. + + .. versionchanged:: 3.2 + The default stream is set to `sys.stderr` at instantiation time rather + than import time. + .. method:: _makeResult() This method returns the instance of ``TestResult`` used by :meth:`run`. @@ -1898,8 +1906,6 @@ stream, descriptions, verbosity - .. versionchanged:: 3.2 - Added the ``warnings`` argument. .. function:: main(module='__main__', defaultTest=None, argv=None, testRunner=None, \ testLoader=unittest.loader.defaultTestLoader, exit=True, verbosity=1, \ From python-checkins at python.org Mon Jan 3 15:30:39 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 3 Jan 2011 15:30:39 +0100 (CET) Subject: [Python-checkins] r87680 - python/branches/py3k/Lib/test/test_socketserver.py Message-ID: <20110103143039.A94E7EE9A7@mail.python.org> Author: victor.stinner Date: Mon Jan 3 15:30:39 2011 New Revision: 87680 Log: test_sockserver: close servers when done Modified: python/branches/py3k/Lib/test/test_socketserver.py Modified: python/branches/py3k/Lib/test/test_socketserver.py ============================================================================== --- python/branches/py3k/Lib/test/test_socketserver.py (original) +++ python/branches/py3k/Lib/test/test_socketserver.py Mon Jan 3 15:30:39 2011 @@ -151,6 +151,7 @@ if verbose: print("waiting for server") server.shutdown() t.join() + server.server_close() if verbose: print("done") def stream_examine(self, proto, addr): @@ -270,6 +271,7 @@ s.shutdown() for t, s in threads: t.join() + s.server_close() def test_main(): From python-checkins at python.org Mon Jan 3 15:30:41 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 3 Jan 2011 15:30:41 +0100 (CET) Subject: [Python-checkins] r87681 - python/branches/py3k/Lib/test/test_timeout.py Message-ID: <20110103143041.AB130EE9D0@mail.python.org> Author: victor.stinner Date: Mon Jan 3 15:30:41 2011 New Revision: 87681 Log: test_timeout: move testRecvfromTimeout() to a UDP-specific test case Fix a ResourceWarning(unclosed socket). Modified: python/branches/py3k/Lib/test/test_timeout.py Modified: python/branches/py3k/Lib/test/test_timeout.py ============================================================================== --- python/branches/py3k/Lib/test/test_timeout.py (original) +++ python/branches/py3k/Lib/test/test_timeout.py Mon Jan 3 15:30:41 2011 @@ -88,8 +88,6 @@ class TimeoutTestCase(unittest.TestCase): - """Test case for socket.socket() timeout functions""" - # There are a number of tests here trying to make sure that an operation # doesn't take too much longer than expected. But competing machine # activity makes it inevitable that such tests will fail at times. @@ -98,14 +96,22 @@ # solution. fuzz = 2.0 + localhost = '127.0.0.1' + def setUp(self): - self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self.addr_remote = ('www.python.org.', 80) - self.localhost = '127.0.0.1' + raise NotImplementedError() def tearDown(self): self.sock.close() + +class TCPTimeoutTestCase(TimeoutTestCase): + """TCP test case for socket.socket() timeout functions""" + + def setUp(self): + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.addr_remote = ('www.python.org.', 80) + def testConnectTimeout(self): # Choose a private address that is unlikely to exist to prevent # failures due to the connect succeeding before the timeout. @@ -161,10 +167,31 @@ "timeout (%g) is %g seconds more than expected (%g)" %(_delta, self.fuzz, _timeout)) + def testSend(self): + # Test send() timeout + # couldn't figure out how to test it + pass + + def testSendto(self): + # Test sendto() timeout + # couldn't figure out how to test it + pass + + def testSendall(self): + # Test sendall() timeout + # couldn't figure out how to test it + pass + + +class UDPTimeoutTestCase(TimeoutTestCase): + """UDP test case for socket.socket() timeout functions""" + + def setUp(self): + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + def testRecvfromTimeout(self): # Test recvfrom() timeout _timeout = 2 - self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self.sock.settimeout(_timeout) # Prevent "Address already in use" socket exceptions support.bind_port(self.sock, self.localhost) @@ -178,25 +205,14 @@ "timeout (%g) is %g seconds more than expected (%g)" %(_delta, self.fuzz, _timeout)) - def testSend(self): - # Test send() timeout - # couldn't figure out how to test it - pass - - def testSendto(self): - # Test sendto() timeout - # couldn't figure out how to test it - pass - - def testSendall(self): - # Test sendall() timeout - # couldn't figure out how to test it - pass - def test_main(): support.requires('network') - support.run_unittest(CreationTestCase, TimeoutTestCase) + support.run_unittest( + CreationTestCase, + TCPTimeoutTestCase, + UDPTimeoutTestCase, + ) if __name__ == "__main__": test_main() From python-checkins at python.org Mon Jan 3 15:30:43 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 3 Jan 2011 15:30:43 +0100 (CET) Subject: [Python-checkins] r87682 - in python/branches/py3k: Lib/tkinter/test/test_tkinter/test_loadtk.py Misc/ACKS Message-ID: <20110103143043.527FBEE9DB@mail.python.org> Author: victor.stinner Date: Mon Jan 3 15:30:43 2011 New Revision: 87682 Log: test_tkinter: use a context manager to close directly the pipe Patch written by Nadeem Vawda Modified: python/branches/py3k/Lib/tkinter/test/test_tkinter/test_loadtk.py python/branches/py3k/Misc/ACKS Modified: python/branches/py3k/Lib/tkinter/test/test_tkinter/test_loadtk.py ============================================================================== --- python/branches/py3k/Lib/tkinter/test/test_tkinter/test_loadtk.py (original) +++ python/branches/py3k/Lib/tkinter/test/test_tkinter/test_loadtk.py Mon Jan 3 15:30:43 2011 @@ -31,7 +31,8 @@ # doesn't actually carry through to the process level # because they don't support unsetenv # If that's the case, abort. - display = os.popen('echo $DISPLAY').read().strip() + with os.popen('echo $DISPLAY') as pipe: + display = pipe.read().strip() if display: return Modified: python/branches/py3k/Misc/ACKS ============================================================================== --- python/branches/py3k/Misc/ACKS (original) +++ python/branches/py3k/Misc/ACKS Mon Jan 3 15:30:43 2011 @@ -866,6 +866,7 @@ Atul Varma Dmitry Vasiliev Alexandre Vassalotti +Nadeem Vawda Frank Vercruesse Mike Verdone Jaap Vermeulen From python-checkins at python.org Mon Jan 3 15:30:44 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 3 Jan 2011 15:30:44 +0100 (CET) Subject: [Python-checkins] r87683 - python/branches/py3k/Lib/test/test_xmlrpc.py Message-ID: <20110103143044.DD7E4EE9D3@mail.python.org> Author: victor.stinner Date: Mon Jan 3 15:30:44 2011 New Revision: 87683 Log: test_xmlrpc: close the transport when done Fix a ResourceWarning(unclosed socket). Patch written by Nadeem Vawda. Modified: python/branches/py3k/Lib/test/test_xmlrpc.py Modified: python/branches/py3k/Lib/test/test_xmlrpc.py ============================================================================== --- python/branches/py3k/Lib/test/test_xmlrpc.py (original) +++ python/branches/py3k/Lib/test/test_xmlrpc.py Mon Jan 3 15:30:44 2011 @@ -629,6 +629,7 @@ self.assertEqual(p.pow(6,8), 6**8) self.assertEqual(p.pow(6,8), 6**8) self.assertEqual(p.pow(6,8), 6**8) + p("close")() #they should have all been handled by a single request handler self.assertEqual(len(self.RequestHandler.myRequests), 1) @@ -637,6 +638,7 @@ #due to thread scheduling) self.assertGreaterEqual(len(self.RequestHandler.myRequests[-1]), 2) + #test special attribute access on the serverproxy, through the __call__ #function. class KeepaliveServerTestCase2(BaseKeepaliveServerTestCase): @@ -653,6 +655,7 @@ self.assertEqual(p.pow(6,8), 6**8) self.assertEqual(p.pow(6,8), 6**8) self.assertEqual(p.pow(6,8), 6**8) + p("close")() #they should have all been two request handlers, each having logged at least #two complete requests @@ -660,12 +663,14 @@ self.assertGreaterEqual(len(self.RequestHandler.myRequests[-1]), 2) self.assertGreaterEqual(len(self.RequestHandler.myRequests[-2]), 2) + def test_transport(self): p = xmlrpclib.ServerProxy(URL) #do some requests with close. self.assertEqual(p.pow(6,8), 6**8) p("transport").close() #same as above, really. self.assertEqual(p.pow(6,8), 6**8) + p("close")() self.assertEqual(len(self.RequestHandler.myRequests), 2) #A test case that verifies that gzip encoding works in both directions @@ -709,6 +714,7 @@ self.assertEqual(p.pow(6,8), 6**8) b = self.RequestHandler.content_length self.assertTrue(a>b) + p("close")() def test_bad_gzip_request(self): t = self.Transport() @@ -719,6 +725,7 @@ re.compile(r"\b400\b")) with cm: p.pow(6, 8) + p("close")() def test_gsip_response(self): t = self.Transport() @@ -729,6 +736,7 @@ a = t.response_length self.requestHandler.encode_threshold = 0 #always encode self.assertEqual(p.pow(6,8), 6**8) + p("close")() b = t.response_length self.requestHandler.encode_threshold = old self.assertTrue(a>b) From python-checkins at python.org Mon Jan 3 15:30:46 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 3 Jan 2011 15:30:46 +0100 (CET) Subject: [Python-checkins] r87684 - python/branches/py3k/Lib/test/test_socket.py Message-ID: <20110103143046.86E49EE9C1@mail.python.org> Author: victor.stinner Date: Mon Jan 3 15:30:46 2011 New Revision: 87684 Log: test_socket: use context managers to close directly the socket Fix ResourceWarning(unclosed socket) warnings. Patch written by Nadeem Vawda. Modified: python/branches/py3k/Lib/test/test_socket.py Modified: python/branches/py3k/Lib/test/test_socket.py ============================================================================== --- python/branches/py3k/Lib/test/test_socket.py (original) +++ python/branches/py3k/Lib/test/test_socket.py Mon Jan 3 15:30:46 2011 @@ -1678,25 +1678,25 @@ def testLinuxAbstractNamespace(self): address = b"\x00python-test-hello\x00\xff" - s1 = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - s1.bind(address) - s1.listen(1) - s2 = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - s2.connect(s1.getsockname()) - s1.accept() - self.assertEqual(s1.getsockname(), address) - self.assertEqual(s2.getpeername(), address) + with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s1: + s1.bind(address) + s1.listen(1) + with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s2: + s2.connect(s1.getsockname()) + with s1.accept()[0] as s3: + self.assertEqual(s1.getsockname(), address) + self.assertEqual(s2.getpeername(), address) def testMaxName(self): address = b"\x00" + b"h" * (self.UNIX_PATH_MAX - 1) - s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - s.bind(address) - self.assertEqual(s.getsockname(), address) + with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s: + s.bind(address) + self.assertEqual(s.getsockname(), address) def testNameOverflow(self): address = "\x00" + "h" * self.UNIX_PATH_MAX - s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - self.assertRaises(socket.error, s.bind, address) + with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as s: + self.assertRaises(socket.error, s.bind, address) @unittest.skipUnless(thread, 'Threading required for this test.') @@ -1898,10 +1898,10 @@ if v < (2, 6, 28): self.skipTest("Linux kernel 2.6.28 or higher required, not %s" % ".".join(map(str, v))) - s = socket.socket(socket.AF_INET, - socket.SOCK_STREAM | socket.SOCK_CLOEXEC) - self.assertTrue(s.type & socket.SOCK_CLOEXEC) - self.assertTrue(fcntl.fcntl(s, fcntl.F_GETFD) & fcntl.FD_CLOEXEC) + with socket.socket(socket.AF_INET, + socket.SOCK_STREAM | socket.SOCK_CLOEXEC) as s: + self.assertTrue(s.type & socket.SOCK_CLOEXEC) + self.assertTrue(fcntl.fcntl(s, fcntl.F_GETFD) & fcntl.FD_CLOEXEC) @unittest.skipUnless(hasattr(socket, "SOCK_NONBLOCK"), @@ -1922,29 +1922,33 @@ % ".".join(map(str, v))) # a lot of it seems silly and redundant, but I wanted to test that # changing back and forth worked ok - s = socket.socket(socket.AF_INET, - socket.SOCK_STREAM | socket.SOCK_NONBLOCK) - self.checkNonblock(s) - s.setblocking(1) - self.checkNonblock(s, False) - s.setblocking(0) - self.checkNonblock(s) - s.settimeout(None) - self.checkNonblock(s, False) - s.settimeout(2.0) - self.checkNonblock(s, timeout=2.0) - s.setblocking(1) - self.checkNonblock(s, False) + with socket.socket(socket.AF_INET, + socket.SOCK_STREAM | socket.SOCK_NONBLOCK) as s: + self.checkNonblock(s) + s.setblocking(1) + self.checkNonblock(s, False) + s.setblocking(0) + self.checkNonblock(s) + s.settimeout(None) + self.checkNonblock(s, False) + s.settimeout(2.0) + self.checkNonblock(s, timeout=2.0) + s.setblocking(1) + self.checkNonblock(s, False) # defaulttimeout t = socket.getdefaulttimeout() socket.setdefaulttimeout(0.0) - self.checkNonblock(socket.socket()) + with socket.socket() as s: + self.checkNonblock(s) socket.setdefaulttimeout(None) - self.checkNonblock(socket.socket(), False) + with socket.socket() as s: + self.checkNonblock(s, False) socket.setdefaulttimeout(2.0) - self.checkNonblock(socket.socket(), timeout=2.0) + with socket.socket() as s: + self.checkNonblock(s, timeout=2.0) socket.setdefaulttimeout(None) - self.checkNonblock(socket.socket(), False) + with socket.socket() as s: + self.checkNonblock(s, False) socket.setdefaulttimeout(t) From python-checkins at python.org Mon Jan 3 16:39:50 2011 From: python-checkins at python.org (michael.foord) Date: Mon, 3 Jan 2011 16:39:50 +0100 (CET) Subject: [Python-checkins] r87685 - in python/branches/py3k: Doc/library/unittest.rst Misc/NEWS Tools/README Tools/unittestgui Tools/unittestgui/README.txt Tools/unittestgui/unittestgui.py Message-ID: <20110103153950.13E1AEE9E0@mail.python.org> Author: michael.foord Date: Mon Jan 3 16:39:49 2011 New Revision: 87685 Log: Issue 10502: addition of unittestgui to Tools/ Added: python/branches/py3k/Tools/unittestgui/ python/branches/py3k/Tools/unittestgui/README.txt (contents, props changed) python/branches/py3k/Tools/unittestgui/unittestgui.py (contents, props changed) Modified: python/branches/py3k/Doc/library/unittest.rst python/branches/py3k/Misc/NEWS python/branches/py3k/Tools/README Modified: python/branches/py3k/Doc/library/unittest.rst ============================================================================== --- python/branches/py3k/Doc/library/unittest.rst (original) +++ python/branches/py3k/Doc/library/unittest.rst Mon Jan 3 16:39:49 2011 @@ -97,6 +97,13 @@ A special-interest-group for discussion of testing, and testing tools, in Python. + The script :file:`Tools/unittestgui/unittestgui.py` in the Python source distribution is + a GUI tool for test discovery and execution. This is intended largely for ease of use + for those new to unit testing. For production environments it is recommended that + tests be driven by a continuous integration system such as `Hudson `_ + or `Buildbot `_. + + .. _unittest-minimal-example: Basic example Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 3 16:39:49 2011 @@ -107,6 +107,10 @@ demos have been removed, others integrated in documentation or a new Tools/demo subdirectory. +- Issue #10502: Addition of the unittestgui tool. Originally by Steve Purcell. + Updated for test discovery by Mark Roddy and Python 3 compatibility by + Brian Curtin. + What's New in Python 3.2 Beta 2? ================================ Modified: python/branches/py3k/Tools/README ============================================================================== --- python/branches/py3k/Tools/README (original) +++ python/branches/py3k/Tools/README Mon Jan 3 16:39:49 2011 @@ -34,8 +34,11 @@ test2to3 A demonstration of how to use 2to3 transparently in setup.py. -unicode Tools used to generate unicode database files for - Python 2.0 (by Fredrik Lundh). +unicode Tools used to generate unicode database files (by Fredrik + Lundh). + +unittestgui A Tkinter based GUI test runner for unittest, with test + discovery. world Script to take a list of Internet addresses and print out where in the world those addresses originate from, Added: python/branches/py3k/Tools/unittestgui/README.txt ============================================================================== --- (empty file) +++ python/branches/py3k/Tools/unittestgui/README.txt Mon Jan 3 16:39:49 2011 @@ -0,0 +1,16 @@ +unittestgui.py is GUI framework and application for use with Python unit +testing framework. It executes tests written using the framework provided +by the 'unittest' module. + +Based on the original by Steve Purcell, from: + + http://pyunit.sourceforge.net/ + +Updated for unittest test discovery by Mark Roddy and Python 3 +support by Brian Curtin. + +For details on how to make your tests work with test discovery, +and for explanations of the configuration options, see the unittest +documentation: + + http://docs.python.org/library/unittest.html#test-discovery Added: python/branches/py3k/Tools/unittestgui/unittestgui.py ============================================================================== --- (empty file) +++ python/branches/py3k/Tools/unittestgui/unittestgui.py Mon Jan 3 16:39:49 2011 @@ -0,0 +1,477 @@ +#!/usr/bin/env python +""" +GUI framework and application for use with Python unit testing framework. +Execute tests written using the framework provided by the 'unittest' module. + +Updated for unittest test discovery by Mark Roddy and Python 3 +support by Brian Curtin. + +Based on the original by Steve Purcell, from: + + http://pyunit.sourceforge.net/ + +Copyright (c) 1999, 2000, 2001 Steve Purcell +This module is free software, and you may redistribute it and/or modify +it under the same terms as Python itself, so long as this copyright message +and disclaimer are retained in their original form. + +IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, +SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF +THIS CODE, EVEN IF THE AUTHOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + +THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. THE CODE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, +AND THERE IS NO OBLIGATION WHATSOEVER TO PROVIDE MAINTENANCE, +SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. +""" + +__author__ = "Steve Purcell (stephen_purcell at yahoo.com)" +__version__ = "$Revision: 1.7 $"[11:-2] + +import sys +import traceback +import unittest + +import tkinter as tk +from tkinter import messagebox +from tkinter import filedialog +from tkinter import simpledialog + + + + +############################################################################## +# GUI framework classes +############################################################################## + +class BaseGUITestRunner(object): + """Subclass this class to create a GUI TestRunner that uses a specific + windowing toolkit. The class takes care of running tests in the correct + manner, and making callbacks to the derived class to obtain information + or signal that events have occurred. + """ + def __init__(self, *args, **kwargs): + self.currentResult = None + self.running = 0 + self.__rollbackImporter = None + self.__rollbackImporter = RollbackImporter() + self.test_suite = None + + #test discovery variables + self.directory_to_read = '' + self.top_level_dir = '' + self.test_file_glob_pattern = 'test*.py' + + self.initGUI(*args, **kwargs) + + def errorDialog(self, title, message): + "Override to display an error arising from GUI usage" + pass + + def getDirectoryToDiscover(self): + "Override to prompt user for directory to perform test discovery" + pass + + def runClicked(self): + "To be called in response to user choosing to run a test" + if self.running: return + if not self.test_suite: + self.errorDialog("Test Discovery", "You discover some tests first!") + return + self.currentResult = GUITestResult(self) + self.totalTests = self.test_suite.countTestCases() + self.running = 1 + self.notifyRunning() + self.test_suite.run(self.currentResult) + self.running = 0 + self.notifyStopped() + + def stopClicked(self): + "To be called in response to user stopping the running of a test" + if self.currentResult: + self.currentResult.stop() + + def discoverClicked(self): + self.__rollbackImporter.rollbackImports() + directory = self.getDirectoryToDiscover() + if not directory: + return + self.directory_to_read = directory + try: + # Explicitly use 'None' value if no top level directory is + # specified (indicated by empty string) as discover() explicitly + # checks for a 'None' to determine if no tld has been specified + top_level_dir = self.top_level_dir or None + tests = unittest.defaultTestLoader.discover(directory, self.test_file_glob_pattern, top_level_dir) + self.test_suite = tests + except: + exc_type, exc_value, exc_tb = sys.exc_info() + traceback.print_exception(*sys.exc_info()) + self.errorDialog("Unable to run test '%s'" % directory, + "Error loading specified test: %s, %s" % (exc_type, exc_value)) + return + self.notifyTestsDiscovered(self.test_suite) + + # Required callbacks + + def notifyTestsDiscovered(self, test_suite): + "Override to display information about the suite of discovered tests" + pass + + def notifyRunning(self): + "Override to set GUI in 'running' mode, enabling 'stop' button etc." + pass + + def notifyStopped(self): + "Override to set GUI in 'stopped' mode, enabling 'run' button etc." + pass + + def notifyTestFailed(self, test, err): + "Override to indicate that a test has just failed" + pass + + def notifyTestErrored(self, test, err): + "Override to indicate that a test has just errored" + pass + + def notifyTestSkipped(self, test, reason): + "Override to indicate that test was skipped" + pass + + def notifyTestFailedExpectedly(self, test, err): + "Override to indicate that test has just failed expectedly" + pass + + def notifyTestStarted(self, test): + "Override to indicate that a test is about to run" + pass + + def notifyTestFinished(self, test): + """Override to indicate that a test has finished (it may already have + failed or errored)""" + pass + + +class GUITestResult(unittest.TestResult): + """A TestResult that makes callbacks to its associated GUI TestRunner. + Used by BaseGUITestRunner. Need not be created directly. + """ + def __init__(self, callback): + unittest.TestResult.__init__(self) + self.callback = callback + + def addError(self, test, err): + unittest.TestResult.addError(self, test, err) + self.callback.notifyTestErrored(test, err) + + def addFailure(self, test, err): + unittest.TestResult.addFailure(self, test, err) + self.callback.notifyTestFailed(test, err) + + def addSkip(self, test, reason): + super(GUITestResult,self).addSkip(test, reason) + self.callback.notifyTestSkipped(test, reason) + + def addExpectedFailure(self, test, err): + super(GUITestResult,self).addExpectedFailure(test, err) + self.callback.notifyTestFailedExpectedly(test, err) + + def stopTest(self, test): + unittest.TestResult.stopTest(self, test) + self.callback.notifyTestFinished(test) + + def startTest(self, test): + unittest.TestResult.startTest(self, test) + self.callback.notifyTestStarted(test) + + +class RollbackImporter: + """This tricky little class is used to make sure that modules under test + will be reloaded the next time they are imported. + """ + def __init__(self): + self.previousModules = sys.modules.copy() + + def rollbackImports(self): + for modname in sys.modules.copy().keys(): + if not modname in self.previousModules: + # Force reload when modname next imported + del(sys.modules[modname]) + + +############################################################################## +# Tkinter GUI +############################################################################## + +class DiscoverSettingsDialog(simpledialog.Dialog): + """ + Dialog box for prompting test discovery settings + """ + + def __init__(self, master, top_level_dir, test_file_glob_pattern, *args, **kwargs): + self.top_level_dir = top_level_dir + self.dirVar = tk.StringVar() + self.dirVar.set(top_level_dir) + + self.test_file_glob_pattern = test_file_glob_pattern + self.testPatternVar = tk.StringVar() + self.testPatternVar.set(test_file_glob_pattern) + + simpledialog.Dialog.__init__(self, master, title="Discover Settings", + *args, **kwargs) + + def body(self, master): + tk.Label(master, text="Top Level Directory").grid(row=0) + self.e1 = tk.Entry(master, textvariable=self.dirVar) + self.e1.grid(row = 0, column=1) + tk.Button(master, text="...", + command=lambda: self.selectDirClicked(master)).grid(row=0,column=3) + + tk.Label(master, text="Test File Pattern").grid(row=1) + self.e2 = tk.Entry(master, textvariable = self.testPatternVar) + self.e2.grid(row = 1, column=1) + return None + + def selectDirClicked(self, master): + dir_path = filedialog.askdirectory(parent=master) + if dir_path: + self.dirVar.set(dir_path) + + def apply(self): + self.top_level_dir = self.dirVar.get() + self.test_file_glob_pattern = self.testPatternVar.get() + +class TkTestRunner(BaseGUITestRunner): + """An implementation of BaseGUITestRunner using Tkinter. + """ + def initGUI(self, root, initialTestName): + """Set up the GUI inside the given root window. The test name entry + field will be pre-filled with the given initialTestName. + """ + self.root = root + + self.statusVar = tk.StringVar() + self.statusVar.set("Idle") + + #tk vars for tracking counts of test result types + self.runCountVar = tk.IntVar() + self.failCountVar = tk.IntVar() + self.errorCountVar = tk.IntVar() + self.skipCountVar = tk.IntVar() + self.expectFailCountVar = tk.IntVar() + self.remainingCountVar = tk.IntVar() + + self.top = tk.Frame() + self.top.pack(fill=tk.BOTH, expand=1) + self.createWidgets() + + def getDirectoryToDiscover(self): + return filedialog.askdirectory() + + def settingsClicked(self): + d = DiscoverSettingsDialog(self.top, self.top_level_dir, self.test_file_glob_pattern) + self.top_level_dir = d.top_level_dir + self.test_file_glob_pattern = d.test_file_glob_pattern + + def notifyTestsDiscovered(self, test_suite): + self.runCountVar.set(0) + self.failCountVar.set(0) + self.errorCountVar.set(0) + self.remainingCountVar.set(test_suite.countTestCases()) + self.progressBar.setProgressFraction(0.0) + self.errorListbox.delete(0, tk.END) + self.statusVar.set("Discovering tests from %s" % self.directory_to_read) + self.stopGoButton['state'] = tk.NORMAL + + def createWidgets(self): + """Creates and packs the various widgets. + + Why is it that GUI code always ends up looking a mess, despite all the + best intentions to keep it tidy? Answers on a postcard, please. + """ + # Status bar + statusFrame = tk.Frame(self.top, relief=tk.SUNKEN, borderwidth=2) + statusFrame.pack(anchor=tk.SW, fill=tk.X, side=tk.BOTTOM) + tk.Label(statusFrame, width=1, textvariable=self.statusVar).pack(side=tk.TOP, fill=tk.X) + + # Area to enter name of test to run + leftFrame = tk.Frame(self.top, borderwidth=3) + leftFrame.pack(fill=tk.BOTH, side=tk.LEFT, anchor=tk.NW, expand=1) + suiteNameFrame = tk.Frame(leftFrame, borderwidth=3) + suiteNameFrame.pack(fill=tk.X) + + # Progress bar + progressFrame = tk.Frame(leftFrame, relief=tk.GROOVE, borderwidth=2) + progressFrame.pack(fill=tk.X, expand=0, anchor=tk.NW) + tk.Label(progressFrame, text="Progress:").pack(anchor=tk.W) + self.progressBar = ProgressBar(progressFrame, relief=tk.SUNKEN, + borderwidth=2) + self.progressBar.pack(fill=tk.X, expand=1) + + + # Area with buttons to start/stop tests and quit + buttonFrame = tk.Frame(self.top, borderwidth=3) + buttonFrame.pack(side=tk.LEFT, anchor=tk.NW, fill=tk.Y) + + tk.Button(buttonFrame, text="Discover Tests", + command=self.discoverClicked).pack(fill=tk.X) + + + self.stopGoButton = tk.Button(buttonFrame, text="Start", + command=self.runClicked, state=tk.DISABLED) + self.stopGoButton.pack(fill=tk.X) + + tk.Button(buttonFrame, text="Close", + command=self.top.quit).pack(side=tk.BOTTOM, fill=tk.X) + tk.Button(buttonFrame, text="Settings", + command=self.settingsClicked).pack(side=tk.BOTTOM, fill=tk.X) + + # Area with labels reporting results + for label, var in (('Run:', self.runCountVar), + ('Failures:', self.failCountVar), + ('Errors:', self.errorCountVar), + ('Skipped:', self.skipCountVar), + ('Expected Failures:', self.expectFailCountVar), + ('Remaining:', self.remainingCountVar), + ): + tk.Label(progressFrame, text=label).pack(side=tk.LEFT) + tk.Label(progressFrame, textvariable=var, + foreground="blue").pack(side=tk.LEFT, fill=tk.X, + expand=1, anchor=tk.W) + + # List box showing errors and failures + tk.Label(leftFrame, text="Failures and errors:").pack(anchor=tk.W) + listFrame = tk.Frame(leftFrame, relief=tk.SUNKEN, borderwidth=2) + listFrame.pack(fill=tk.BOTH, anchor=tk.NW, expand=1) + self.errorListbox = tk.Listbox(listFrame, foreground='red', + selectmode=tk.SINGLE, + selectborderwidth=0) + self.errorListbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=1, + anchor=tk.NW) + listScroll = tk.Scrollbar(listFrame, command=self.errorListbox.yview) + listScroll.pack(side=tk.LEFT, fill=tk.Y, anchor=tk.N) + self.errorListbox.bind("", + lambda e, self=self: self.showSelectedError()) + self.errorListbox.configure(yscrollcommand=listScroll.set) + + def errorDialog(self, title, message): + messagebox.showerror(parent=self.root, title=title, + message=message) + + def notifyRunning(self): + self.runCountVar.set(0) + self.failCountVar.set(0) + self.errorCountVar.set(0) + self.remainingCountVar.set(self.totalTests) + self.errorInfo = [] + while self.errorListbox.size(): + self.errorListbox.delete(0) + #Stopping seems not to work, so simply disable the start button + #self.stopGoButton.config(command=self.stopClicked, text="Stop") + self.stopGoButton.config(state=tk.DISABLED) + self.progressBar.setProgressFraction(0.0) + self.top.update_idletasks() + + def notifyStopped(self): + self.stopGoButton.config(state=tk.DISABLED) + #self.stopGoButton.config(command=self.runClicked, text="Start") + self.statusVar.set("Idle") + + def notifyTestStarted(self, test): + self.statusVar.set(str(test)) + self.top.update_idletasks() + + def notifyTestFailed(self, test, err): + self.failCountVar.set(1 + self.failCountVar.get()) + self.errorListbox.insert(tk.END, "Failure: %s" % test) + self.errorInfo.append((test,err)) + + def notifyTestErrored(self, test, err): + self.errorCountVar.set(1 + self.errorCountVar.get()) + self.errorListbox.insert(tk.END, "Error: %s" % test) + self.errorInfo.append((test,err)) + + def notifyTestSkipped(self, test, reason): + super(TkTestRunner, self).notifyTestSkipped(test, reason) + self.skipCountVar.set(1 + self.skipCountVar.get()) + + def notifyTestFailedExpectedly(self, test, err): + super(TkTestRunner, self).notifyTestFailedExpectedly(test, err) + self.expectFailCountVar.set(1 + self.expectFailCountVar.get()) + + + def notifyTestFinished(self, test): + self.remainingCountVar.set(self.remainingCountVar.get() - 1) + self.runCountVar.set(1 + self.runCountVar.get()) + fractionDone = float(self.runCountVar.get())/float(self.totalTests) + fillColor = len(self.errorInfo) and "red" or "green" + self.progressBar.setProgressFraction(fractionDone, fillColor) + + def showSelectedError(self): + selection = self.errorListbox.curselection() + if not selection: return + selected = int(selection[0]) + txt = self.errorListbox.get(selected) + window = tk.Toplevel(self.root) + window.title(txt) + window.protocol('WM_DELETE_WINDOW', window.quit) + test, error = self.errorInfo[selected] + tk.Label(window, text=str(test), + foreground="red", justify=tk.LEFT).pack(anchor=tk.W) + tracebackLines = traceback.format_exception(*error) + tracebackText = "".join(tracebackLines) + tk.Label(window, text=tracebackText, justify=tk.LEFT).pack() + tk.Button(window, text="Close", + command=window.quit).pack(side=tk.BOTTOM) + window.bind('', lambda e, w=window: w.quit()) + window.mainloop() + window.destroy() + + +class ProgressBar(tk.Frame): + """A simple progress bar that shows a percentage progress in + the given colour.""" + + def __init__(self, *args, **kwargs): + tk.Frame.__init__(self, *args, **kwargs) + self.canvas = tk.Canvas(self, height='20', width='60', + background='white', borderwidth=3) + self.canvas.pack(fill=tk.X, expand=1) + self.rect = self.text = None + self.canvas.bind('', self.paint) + self.setProgressFraction(0.0) + + def setProgressFraction(self, fraction, color='blue'): + self.fraction = fraction + self.color = color + self.paint() + self.canvas.update_idletasks() + + def paint(self, *args): + totalWidth = self.canvas.winfo_width() + width = int(self.fraction * float(totalWidth)) + height = self.canvas.winfo_height() + if self.rect is not None: self.canvas.delete(self.rect) + if self.text is not None: self.canvas.delete(self.text) + self.rect = self.canvas.create_rectangle(0, 0, width, height, + fill=self.color) + percentString = "%3.0f%%" % (100.0 * self.fraction) + self.text = self.canvas.create_text(totalWidth/2, height/2, + anchor=tk.CENTER, + text=percentString) + +def main(initialTestName=""): + root = tk.Tk() + root.title("PyUnit") + runner = TkTestRunner(root, initialTestName) + root.protocol('WM_DELETE_WINDOW', root.quit) + root.mainloop() + + +if __name__ == '__main__': + if len(sys.argv) == 2: + main(sys.argv[1]) + else: + main() From python-checkins at python.org Mon Jan 3 16:47:59 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 3 Jan 2011 16:47:59 +0100 (CET) Subject: [Python-checkins] r87686 - python/branches/py3k/Lib/multiprocessing/connection.py Message-ID: <20110103154759.3D1A8EE9A1@mail.python.org> Author: victor.stinner Date: Mon Jan 3 16:47:59 2011 New Revision: 87686 Log: Issue #10816: multiprocessing.SocketClient() closes the socket on error Use a context manager to close immediatly the socket on error. Modified: python/branches/py3k/Lib/multiprocessing/connection.py Modified: python/branches/py3k/Lib/multiprocessing/connection.py ============================================================================== --- python/branches/py3k/Lib/multiprocessing/connection.py (original) +++ python/branches/py3k/Lib/multiprocessing/connection.py Mon Jan 3 16:47:59 2011 @@ -281,25 +281,24 @@ Return a connection object connected to the socket given by `address` ''' family = address_type(address) - s = socket.socket( getattr(socket, family) ) - t = _init_timeout() + with socket.socket( getattr(socket, family) ) as s: + t = _init_timeout() - while 1: - try: - s.connect(address) - except socket.error as e: - if e.args[0] != errno.ECONNREFUSED or _check_timeout(t): - debug('failed to connect to address %s', address) - raise - time.sleep(0.01) + while 1: + try: + s.connect(address) + except socket.error as e: + if e.args[0] != errno.ECONNREFUSED or _check_timeout(t): + debug('failed to connect to address %s', address) + raise + time.sleep(0.01) + else: + break else: - break - else: - raise + raise - fd = duplicate(s.fileno()) + fd = duplicate(s.fileno()) conn = _multiprocessing.Connection(fd) - s.close() return conn # From python-checkins at python.org Mon Jan 3 17:12:39 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 3 Jan 2011 17:12:39 +0100 (CET) Subject: [Python-checkins] r87687 - python/branches/py3k/Lib/pydoc.py Message-ID: <20110103161239.30CB9EE9B8@mail.python.org> Author: victor.stinner Date: Mon Jan 3 17:12:39 2011 New Revision: 87687 Log: pydoc: close the DocServer when done Modified: python/branches/py3k/Lib/pydoc.py Modified: python/branches/py3k/Lib/pydoc.py ============================================================================== --- python/branches/py3k/Lib/pydoc.py (original) +++ python/branches/py3k/Lib/pydoc.py Mon Jan 3 17:12:39 2011 @@ -2112,6 +2112,7 @@ while not self.quit: rd, wr, ex = select.select([self.socket.fileno()], [], [], 1) if rd: self.handle_request() + self.server_close() def server_activate(self): self.base.server_activate(self) @@ -2409,6 +2410,7 @@ rd, wr, ex = select.select([self.socket.fileno()], [], [], 1) if rd: self.handle_request() + self.server_close() def server_activate(self): self.base.server_activate(self) From python-checkins at python.org Mon Jan 3 17:36:00 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 3 Jan 2011 17:36:00 +0100 (CET) Subject: [Python-checkins] r87688 - python/branches/py3k/Lib/test/test_subprocess.py Message-ID: <20110103163600.B85C1EE9A1@mail.python.org> Author: victor.stinner Date: Mon Jan 3 17:36:00 2011 New Revision: 87688 Log: test_subprocess: close pipes at the end of test_pipe_cloexec_real_tools() Modified: python/branches/py3k/Lib/test/test_subprocess.py Modified: python/branches/py3k/Lib/test/test_subprocess.py ============================================================================== --- python/branches/py3k/Lib/test/test_subprocess.py (original) +++ python/branches/py3k/Lib/test/test_subprocess.py Mon Jan 3 17:36:00 2011 @@ -1022,6 +1022,9 @@ self.assertTrue(readfiles, "The child hung") self.assertEqual(p2.stdout.read(), data) + p1.stdout.close() + p2.stdout.close() + def test_close_fds(self): fd_status = support.findfile("fd_status.py", subdir="subprocessdata") From python-checkins at python.org Mon Jan 3 18:00:11 2011 From: python-checkins at python.org (michael.foord) Date: Mon, 3 Jan 2011 18:00:11 +0100 (CET) Subject: [Python-checkins] r87689 - in python/branches/py3k: Doc/library/unittest.rst Lib/unittest/case.py Lib/unittest/test/test_case.py Misc/NEWS Tools/unittestgui/unittestgui.py Message-ID: <20110103170011.ABB4AEE9FA@mail.python.org> Author: michael.foord Date: Mon Jan 3 18:00:11 2011 New Revision: 87689 Log: Enable unittest.TestCase to be instantiated without providing a method name. Changed unittestgui to show number of discovered tests in the status bar. Modified: python/branches/py3k/Doc/library/unittest.rst python/branches/py3k/Lib/unittest/case.py python/branches/py3k/Lib/unittest/test/test_case.py python/branches/py3k/Misc/NEWS python/branches/py3k/Tools/unittestgui/unittestgui.py Modified: python/branches/py3k/Doc/library/unittest.rst ============================================================================== --- python/branches/py3k/Doc/library/unittest.rst (original) +++ python/branches/py3k/Doc/library/unittest.rst Mon Jan 3 18:00:11 2011 @@ -721,6 +721,11 @@ Here, we create two instances of :class:`WidgetTestCase`, each of which runs a single test. + .. versionchanged:: + `TestCase` can be instantiated successfully without providing a method + name. This makes it easier to experiment with `TestCase` from the + interactive interpreter. + *methodName* defaults to :meth:`runTest`. :class:`TestCase` instances provide three groups of methods: one group used Modified: python/branches/py3k/Lib/unittest/case.py ============================================================================== --- python/branches/py3k/Lib/unittest/case.py (original) +++ python/branches/py3k/Lib/unittest/case.py Mon Jan 3 18:00:11 2011 @@ -274,12 +274,17 @@ """ self._testMethodName = methodName self._outcomeForDoCleanups = None + self._testMethodDoc = 'No test' try: testMethod = getattr(self, methodName) except AttributeError: - raise ValueError("no such test method in %s: %s" % - (self.__class__, methodName)) - self._testMethodDoc = testMethod.__doc__ + if methodName != 'runTest': + # we allow instantiation with no explicit method name + # but not an *incorrect* or missing method name + raise ValueError("no such test method in %s: %s" % + (self.__class__, methodName)) + else: + self._testMethodDoc = testMethod.__doc__ self._cleanups = [] # Map types to custom assertEqual functions that will compare Modified: python/branches/py3k/Lib/unittest/test/test_case.py ============================================================================== --- python/branches/py3k/Lib/unittest/test/test_case.py (original) +++ python/branches/py3k/Lib/unittest/test/test_case.py Mon Jan 3 18:00:11 2011 @@ -77,6 +77,16 @@ self.assertEqual(Test().id()[-13:], '.Test.runTest') + # test that TestCase can be instantiated with no args + # primarily for use at the interactive interpreter + test = unittest.TestCase() + test.assertEqual(3, 3) + with test.assertRaises(test.failureException): + test.assertEqual(3, 2) + + with self.assertRaises(AttributeError): + test.run() + # "class TestCase([methodName])" # ... # "Each instance of TestCase will run a single test method: the Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 3 18:00:11 2011 @@ -23,6 +23,9 @@ Library ------- +- `unittest.TestCase` can be instantiated without a method name; for simpler + exploration from the interactive interpreter. + - Issue #10798: Reject supporting concurrent.futures if the system has too few POSIX semaphores. Modified: python/branches/py3k/Tools/unittestgui/unittestgui.py ============================================================================== --- python/branches/py3k/Tools/unittestgui/unittestgui.py (original) +++ python/branches/py3k/Tools/unittestgui/unittestgui.py Mon Jan 3 18:00:11 2011 @@ -276,13 +276,15 @@ self.test_file_glob_pattern = d.test_file_glob_pattern def notifyTestsDiscovered(self, test_suite): + discovered = test_suite.countTestCases() self.runCountVar.set(0) self.failCountVar.set(0) self.errorCountVar.set(0) - self.remainingCountVar.set(test_suite.countTestCases()) + self.remainingCountVar.set(discovered) self.progressBar.setProgressFraction(0.0) self.errorListbox.delete(0, tk.END) - self.statusVar.set("Discovering tests from %s" % self.directory_to_read) + self.statusVar.set("Discovering tests from %s. Found: %s" % + (self.directory_to_read, discovered)) self.stopGoButton['state'] = tk.NORMAL def createWidgets(self): From python-checkins at python.org Mon Jan 3 18:06:39 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 3 Jan 2011 18:06:39 +0100 (CET) Subject: [Python-checkins] r87690 - python/branches/release31-maint/Lib/test/test_time.py Message-ID: <20110103170639.C34F7EE9C3@mail.python.org> Author: alexander.belopolsky Date: Mon Jan 3 18:06:39 2011 New Revision: 87690 Log: Issue 10814: time.asctime test will now use a valid day with out of range year. Modified: python/branches/release31-maint/Lib/test/test_time.py Modified: python/branches/release31-maint/Lib/test/test_time.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_time.py (original) +++ python/branches/release31-maint/Lib/test/test_time.py Mon Jan 3 18:06:39 2011 @@ -131,7 +131,7 @@ # (12345, 1, 0, 0, 0, 0, 0, 0, 0)) # XXX: For now, just make sure we don't have a crash: try: - time.asctime((12345, 1, 0, 0, 0, 0, 0, 0, 0)) + time.asctime((12345, 1, 1, 0, 0, 0, 0, 1, 0)) except ValueError: pass From python-checkins at python.org Mon Jan 3 18:51:11 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 3 Jan 2011 18:51:11 +0100 (CET) Subject: [Python-checkins] r87691 - python/branches/py3k/Lib/test/test_site.py Message-ID: <20110103175111.4A052EE9D0@mail.python.org> Author: eric.araujo Date: Mon Jan 3 18:51:11 2011 New Revision: 87691 Log: Fix test_site for systems without unsetenv. Reported by Zsolt Cserna. Modified: python/branches/py3k/Lib/test/test_site.py Modified: python/branches/py3k/Lib/test/test_site.py ============================================================================== --- python/branches/py3k/Lib/test/test_site.py (original) +++ python/branches/py3k/Lib/test/test_site.py Mon Jan 3 18:51:11 2011 @@ -161,12 +161,16 @@ usersite = site.USER_SITE self.assertIn(usersite, sys.path) + env = os.environ.copy() rc = subprocess.call([sys.executable, '-c', - 'import sys; sys.exit(%r in sys.path)' % usersite]) + 'import sys; sys.exit(%r in sys.path)' % usersite], + env=env) self.assertEqual(rc, 1) + env = os.environ.copy() rc = subprocess.call([sys.executable, '-s', '-c', - 'import sys; sys.exit(%r in sys.path)' % usersite]) + 'import sys; sys.exit(%r in sys.path)' % usersite], + env=env) self.assertEqual(rc, 0) env = os.environ.copy() From python-checkins at python.org Mon Jan 3 18:52:04 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 3 Jan 2011 18:52:04 +0100 (CET) Subject: [Python-checkins] r87692 - python/branches/release27-maint/Lib/test/test_time.py Message-ID: <20110103175204.21134EE9D0@mail.python.org> Author: alexander.belopolsky Date: Mon Jan 3 18:52:03 2011 New Revision: 87692 Log: Issue 10814: time.asctime test will now use a valid day with out of range year. Modified: python/branches/release27-maint/Lib/test/test_time.py Modified: python/branches/release27-maint/Lib/test/test_time.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_time.py (original) +++ python/branches/release27-maint/Lib/test/test_time.py Mon Jan 3 18:52:03 2011 @@ -121,7 +121,7 @@ # (12345, 1, 0, 0, 0, 0, 0, 0, 0)) # XXX: For now, just make sure we don't have a crash: try: - time.asctime((12345, 1, 0, 0, 0, 0, 0, 0, 0)) + time.asctime((12345, 1, 1, 0, 0, 0, 0, 1, 0)) except ValueError: pass From python-checkins at python.org Mon Jan 3 18:53:13 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 3 Jan 2011 18:53:13 +0100 (CET) Subject: [Python-checkins] r87693 - in python/branches/release31-maint: Lib/test/test_site.py Message-ID: <20110103175313.CE064EE9D2@mail.python.org> Author: eric.araujo Date: Mon Jan 3 18:53:13 2011 New Revision: 87693 Log: Merged revisions 87691 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87691 | eric.araujo | 2011-01-03 18:51:11 +0100 (lun., 03 janv. 2011) | 2 lines Fix test_site for systems without unsetenv. Reported by Zsolt Cserna. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/test/test_site.py Modified: python/branches/release31-maint/Lib/test/test_site.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_site.py (original) +++ python/branches/release31-maint/Lib/test/test_site.py Mon Jan 3 18:53:13 2011 @@ -154,12 +154,16 @@ usersite = site.USER_SITE self.assertTrue(usersite in sys.path) + env = os.environ.copy() rc = subprocess.call([sys.executable, '-c', - 'import sys; sys.exit(%r in sys.path)' % usersite]) + 'import sys; sys.exit(%r in sys.path)' % usersite], + env=env) self.assertEqual(rc, 1) + env = os.environ.copy() rc = subprocess.call([sys.executable, '-s', '-c', - 'import sys; sys.exit(%r in sys.path)' % usersite]) + 'import sys; sys.exit(%r in sys.path)' % usersite], + env=env) self.assertEqual(rc, 0) env = os.environ.copy() From python-checkins at python.org Mon Jan 3 18:57:30 2011 From: python-checkins at python.org (eric.araujo) Date: Mon, 3 Jan 2011 18:57:30 +0100 (CET) Subject: [Python-checkins] r87694 - in python/branches/release27-maint: Lib/test/test_site.py Message-ID: <20110103175730.0E050F46F@mail.python.org> Author: eric.araujo Date: Mon Jan 3 18:57:29 2011 New Revision: 87694 Log: Merged revisions 87691 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87691 | eric.araujo | 2011-01-03 18:51:11 +0100 (lun., 03 janv. 2011) | 2 lines Fix test_site for systems without unsetenv. Reported by Zsolt Cserna. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/test/test_site.py Modified: python/branches/release27-maint/Lib/test/test_site.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_site.py (original) +++ python/branches/release27-maint/Lib/test/test_site.py Mon Jan 3 18:57:29 2011 @@ -165,13 +165,17 @@ usersite = site.USER_SITE self.assertIn(usersite, sys.path) + env = os.environ.copy() rc = subprocess.call([sys.executable, '-c', - 'import sys; sys.exit(%r in sys.path)' % usersite]) + 'import sys; sys.exit(%r in sys.path)' % usersite], + env=env) self.assertEqual(rc, 1, "%r is not in sys.path (sys.exit returned %r)" % (usersite, rc)) + env = os.environ.copy() rc = subprocess.call([sys.executable, '-s', '-c', - 'import sys; sys.exit(%r in sys.path)' % usersite]) + 'import sys; sys.exit(%r in sys.path)' % usersite], + env=env) self.assertEqual(rc, 0) env = os.environ.copy() From python-checkins at python.org Mon Jan 3 19:23:55 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 19:23:55 +0100 (CET) Subject: [Python-checkins] r87695 - in python/branches/py3k: Lib/subprocess.py Lib/test/test_subprocess.py Misc/NEWS Modules/_posixsubprocess.c Message-ID: <20110103182355.527C8EEA0B@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 19:23:55 2011 New Revision: 87695 Log: Issue #10806, issue #9905: Fix subprocess pipes when some of the standard file descriptors (0, 1, 2) are closed in the parent process. Initial patch by Ross Lagerwall. Modified: python/branches/py3k/Lib/subprocess.py python/branches/py3k/Lib/test/test_subprocess.py python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/_posixsubprocess.c Modified: python/branches/py3k/Lib/subprocess.py ============================================================================== --- python/branches/py3k/Lib/subprocess.py (original) +++ python/branches/py3k/Lib/subprocess.py Mon Jan 3 19:23:55 2011 @@ -393,22 +393,22 @@ # POSIX defines PIPE_BUF as >= 512. _PIPE_BUF = getattr(select, 'PIPE_BUF', 512) + _FD_CLOEXEC = getattr(fcntl, 'FD_CLOEXEC', 1) + + def _set_cloexec(fd, cloexec): + old = fcntl.fcntl(fd, fcntl.F_GETFD) + if cloexec: + fcntl.fcntl(fd, fcntl.F_SETFD, old | _FD_CLOEXEC) + else: + fcntl.fcntl(fd, fcntl.F_SETFD, old & ~_FD_CLOEXEC) + if _posixsubprocess: _create_pipe = _posixsubprocess.cloexec_pipe else: def _create_pipe(): - try: - cloexec_flag = fcntl.FD_CLOEXEC - except AttributeError: - cloexec_flag = 1 - fds = os.pipe() - - old = fcntl.fcntl(fds[0], fcntl.F_GETFD) - fcntl.fcntl(fds[0], fcntl.F_SETFD, old | cloexec_flag) - old = fcntl.fcntl(fds[1], fcntl.F_GETFD) - fcntl.fcntl(fds[1], fcntl.F_SETFD, old | cloexec_flag) - + _set_cloexec(fds[0], True) + _set_cloexec(fds[1], True) return fds __all__ = ["Popen", "PIPE", "STDOUT", "call", "check_call", "getstatusoutput", @@ -1194,23 +1194,25 @@ os.close(errpipe_read) # Dup fds for child - if p2cread != -1: - os.dup2(p2cread, 0) - if c2pwrite != -1: - os.dup2(c2pwrite, 1) - if errwrite != -1: - os.dup2(errwrite, 2) + def _dup2(a, b): + # dup2() removes the CLOEXEC flag but + # we must do it ourselves if dup2() + # would be a no-op (issue #10806). + if a == b: + _set_cloexec(a, False) + elif a != -1: + os.dup2(a, b) + _dup2(p2cread, 0) + _dup2(c2pwrite, 1) + _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. - if p2cread != -1 and p2cread not in (0,): - os.close(p2cread) - if (c2pwrite != -1 and - c2pwrite not in (p2cread, 1)): - os.close(c2pwrite) - if (errwrite != -1 and - errwrite not in (p2cread, c2pwrite, 2)): - os.close(errwrite) + closed = set() + for fd in [p2cread, c2pwrite, errwrite]: + if fd > 2 and fd not in closed: + os.close(fd) + closed.add(fd) # Close all other fds, if asked for if close_fds: Modified: python/branches/py3k/Lib/test/test_subprocess.py ============================================================================== --- python/branches/py3k/Lib/test/test_subprocess.py (original) +++ python/branches/py3k/Lib/test/test_subprocess.py Mon Jan 3 19:23:55 2011 @@ -903,6 +903,58 @@ self.assertStderrEqual(stderr, b'') self.assertEqual(p.wait(), -signal.SIGTERM) + def check_close_std_fds(self, fds): + # Issue #9905: test that subprocess pipes still work properly with + # some standard fds closed + stdin = 0 + newfds = [] + for a in fds: + b = os.dup(a) + newfds.append(b) + if a == 0: + stdin = b + try: + for fd in fds: + os.close(fd) + out, err = subprocess.Popen([sys.executable, "-c", + 'import sys;' + 'sys.stdout.write("apple");' + 'sys.stdout.flush();' + 'sys.stderr.write("orange")'], + stdin=stdin, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate() + err = support.strip_python_stderr(err) + self.assertEqual((out, err), (b'apple', b'orange')) + finally: + for b, a in zip(newfds, fds): + os.dup2(b, a) + for b in newfds: + os.close(b) + + def test_close_fd_0(self): + self.check_close_std_fds([0]) + + def test_close_fd_1(self): + self.check_close_std_fds([1]) + + def test_close_fd_2(self): + self.check_close_std_fds([2]) + + def test_close_fds_0_1(self): + self.check_close_std_fds([0, 1]) + + def test_close_fds_0_2(self): + self.check_close_std_fds([0, 2]) + + def test_close_fds_1_2(self): + self.check_close_std_fds([1, 2]) + + def test_close_fds_0_1_2(self): + # Issue #10806: test that subprocess pipes still work properly with + # all standard fds closed. + self.check_close_std_fds([0, 1, 2]) + def test_surrogates_error_message(self): def prepare(): raise ValueError("surrogate:\uDCff") Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 3 19:23:55 2011 @@ -23,6 +23,10 @@ Library ------- +- Issue #10806, issue #9905: Fix subprocess pipes when some of the standard + file descriptors (0, 1, 2) are closed in the parent process. Initial + patch by Ross Lagerwall. + - `unittest.TestCase` can be instantiated without a method name; for simpler exploration from the interactive interpreter. Modified: python/branches/py3k/Modules/_posixsubprocess.c ============================================================================== --- python/branches/py3k/Modules/_posixsubprocess.c (original) +++ python/branches/py3k/Modules/_posixsubprocess.c Mon Jan 3 19:23:55 2011 @@ -69,27 +69,40 @@ } POSIX_CALL(close(errpipe_read)); - /* Dup fds for child. */ - if (p2cread != -1) { + /* Dup fds for child. + dup2() removes the CLOEXEC flag but we must do it ourselves if dup2() + would be a no-op (issue #10806). */ + if (p2cread == 0) { + int old = fcntl(p2cread, F_GETFD); + if (old != -1) + fcntl(p2cread, F_SETFD, old & ~FD_CLOEXEC); + } else if (p2cread != -1) { POSIX_CALL(dup2(p2cread, 0)); /* stdin */ } - if (c2pwrite != -1) { + if (c2pwrite == 1) { + int old = fcntl(c2pwrite, F_GETFD); + if (old != -1) + fcntl(c2pwrite, F_SETFD, old & ~FD_CLOEXEC); + } else if (c2pwrite != -1) { POSIX_CALL(dup2(c2pwrite, 1)); /* stdout */ } - if (errwrite != -1) { + if (errwrite == 2) { + int old = fcntl(errwrite, F_GETFD); + if (old != -1) + fcntl(errwrite, F_SETFD, old & ~FD_CLOEXEC); + } else if (errwrite != -1) { POSIX_CALL(dup2(errwrite, 2)); /* stderr */ } /* Close pipe fds. Make sure we don't close the same fd more than */ /* once, or standard fds. */ - if (p2cread != -1 && p2cread != 0) { + if (p2cread > 2) { POSIX_CALL(close(p2cread)); } - if (c2pwrite != -1 && c2pwrite != p2cread && c2pwrite != 1) { + if (c2pwrite > 2) { POSIX_CALL(close(c2pwrite)); } - if (errwrite != -1 && errwrite != p2cread && - errwrite != c2pwrite && errwrite != 2) { + if (errwrite != c2pwrite && errwrite > 2) { POSIX_CALL(close(errwrite)); } From python-checkins at python.org Mon Jan 3 19:36:36 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 19:36:36 +0100 (CET) Subject: [Python-checkins] r87696 - in python/branches/release31-maint: Lib/subprocess.py Lib/test/support.py Lib/test/test_subprocess.py Misc/NEWS Message-ID: <20110103183636.5DA71EE9F8@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 19:36:36 2011 New Revision: 87696 Log: Merged revisions 87695 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87695 | antoine.pitrou | 2011-01-03 19:23:55 +0100 (lun., 03 janv. 2011) | 5 lines Issue #10806, issue #9905: Fix subprocess pipes when some of the standard file descriptors (0, 1, 2) are closed in the parent process. Initial patch by Ross Lagerwall. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/subprocess.py python/branches/release31-maint/Lib/test/support.py python/branches/release31-maint/Lib/test/test_subprocess.py python/branches/release31-maint/Misc/NEWS Modified: python/branches/release31-maint/Lib/subprocess.py ============================================================================== --- python/branches/release31-maint/Lib/subprocess.py (original) +++ python/branches/release31-maint/Lib/subprocess.py Mon Jan 3 19:36:36 2011 @@ -1012,14 +1012,17 @@ errread, errwrite) - def _set_cloexec_flag(self, fd): + def _set_cloexec_flag(self, fd, cloexec=True): try: cloexec_flag = fcntl.FD_CLOEXEC except AttributeError: cloexec_flag = 1 old = fcntl.fcntl(fd, fcntl.F_GETFD) - fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) + if cloexec: + fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) + else: + fcntl.fcntl(fd, fcntl.F_SETFD, old & ~cloexec_flag) def _close_fds(self, but): @@ -1080,23 +1083,25 @@ os.close(errpipe_read) # Dup fds for child - if p2cread is not None: - os.dup2(p2cread, 0) - if c2pwrite is not None: - os.dup2(c2pwrite, 1) - if errwrite is not None: - os.dup2(errwrite, 2) + def _dup2(a, b): + # dup2() removes the CLOEXEC flag but + # we must do it ourselves if dup2() + # would be a no-op (issue #10806). + if a == b: + self._set_cloexec_flag(a, False) + elif a is not None: + os.dup2(a, b) + _dup2(p2cread, 0) + _dup2(c2pwrite, 1) + _dup2(errwrite, 2) # Close pipe fds. Make sure we don't close the # same fd more than once, or standard fds. - if p2cread is not None and p2cread not in (0,): - os.close(p2cread) - if c2pwrite is not None and \ - c2pwrite not in (p2cread, 1): - os.close(c2pwrite) - if (errwrite is not None and - errwrite not in (p2cread, c2pwrite, 2)): - os.close(errwrite) + closed = { None } + for fd in [p2cread, c2pwrite, errwrite]: + if fd not in closed and fd > 2: + os.close(fd) + closed.add(fd) # Close all other fds, if asked for if close_fds: Modified: python/branches/release31-maint/Lib/test/support.py ============================================================================== --- python/branches/release31-maint/Lib/test/support.py (original) +++ python/branches/release31-maint/Lib/test/support.py Mon Jan 3 19:36:36 2011 @@ -10,6 +10,7 @@ import socket import sys import os +import re import platform import shutil import warnings @@ -1056,3 +1057,13 @@ break except: break + +def strip_python_stderr(stderr): + """Strip the stderr of a Python process from potential debug output + emitted by the interpreter. + + This will typically be run on the result of the communicate() method + of a subprocess.Popen object. + """ + stderr = re.sub(br"\[\d+ refs\]\r?\n?$", b"", stderr).strip() + return stderr Modified: python/branches/release31-maint/Lib/test/test_subprocess.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_subprocess.py (original) +++ python/branches/release31-maint/Lib/test/test_subprocess.py Mon Jan 3 19:36:36 2011 @@ -804,6 +804,62 @@ " non-zero with this error:\n%s" % stderr.decode('utf8')) + def check_close_std_fds(self, fds): + # Issue #9905: test that subprocess pipes still work properly with + # some standard fds closed + stdin = 0 + newfds = [] + for a in fds: + b = os.dup(a) + newfds.append(b) + if a == 0: + stdin = b + try: + for fd in fds: + os.close(fd) + out, err = subprocess.Popen([sys.executable, "-c", + 'import sys;' + 'sys.stdout.write("apple");' + 'sys.stdout.flush();' + 'sys.stderr.write("orange")'], + stdin=stdin, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate() + err = support.strip_python_stderr(err) + self.assertEqual((out, err), (b'apple', b'orange')) + finally: + for b, a in zip(newfds, fds): + os.dup2(b, a) + for b in newfds: + os.close(b) + + def test_close_fd_0(self): + self.check_close_std_fds([0]) + + def test_close_fd_1(self): + self.check_close_std_fds([1]) + + def test_close_fd_2(self): + self.check_close_std_fds([2]) + + def test_close_fds_0_1(self): + self.check_close_std_fds([0, 1]) + + def test_close_fds_0_2(self): + self.check_close_std_fds([0, 2]) + + def test_close_fds_1_2(self): + self.check_close_std_fds([1, 2]) + + def test_close_fds_0_1_2(self): + # Issue #10806: test that subprocess pipes still work properly with + # all standard fds closed. + self.check_close_std_fds([0, 1, 2]) + + def test_surrogates_error_message(self): + def prepare(): + raise ValueError("surrogate:\uDCff") + # # Windows tests Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Mon Jan 3 19:36:36 2011 @@ -27,6 +27,10 @@ Library ------- +- Issue #10806, issue #9905: Fix subprocess pipes when some of the standard + file descriptors (0, 1, 2) are closed in the parent process. Initial + patch by Ross Lagerwall. + - Issue 10753 - Characters ';','=' and ',' in the PATH_INFO environment variable won't be quoted when the URI is constructed by the wsgiref.util 's request_uri method. According to RFC 3986, these characters can be a part of From python-checkins at python.org Mon Jan 3 19:45:09 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 19:45:09 +0100 (CET) Subject: [Python-checkins] r87697 - in python/branches/release27-maint: Lib/subprocess.py Lib/test/test_subprocess.py Lib/test/test_support.py Misc/NEWS Message-ID: <20110103184509.D67C2EE9D0@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 19:45:09 2011 New Revision: 87697 Log: Merged revisions 87695 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87695 | antoine.pitrou | 2011-01-03 19:23:55 +0100 (lun., 03 janv. 2011) | 5 lines Issue #10806, issue #9905: Fix subprocess pipes when some of the standard file descriptors (0, 1, 2) are closed in the parent process. Initial patch by Ross Lagerwall. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/subprocess.py python/branches/release27-maint/Lib/test/test_subprocess.py python/branches/release27-maint/Lib/test/test_support.py python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Lib/subprocess.py ============================================================================== --- python/branches/release27-maint/Lib/subprocess.py (original) +++ python/branches/release27-maint/Lib/subprocess.py Mon Jan 3 19:45:09 2011 @@ -1051,14 +1051,17 @@ errread, errwrite) - def _set_cloexec_flag(self, fd): + def _set_cloexec_flag(self, fd, cloexec=True): try: cloexec_flag = fcntl.FD_CLOEXEC except AttributeError: cloexec_flag = 1 old = fcntl.fcntl(fd, fcntl.F_GETFD) - fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) + if cloexec: + fcntl.fcntl(fd, fcntl.F_SETFD, old | cloexec_flag) + else: + fcntl.fcntl(fd, fcntl.F_SETFD, old & ~cloexec_flag) def _close_fds(self, but): @@ -1128,21 +1131,25 @@ os.close(errpipe_read) # Dup fds for child - if p2cread is not None: - os.dup2(p2cread, 0) - if c2pwrite is not None: - os.dup2(c2pwrite, 1) - if errwrite is not None: - os.dup2(errwrite, 2) - - # Close pipe fds. Make sure we don't close the same - # fd more than once, or standard fds. - if p2cread is not None and p2cread not in (0,): - os.close(p2cread) - if c2pwrite is not None and c2pwrite not in (p2cread, 1): - os.close(c2pwrite) - if errwrite is not None and errwrite not in (p2cread, c2pwrite, 2): - os.close(errwrite) + def _dup2(a, b): + # dup2() removes the CLOEXEC flag but + # we must do it ourselves if dup2() + # would be a no-op (issue #10806). + if a == b: + self._set_cloexec_flag(a, False) + elif a is not None: + os.dup2(a, b) + _dup2(p2cread, 0) + _dup2(c2pwrite, 1) + _dup2(errwrite, 2) + + # Close pipe fds. Make sure we don't close the + # same fd more than once, or standard fds. + closed = { None } + for fd in [p2cread, c2pwrite, errwrite]: + if fd not in closed and fd > 2: + os.close(fd) + closed.add(fd) # Close all other fds, if asked for if close_fds: Modified: python/branches/release27-maint/Lib/test/test_subprocess.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_subprocess.py (original) +++ python/branches/release27-maint/Lib/test/test_subprocess.py Mon Jan 3 19:45:09 2011 @@ -778,6 +778,58 @@ self.assertStderrEqual(stderr, '') self.assertEqual(p.wait(), -signal.SIGTERM) + def check_close_std_fds(self, fds): + # Issue #9905: test that subprocess pipes still work properly with + # some standard fds closed + stdin = 0 + newfds = [] + for a in fds: + b = os.dup(a) + newfds.append(b) + if a == 0: + stdin = b + try: + for fd in fds: + os.close(fd) + out, err = subprocess.Popen([sys.executable, "-c", + 'import sys;' + 'sys.stdout.write("apple");' + 'sys.stdout.flush();' + 'sys.stderr.write("orange")'], + stdin=stdin, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE).communicate() + err = test_support.strip_python_stderr(err) + self.assertEqual((out, err), (b'apple', b'orange')) + finally: + for b, a in zip(newfds, fds): + os.dup2(b, a) + for b in newfds: + os.close(b) + + def test_close_fd_0(self): + self.check_close_std_fds([0]) + + def test_close_fd_1(self): + self.check_close_std_fds([1]) + + def test_close_fd_2(self): + self.check_close_std_fds([2]) + + def test_close_fds_0_1(self): + self.check_close_std_fds([0, 1]) + + def test_close_fds_0_2(self): + self.check_close_std_fds([0, 2]) + + def test_close_fds_1_2(self): + self.check_close_std_fds([1, 2]) + + def test_close_fds_0_1_2(self): + # Issue #10806: test that subprocess pipes still work properly with + # all standard fds closed. + self.check_close_std_fds([0, 1, 2]) + def test_wait_when_sigchild_ignored(self): # NOTE: sigchild_ignore.py may not be an effective test on all OSes. sigchild_ignore = test_support.findfile("sigchild_ignore.py", Modified: python/branches/release27-maint/Lib/test/test_support.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_support.py (original) +++ python/branches/release27-maint/Lib/test/test_support.py Mon Jan 3 19:45:09 2011 @@ -1219,3 +1219,13 @@ if v > 0: args.append('-' + opt * v) return args + +def strip_python_stderr(stderr): + """Strip the stderr of a Python process from potential debug output + emitted by the interpreter. + + This will typically be run on the result of the communicate() method + of a subprocess.Popen object. + """ + stderr = re.sub(br"\[\d+ refs\]\r?\n?$", b"", stderr).strip() + return stderr Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Mon Jan 3 19:45:09 2011 @@ -25,6 +25,10 @@ Library ------- +- Issue #10806, issue #9905: Fix subprocess pipes when some of the standard + file descriptors (0, 1, 2) are closed in the parent process. Initial + patch by Ross Lagerwall. + - Issue #4662: os.tempnam(), os.tmpfile() and os.tmpnam() now raise a py3k DeprecationWarning. From python-checkins at python.org Mon Jan 3 19:53:50 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 19:53:50 +0100 (CET) Subject: [Python-checkins] r87698 - in python/branches/py3k: Misc/ACKS Misc/NEWS configure configure.in Message-ID: <20110103185350.42021EE984@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 19:53:50 2011 New Revision: 87698 Log: Issue #7716: Under Solaris, don't assume existence of /usr/xpg4/bin/grep in the configure script but use $GREP instead. Patch by Fabian Groffen. Modified: python/branches/py3k/Misc/ACKS python/branches/py3k/Misc/NEWS python/branches/py3k/configure python/branches/py3k/configure.in Modified: python/branches/py3k/Misc/ACKS ============================================================================== --- python/branches/py3k/Misc/ACKS (original) +++ python/branches/py3k/Misc/ACKS Mon Jan 3 19:53:50 2011 @@ -321,6 +321,7 @@ Hans de Graaff Eddy De Greef Duncan Grisby +Fabian Groffen Eric Groo Dag Gruneau Michael Guravage Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 3 19:53:50 2011 @@ -101,6 +101,9 @@ Build ----- +- Issue #7716: Under Solaris, don't assume existence of /usr/xpg4/bin/grep in + the configure script but use $GREP instead. Patch by Fabian Groffen. + - Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD and DragonFly BSD. Patch by Nicolas Joly. Modified: python/branches/py3k/configure ============================================================================== --- python/branches/py3k/configure (original) +++ python/branches/py3k/configure Mon Jan 3 19:53:50 2011 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 87639 . +# From configure.in Revision: 87646 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65 for python 3.2. # @@ -8976,7 +8976,7 @@ ;; solaris) if test -f /etc/netconfig; then - if /usr/xpg4/bin/grep -q tcp6 /etc/netconfig; then + if $GREP -q tcp6 /etc/netconfig; then ipv6type=$i ipv6trylibc=yes fi Modified: python/branches/py3k/configure.in ============================================================================== --- python/branches/py3k/configure.in (original) +++ python/branches/py3k/configure.in Mon Jan 3 19:53:50 2011 @@ -2350,7 +2350,7 @@ ;; solaris) if test -f /etc/netconfig; then - if /usr/xpg4/bin/grep -q tcp6 /etc/netconfig; then + if $GREP -q tcp6 /etc/netconfig; then ipv6type=$i ipv6trylibc=yes fi From python-checkins at python.org Mon Jan 3 19:56:50 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 19:56:50 +0100 (CET) Subject: [Python-checkins] r87699 - in python/branches/release31-maint: Misc/ACKS Misc/NEWS configure configure.in Message-ID: <20110103185650.E3942EE984@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 19:56:50 2011 New Revision: 87699 Log: Merged revisions 87698 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87698 | antoine.pitrou | 2011-01-03 19:53:50 +0100 (lun., 03 janv. 2011) | 4 lines Issue #7716: Under Solaris, don't assume existence of /usr/xpg4/bin/grep in the configure script but use $GREP instead. Patch by Fabian Groffen. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Misc/ACKS python/branches/release31-maint/Misc/NEWS python/branches/release31-maint/configure python/branches/release31-maint/configure.in Modified: python/branches/release31-maint/Misc/ACKS ============================================================================== --- python/branches/release31-maint/Misc/ACKS (original) +++ python/branches/release31-maint/Misc/ACKS Mon Jan 3 19:56:50 2011 @@ -295,6 +295,7 @@ Hans de Graaff Eddy De Greef Duncan Grisby +Fabian Groffen Dag Gruneau Michael Guravage Lars Gust?bel Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Mon Jan 3 19:56:50 2011 @@ -96,6 +96,9 @@ Build ----- +- Issue #7716: Under Solaris, don't assume existence of /usr/xpg4/bin/grep in + the configure script but use $GREP instead. Patch by Fabian Groffen. + - Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD and DragonFly BSD. Patch by Nicolas Joly. Modified: python/branches/release31-maint/configure ============================================================================== --- python/branches/release31-maint/configure (original) +++ python/branches/release31-maint/configure Mon Jan 3 19:56:50 2011 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 87641 . +# From configure.in Revision: 87649 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65 for python 3.1. # @@ -8878,7 +8878,7 @@ ;; solaris) if test -f /etc/netconfig; then - if /usr/xpg4/bin/grep -q tcp6 /etc/netconfig; then + if $GREP -q tcp6 /etc/netconfig; then ipv6type=$i ipv6trylibc=yes fi Modified: python/branches/release31-maint/configure.in ============================================================================== --- python/branches/release31-maint/configure.in (original) +++ python/branches/release31-maint/configure.in Mon Jan 3 19:56:50 2011 @@ -2385,7 +2385,7 @@ ;; solaris) if test -f /etc/netconfig; then - if /usr/xpg4/bin/grep -q tcp6 /etc/netconfig; then + if $GREP -q tcp6 /etc/netconfig; then ipv6type=$i ipv6trylibc=yes fi From python-checkins at python.org Mon Jan 3 19:57:14 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 19:57:14 +0100 (CET) Subject: [Python-checkins] r87700 - in python/branches/release27-maint: Misc/ACKS Misc/NEWS configure configure.in Message-ID: <20110103185714.BEED1EE986@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 19:57:14 2011 New Revision: 87700 Log: Merged revisions 87698 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87698 | antoine.pitrou | 2011-01-03 19:53:50 +0100 (lun., 03 janv. 2011) | 4 lines Issue #7716: Under Solaris, don't assume existence of /usr/xpg4/bin/grep in the configure script but use $GREP instead. Patch by Fabian Groffen. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Misc/ACKS python/branches/release27-maint/Misc/NEWS python/branches/release27-maint/configure python/branches/release27-maint/configure.in Modified: python/branches/release27-maint/Misc/ACKS ============================================================================== --- python/branches/release27-maint/Misc/ACKS (original) +++ python/branches/release27-maint/Misc/ACKS Mon Jan 3 19:57:14 2011 @@ -301,6 +301,7 @@ Hans de Graaff Eddy De Greef Duncan Grisby +Fabian Groffen Dag Gruneau Michael Guravage Lars Gust?bel Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Mon Jan 3 19:57:14 2011 @@ -105,6 +105,9 @@ Build ----- +- Issue #7716: Under Solaris, don't assume existence of /usr/xpg4/bin/grep in + the configure script but use $GREP instead. Patch by Fabian Groffen. + - Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD and DragonFly BSD. Patch by Nicolas Joly. Modified: python/branches/release27-maint/configure ============================================================================== --- python/branches/release27-maint/configure (original) +++ python/branches/release27-maint/configure Mon Jan 3 19:57:14 2011 @@ -1,5 +1,5 @@ #! /bin/sh -# From configure.in Revision: 87640 . +# From configure.in Revision: 87650 . # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65 for python 2.7. # @@ -9179,7 +9179,7 @@ ;; solaris) if test -f /etc/netconfig; then - if /usr/xpg4/bin/grep -q tcp6 /etc/netconfig; then + if $GREP -q tcp6 /etc/netconfig; then ipv6type=$i ipv6trylibc=yes fi Modified: python/branches/release27-maint/configure.in ============================================================================== --- python/branches/release27-maint/configure.in (original) +++ python/branches/release27-maint/configure.in Mon Jan 3 19:57:14 2011 @@ -2503,7 +2503,7 @@ ;; solaris) if test -f /etc/netconfig; then - if /usr/xpg4/bin/grep -q tcp6 /etc/netconfig; then + if $GREP -q tcp6 /etc/netconfig; then ipv6type=$i ipv6trylibc=yes fi From python-checkins at python.org Mon Jan 3 20:11:32 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 20:11:32 +0100 (CET) Subject: [Python-checkins] r87701 - in python/branches/release27-maint: Makefile.pre.in Misc/NEWS Message-ID: <20110103191132.BBF3BEE98B@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 20:11:32 2011 New Revision: 87701 Log: Merged revisions 84068,87558 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r84068 | martin.v.loewis | 2010-08-15 17:47:25 +0200 (dim., 15 ao?t 2010) | 2 lines Don't run pgen twice when using make -j. ........ r87558 | victor.stinner | 2010-12-29 00:14:17 +0100 (mer., 29 d?c. 2010) | 1 line Don't ignore pgen error (on "make Parser/pgen.stamp") ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Makefile.pre.in python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Makefile.pre.in ============================================================================== --- python/branches/release27-maint/Makefile.pre.in (original) +++ python/branches/release27-maint/Makefile.pre.in Mon Jan 3 20:11:32 2011 @@ -536,9 +536,12 @@ $(MAINCC) -c $(PY_CFLAGS) -o $@ $(srcdir)/Modules/python.c -$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT) +# Use a stamp file to prevent make -j invoking pgen twice +$(GRAMMAR_H) $(GRAMMAR_C): Parser/pgen.stamp +Parser/pgen.stamp: $(PGEN) $(GRAMMAR_INPUT) -@$(INSTALL) -d Include - -$(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C) + $(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C) + -touch Parser/pgen.stamp $(PGEN): $(PGENOBJS) $(CC) $(OPT) $(LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN) @@ -1184,7 +1187,7 @@ clobber: clean profile-removal -rm -f $(BUILDPYTHON) $(PGEN) $(LIBRARY) $(LDLIBRARY) $(DLLLIBRARY) \ - tags TAGS \ + tags TAGS Parser/pgen.stamp \ config.cache config.log pyconfig.h Modules/config.c -rm -rf build platform -rm -rf $(PYTHONFRAMEWORKDIR) Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Mon Jan 3 20:11:32 2011 @@ -105,6 +105,8 @@ Build ----- +- Don't run pgen twice when using make -j. + - Issue #7716: Under Solaris, don't assume existence of /usr/xpg4/bin/grep in the configure script but use $GREP instead. Patch by Fabian Groffen. From python-checkins at python.org Mon Jan 3 20:11:48 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 20:11:48 +0100 (CET) Subject: [Python-checkins] r87702 - in python/branches/release31-maint: Makefile.pre.in Misc/NEWS Message-ID: <20110103191148.F0175EE98B@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 20:11:48 2011 New Revision: 87702 Log: Merged revisions 84068,87558 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r84068 | martin.v.loewis | 2010-08-15 17:47:25 +0200 (dim., 15 ao?t 2010) | 2 lines Don't run pgen twice when using make -j. ........ r87558 | victor.stinner | 2010-12-29 00:14:17 +0100 (mer., 29 d?c. 2010) | 1 line Don't ignore pgen error (on "make Parser/pgen.stamp") ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Makefile.pre.in python/branches/release31-maint/Misc/NEWS Modified: python/branches/release31-maint/Makefile.pre.in ============================================================================== --- python/branches/release31-maint/Makefile.pre.in (original) +++ python/branches/release31-maint/Makefile.pre.in Mon Jan 3 20:11:48 2011 @@ -540,9 +540,12 @@ $(IO_OBJS): $(IO_H) -$(GRAMMAR_H) $(GRAMMAR_C): $(PGEN) $(GRAMMAR_INPUT) +# Use a stamp file to prevent make -j invoking pgen twice +$(GRAMMAR_H) $(GRAMMAR_C): Parser/pgen.stamp +Parser/pgen.stamp: $(PGEN) $(GRAMMAR_INPUT) -@$(INSTALL) -d Include - -$(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C) + $(PGEN) $(GRAMMAR_INPUT) $(GRAMMAR_H) $(GRAMMAR_C) + -touch Parser/pgen.stamp $(PGEN): $(PGENOBJS) $(CC) $(OPT) $(LDFLAGS) $(PGENOBJS) $(LIBS) -o $(PGEN) @@ -1179,7 +1182,7 @@ clobber: clean profile-removal -rm -f $(BUILDPYTHON) $(PGEN) $(LIBRARY) $(LDLIBRARY) $(DLLLIBRARY) \ - tags TAGS \ + tags TAGS Parser/pgen.stamp \ config.cache config.log pyconfig.h Modules/config.c -rm -rf build platform -rm -rf $(PYTHONFRAMEWORKDIR) Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Mon Jan 3 20:11:48 2011 @@ -167,6 +167,8 @@ Build ----- +- Don't run pgen twice when using make -j. + - Backport r83399 to allow test_distutils to pass on installed versions. - Issue #1303434: Generate ZIP file containing all PDBs (already done for rc1). From python-checkins at python.org Mon Jan 3 20:13:03 2011 From: python-checkins at python.org (michael.foord) Date: Mon, 3 Jan 2011 20:13:03 +0100 (CET) Subject: [Python-checkins] r87703 - python/branches/py3k/Tools/README Message-ID: <20110103191303.06323EE98B@mail.python.org> Author: michael.foord Date: Mon Jan 3 20:13:02 2011 New Revision: 87703 Log: Update description of Tools/unicode Modified: python/branches/py3k/Tools/README Modified: python/branches/py3k/Tools/README ============================================================================== --- python/branches/py3k/Tools/README (original) +++ python/branches/py3k/Tools/README Mon Jan 3 20:13:02 2011 @@ -34,8 +34,9 @@ test2to3 A demonstration of how to use 2to3 transparently in setup.py. -unicode Tools used to generate unicode database files (by Fredrik - Lundh). +unicode Tools for generating unicodedata and codecs from unicode.org + and other mapping files (by Fredrik Lundh, Marc-Andre Lemburg + and Martin von Loewis). unittestgui A Tkinter based GUI test runner for unittest, with test discovery. From python-checkins at python.org Mon Jan 3 21:38:53 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 21:38:53 +0100 (CET) Subject: [Python-checkins] r87704 - in python/branches/py3k: Lib/test/regrtest.py Misc/NEWS Message-ID: <20110103203853.16025EE989@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 21:38:52 2011 New Revision: 87704 Log: Issue #6293: Have regrtest.py echo back sys.flags. This is done by default in whole runs and enabled selectively using `--header` when running an explicit list of tests. Original patch by Collin Winter. Modified: python/branches/py3k/Lib/test/regrtest.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/test/regrtest.py ============================================================================== --- python/branches/py3k/Lib/test/regrtest.py (original) +++ python/branches/py3k/Lib/test/regrtest.py Mon Jan 3 21:38:52 2011 @@ -29,6 +29,7 @@ -d/--debug -- print traceback for failed tests -q/--quiet -- no output unless one or more tests fail -S/--slow -- print the slowest 10 tests + --header -- print header with interpreter info Selecting tests @@ -228,7 +229,8 @@ exclude=False, single=False, randomize=False, fromfile=None, findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, - random_seed=None, use_mp=None, verbose3=False, forever=False): + random_seed=None, use_mp=None, verbose3=False, forever=False, + header=False): """Execute a test suite. This also parses command-line options and modifies its behavior @@ -262,7 +264,7 @@ 'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir', 'runleaks', 'huntrleaks=', 'memlimit=', 'randseed=', 'multiprocess=', 'slaveargs=', 'forever', 'debug', 'start=', - 'nowindows']) + 'nowindows', 'header']) except getopt.error as msg: usage(msg) @@ -371,6 +373,8 @@ forever = True elif o in ('-j', '--multiprocess'): use_mp = int(a) + elif o == '--header': + header = True elif o == '--slaveargs': args, kwargs = json.loads(a) try: @@ -447,12 +451,13 @@ args = [] # For a partial run, we do not need to clutter the output. - if verbose or not (quiet or single or tests or args): + if verbose or header or not (quiet or single or tests or args): # Print basic platform information print("==", platform.python_implementation(), *sys.version.split()) print("== ", platform.platform(aliased=True), "%s-endian" % sys.byteorder) print("== ", os.getcwd()) + print("Testing with flags:", sys.flags) alltests = findtests(testdir, stdtests, nottests) selected = tests or args or alltests Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 3 21:38:52 2011 @@ -121,6 +121,13 @@ Updated for test discovery by Mark Roddy and Python 3 compatibility by Brian Curtin. +Tests +----- + +- Issue #6293: Have regrtest.py echo back sys.flags. This is done by default + in whole runs and enabled selectively using ``--header`` when running an + explicit list of tests. Original patch by Collin Winter. + What's New in Python 3.2 Beta 2? ================================ From python-checkins at python.org Mon Jan 3 21:40:07 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 21:40:07 +0100 (CET) Subject: [Python-checkins] r87705 - python/branches/py3k/Lib/test/regrtest.py Message-ID: <20110103204007.E9851EE989@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 21:40:07 2011 New Revision: 87705 Log: Mention --randseed in option list Modified: python/branches/py3k/Lib/test/regrtest.py Modified: python/branches/py3k/Lib/test/regrtest.py ============================================================================== --- python/branches/py3k/Lib/test/regrtest.py (original) +++ python/branches/py3k/Lib/test/regrtest.py Mon Jan 3 21:40:07 2011 @@ -34,6 +34,7 @@ Selecting tests -r/--random -- randomize test execution order (see below) + --randseed -- pass a random seed to reproduce a previous random run -f/--fromfile -- read names of tests to run from a file (see below) -x/--exclude -- arguments are tests to *exclude* -s/--single -- single step through a set of tests (see below) From python-checkins at python.org Mon Jan 3 21:47:05 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 21:47:05 +0100 (CET) Subject: [Python-checkins] r87706 - in python/branches/release31-maint: Lib/test/regrtest.py Misc/NEWS Message-ID: <20110103204705.2FC28EE986@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 21:47:02 2011 New Revision: 87706 Log: Merged revisions 87704-87705 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87704 | antoine.pitrou | 2011-01-03 21:38:52 +0100 (lun., 03 janv. 2011) | 5 lines Issue #6293: Have regrtest.py echo back sys.flags. This is done by default in whole runs and enabled selectively using `--header` when running an explicit list of tests. Original patch by Collin Winter. ........ r87705 | antoine.pitrou | 2011-01-03 21:40:07 +0100 (lun., 03 janv. 2011) | 3 lines Mention --randseed in option list ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/test/regrtest.py python/branches/release31-maint/Misc/NEWS Modified: python/branches/release31-maint/Lib/test/regrtest.py ============================================================================== --- python/branches/release31-maint/Lib/test/regrtest.py (original) +++ python/branches/release31-maint/Lib/test/regrtest.py Mon Jan 3 21:47:02 2011 @@ -6,34 +6,51 @@ directory, and run them. Various command line options provide additional facilities. -Command line options: - --v: verbose -- run tests in verbose mode with output to stdout --w: verbose2 -- re-run failed tests in verbose mode --d: debug -- print traceback for failed tests --q: quiet -- don't print anything except if a test fails --x: exclude -- arguments are tests to *exclude* --s: single -- run only a single test (see below) --S: slow -- print the slowest 10 tests --r: random -- randomize test execution order --f: fromfile -- read names of tests to run from a file (see below) --l: findleaks -- if GC is available detect tests that leak memory --u: use -- specify which special resource intensive tests to run --h: help -- print this text and exit --t: threshold -- call gc.set_threshold(N) --T: coverage -- turn on code coverage using the trace module --D: coverdir -- Directory where coverage files are put --N: nocoverdir -- Put coverage files alongside modules --L: runleaks -- run the leaks(1) command just before exit --R: huntrleaks -- search for reference leaks (needs debug build, v. slow) --M: memlimit -- run very large memory-consuming tests --n: nowindows -- suppress error message boxes on Windows - If non-option arguments are present, they are names for tests to run, unless -x is given, in which case they are names for tests not to run. If no test names are given, all tests are run. --v is incompatible with -g and does not compare test output files. +Options: + +-h/--help -- print this text and exit + +Verbosity + +-v/--verbose -- run tests in verbose mode with output to stdout +-w/--verbose2 -- re-run failed tests in verbose mode +-d/--debug -- print traceback for failed tests +-q/--quiet -- no output unless one or more tests fail +-S/--slow -- print the slowest 10 tests + --header -- print header with interpreter info + +Selecting tests + +-r/--random -- randomize test execution order (see below) + --randseed -- pass a random seed to reproduce a previous random run +-f/--fromfile -- read names of tests to run from a file (see below) +-x/--exclude -- arguments are tests to *exclude* +-s/--single -- single step through a set of tests (see below) +-u/--use RES1,RES2,... + -- specify which special resource intensive tests to run +-M/--memlimit LIMIT + -- run very large memory-consuming tests + +Special runs + +-l/--findleaks -- if GC is available detect tests that leak memory +-L/--runleaks -- run the leaks(1) command just before exit +-R/--huntrleaks RUNCOUNTS + -- search for reference leaks (needs debug build, v. slow) +-T/--coverage -- turn on code coverage tracing using the trace module +-D/--coverdir DIRECTORY + -- Directory where coverage files are put +-N/--nocoverdir -- Put coverage files alongside modules +-t/--threshold THRESHOLD + -- call gc.set_threshold(THRESHOLD) +-n/--nowindows -- suppress error message boxes on Windows + + +Additional Option Details: -r randomizes test execution order. You can use --randseed=int to provide a int seed value for the randomizer; this is useful for reproducing troublesome @@ -135,6 +152,7 @@ import io import sys import time +import platform import traceback import warnings import unittest @@ -190,7 +208,7 @@ exclude=False, single=False, randomize=False, fromfile=None, findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, - random_seed=None): + random_seed=None, header=False): """Execute a test suite. This also parses command-line options and modifies its behavior @@ -225,8 +243,7 @@ 'coverdir=', 'nocoverdir', 'runleaks', 'huntrleaks=', 'verbose2', 'memlimit=', 'debug', 'start=', 'nowindows', - 'randseed=', - ]) + 'randseed=', 'header']) except getopt.error as msg: usage(msg) @@ -329,6 +346,8 @@ for m in [msvcrt.CRT_WARN, msvcrt.CRT_ERROR, msvcrt.CRT_ASSERT]: msvcrt.CrtSetReportMode(m, msvcrt.CRTDBG_MODE_FILE) msvcrt.CrtSetReportFile(m, msvcrt.CRTDBG_FILE_STDERR) + elif o == '--header': + header = True else: print(("No handler for option {}. Please report this as a bug " "at http://bugs.python.org.").format(o), file=sys.stderr) @@ -343,6 +362,15 @@ skipped = [] resource_denieds = [] + # For a partial run, we do not need to clutter the output. + if verbose or header or not (quiet or single or tests or args): + # Print basic platform information + print("==", platform.python_implementation(), *sys.version.split()) + print("== ", platform.platform(aliased=True), + "%s-endian" % sys.byteorder) + print("== ", os.getcwd()) + print("Testing with flags:", sys.flags) + if findleaks: try: import gc Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Mon Jan 3 21:47:02 2011 @@ -105,6 +105,10 @@ Tests ----- +- Issue #6293: Have regrtest.py echo back sys.flags. This is done by default + in whole runs and enabled selectively using ``--header`` when running an + explicit list of tests. Original patch by Collin Winter. + - Issue #775964: test_grp now skips YP/NIS entries instead of failing when encountering them. From python-checkins at python.org Mon Jan 3 21:49:01 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 21:49:01 +0100 (CET) Subject: [Python-checkins] r87707 - in python/branches/release27-maint: Lib/test/regrtest.py Misc/NEWS Message-ID: <20110103204901.482EBEE986@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 21:49:01 2011 New Revision: 87707 Log: Merged revisions 87704-87705 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87704 | antoine.pitrou | 2011-01-03 21:38:52 +0100 (lun., 03 janv. 2011) | 5 lines Issue #6293: Have regrtest.py echo back sys.flags. This is done by default in whole runs and enabled selectively using `--header` when running an explicit list of tests. Original patch by Collin Winter. ........ r87705 | antoine.pitrou | 2011-01-03 21:40:07 +0100 (lun., 03 janv. 2011) | 3 lines Mention --randseed in option list ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/test/regrtest.py python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Lib/test/regrtest.py ============================================================================== --- python/branches/release27-maint/Lib/test/regrtest.py (original) +++ python/branches/release27-maint/Lib/test/regrtest.py Mon Jan 3 21:49:01 2011 @@ -28,10 +28,12 @@ -W/--verbose3 -- re-run failed tests in verbose mode immediately -q/--quiet -- no output unless one or more tests fail -S/--slow -- print the slowest 10 tests + --header -- print header with interpreter info Selecting tests -r/--random -- randomize test execution order (see below) + --randseed -- pass a random seed to reproduce a previous random run -f/--fromfile -- read names of tests to run from a file (see below) -x/--exclude -- arguments are tests to *exclude* -s/--single -- single step through a set of tests (see below) @@ -227,7 +229,8 @@ exclude=False, single=False, randomize=False, fromfile=None, findleaks=False, use_resources=None, trace=False, coverdir='coverage', runleaks=False, huntrleaks=False, verbose2=False, print_slow=False, - random_seed=None, use_mp=None, verbose3=False, forever=False): + random_seed=None, use_mp=None, verbose3=False, forever=False, + header=False): """Execute a test suite. This also parses command-line options and modifies its behavior @@ -258,7 +261,7 @@ 'exclude', 'single', 'slow', 'random', 'fromfile', 'findleaks', 'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir', 'runleaks', 'huntrleaks=', 'memlimit=', 'randseed=', - 'multiprocess=', 'slaveargs=', 'forever']) + 'multiprocess=', 'slaveargs=', 'forever', 'header']) except getopt.error, msg: usage(2, msg) @@ -342,6 +345,8 @@ forever = True elif o in ('-j', '--multiprocess'): use_mp = int(a) + elif o == '--header': + header = True elif o == '--slaveargs': args, kwargs = json.loads(a) try: @@ -415,13 +420,14 @@ args = [] # For a partial run, we do not need to clutter the output. - if verbose or not (quiet or single or tests or args): + if verbose or header or not (quiet or single or tests or args): # Print basic platform information print "==", platform.python_implementation(), \ " ".join(sys.version.split()) print "== ", platform.platform(aliased=True), \ "%s-endian" % sys.byteorder print "== ", os.getcwd() + print "Testing with flags:", sys.flags alltests = findtests(testdir, stdtests, nottests) selected = tests or args or alltests Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Mon Jan 3 21:49:01 2011 @@ -116,6 +116,10 @@ Tests ----- +- Issue #6293: Have regrtest.py echo back sys.flags. This is done by default + in whole runs and enabled selectively using ``--header`` when running an + explicit list of tests. Original patch by Collin Winter. + - Issue #775964: test_grp now skips YP/NIS entries instead of failing when encountering them. From python-checkins at python.org Mon Jan 3 21:50:32 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 21:50:32 +0100 (CET) Subject: [Python-checkins] r87708 - python/branches/release31-maint/Parser Message-ID: <20110103205032.1FC20EE986@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 21:50:26 2011 New Revision: 87708 Log: Ignore pgen.stamp Modified: python/branches/release31-maint/Parser/ (props changed) From python-checkins at python.org Mon Jan 3 21:51:04 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 21:51:04 +0100 (CET) Subject: [Python-checkins] r87709 - python/branches/release27-maint/Parser Message-ID: <20110103205104.ABCFBEE986@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 21:51:04 2011 New Revision: 87709 Log: Ignore pgen.stamp. Modified: python/branches/release27-maint/Parser/ (props changed) From python-checkins at python.org Mon Jan 3 22:06:13 2011 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 3 Jan 2011 22:06:13 +0100 (CET) Subject: [Python-checkins] r87710 - in python/branches/py3k/Lib: test/test_threading.py threading.py Message-ID: <20110103210613.196F1EE989@mail.python.org> Author: gregory.p.smith Date: Mon Jan 3 22:06:12 2011 New Revision: 87710 Log: issue6643 - Two locks held within the threading module on each thread instance needed to be reinitialized after fork(). Adds tests to confirm that they are and that a potential deadlock and crasher bug are fixed (platform dependant). Modified: python/branches/py3k/Lib/test/test_threading.py python/branches/py3k/Lib/threading.py Modified: python/branches/py3k/Lib/test/test_threading.py ============================================================================== --- python/branches/py3k/Lib/test/test_threading.py (original) +++ python/branches/py3k/Lib/test/test_threading.py Mon Jan 3 22:06:12 2011 @@ -11,6 +11,7 @@ import unittest import weakref import os +import subprocess from test import lock_tests @@ -272,7 +273,6 @@ except ImportError: raise unittest.SkipTest("cannot import ctypes") - import subprocess rc = subprocess.call([sys.executable, "-c", """if 1: import ctypes, sys, time, _thread @@ -303,7 +303,6 @@ def test_finalize_with_trace(self): # Issue1733757 # Avoid a deadlock when sys.settrace steps into threading._shutdown - import subprocess p = subprocess.Popen([sys.executable, "-c", """if 1: import sys, threading @@ -338,7 +337,6 @@ def test_join_nondaemon_on_shutdown(self): # Issue 1722344 # Raising SystemExit skipped threading._shutdown - import subprocess p = subprocess.Popen([sys.executable, "-c", """if 1: import threading from time import sleep @@ -445,7 +443,6 @@ sys.stdout.flush() \n""" + script - import subprocess p = subprocess.Popen([sys.executable, "-c", script], stdout=subprocess.PIPE) rc = p.wait() data = p.stdout.read().decode().replace('\r', '') @@ -512,6 +509,152 @@ """ self._run_and_join(script) + def assertScriptHasOutput(self, script, expected_output): + p = subprocess.Popen([sys.executable, "-c", script], + stdout=subprocess.PIPE) + rc = p.wait() + data = p.stdout.read().decode().replace('\r', '') + self.assertEqual(rc, 0, "Unexpected error") + self.assertEqual(data, expected_output) + + @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + def test_4_joining_across_fork_in_worker_thread(self): + # There used to be a possible deadlock when forking from a child + # thread. See http://bugs.python.org/issue6643. + + # Skip platforms with known problems forking from a worker thread. + # See http://bugs.python.org/issue3863. + if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): + raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) + + # The script takes the following steps: + # - The main thread in the parent process starts a new thread and then + # tries to join it. + # - The join operation acquires the Lock inside the thread's _block + # Condition. (See threading.py:Thread.join().) + # - We stub out the acquire method on the condition to force it to wait + # until the child thread forks. (See LOCK ACQUIRED HERE) + # - The child thread forks. (See LOCK HELD and WORKER THREAD FORKS + # HERE) + # - The main thread of the parent process enters Condition.wait(), + # which releases the lock on the child thread. + # - The child process returns. Without the necessary fix, when the + # main thread of the child process (which used to be the child thread + # in the parent process) attempts to exit, it will try to acquire the + # lock in the Thread._block Condition object and hang, because the + # lock was held across the fork. + + script = """if 1: + import os, time, threading + + finish_join = False + start_fork = False + + def worker(): + # Wait until this thread's lock is acquired before forking to + # create the deadlock. + global finish_join + while not start_fork: + time.sleep(0.01) + # LOCK HELD: Main thread holds lock across this call. + childpid = os.fork() + finish_join = True + if childpid != 0: + # Parent process just waits for child. + os.waitpid(childpid, 0) + # Child process should just return. + + w = threading.Thread(target=worker) + + # Stub out the private condition variable's lock acquire method. + # This acquires the lock and then waits until the child has forked + # before returning, which will release the lock soon after. If + # someone else tries to fix this test case by acquiring this lock + # before forking instead of reseting it, the test case will + # deadlock when it shouldn't. + condition = w._block + orig_acquire = condition.acquire + call_count_lock = threading.Lock() + call_count = 0 + def my_acquire(): + global call_count + global start_fork + orig_acquire() # LOCK ACQUIRED HERE + start_fork = True + if call_count == 0: + while not finish_join: + time.sleep(0.01) # WORKER THREAD FORKS HERE + with call_count_lock: + call_count += 1 + condition.acquire = my_acquire + + w.start() + w.join() + print('end of main') + """ + self.assertScriptHasOutput(script, "end of main\n") + + @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + def test_5_clear_waiter_locks_to_avoid_crash(self): + # Check that a spawned thread that forks doesn't segfault on certain + # platforms, namely OS X. This used to happen if there was a waiter + # lock in the thread's condition variable's waiters list. Even though + # we know the lock will be held across the fork, it is not safe to + # release locks held across forks on all platforms, so releasing the + # waiter lock caused a segfault on OS X. Furthermore, since locks on + # OS X are (as of this writing) implemented with a mutex + condition + # variable instead of a semaphore, while we know that the Python-level + # lock will be acquired, we can't know if the internal mutex will be + # acquired at the time of the fork. + + # Skip platforms with known problems forking from a worker thread. + # See http://bugs.python.org/issue3863. + if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): + raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) + script = """if True: + import os, time, threading + + start_fork = False + + def worker(): + # Wait until the main thread has attempted to join this thread + # before continuing. + while not start_fork: + time.sleep(0.01) + childpid = os.fork() + if childpid != 0: + # Parent process just waits for child. + (cpid, rc) = os.waitpid(childpid, 0) + assert cpid == childpid + assert rc == 0 + print('end of worker thread') + else: + # Child process should just return. + pass + + w = threading.Thread(target=worker) + + # Stub out the private condition variable's _release_save method. + # This releases the condition's lock and flips the global that + # causes the worker to fork. At this point, the problematic waiter + # lock has been acquired once by the waiter and has been put onto + # the waiters list. + condition = w._block + orig_release_save = condition._release_save + def my_release_save(): + global start_fork + orig_release_save() + # Waiter lock held here, condition lock released. + start_fork = True + condition._release_save = my_release_save + + w.start() + w.join() + print('end of main thread') + """ + output = "end of worker thread\nend of main thread\n" + self.assertScriptHasOutput(script, output) + class ThreadingExceptionTests(BaseTestCase): # A RuntimeError should be raised if Thread.start() is called Modified: python/branches/py3k/Lib/threading.py ============================================================================== --- python/branches/py3k/Lib/threading.py (original) +++ python/branches/py3k/Lib/threading.py Mon Jan 3 22:06:12 2011 @@ -1064,6 +1064,10 @@ # its new value since it can have changed. ident = _get_ident() thread._ident = ident + # Any condition variables hanging off of the active thread may + # be in an invalid state, so we reinitialize them. + thread._block.__init__() + thread._started._cond.__init__() new_active[ident] = thread else: # All the others are already stopped. From python-checkins at python.org Mon Jan 3 22:09:23 2011 From: python-checkins at python.org (gregory.p.smith) Date: Mon, 3 Jan 2011 22:09:23 +0100 (CET) Subject: [Python-checkins] r87711 - python/branches/py3k/Misc/NEWS Message-ID: <20110103210923.A7F50EE989@mail.python.org> Author: gregory.p.smith Date: Mon Jan 3 22:09:23 2011 New Revision: 87711 Log: news for 6643 Modified: python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 3 22:09:23 2011 @@ -23,6 +23,9 @@ Library ------- +- Issue #6643: Reinitialize locks held within the threading module after fork + to avoid a potential rare deadlock or crash on some platforms. + - Issue #10806, issue #9905: Fix subprocess pipes when some of the standard file descriptors (0, 1, 2) are closed in the parent process. Initial patch by Ross Lagerwall. From python-checkins at python.org Mon Jan 3 22:15:48 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 22:15:48 +0100 (CET) Subject: [Python-checkins] r87712 - python/branches/py3k/Lib/test/test_subprocess.py Message-ID: <20110103211548.81DFBEE989@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 22:15:48 2011 New Revision: 87712 Log: Add a subprocess test of remapping standard file descriptors (issue #1187). Modified: python/branches/py3k/Lib/test/test_subprocess.py Modified: python/branches/py3k/Lib/test/test_subprocess.py ============================================================================== --- python/branches/py3k/Lib/test/test_subprocess.py (original) +++ python/branches/py3k/Lib/test/test_subprocess.py Mon Jan 3 22:15:48 2011 @@ -955,6 +955,54 @@ # all standard fds closed. self.check_close_std_fds([0, 1, 2]) + def test_remapping_std_fds(self): + # open up some temporary files + temps = [mkstemp() for i in range(3)] + try: + temp_fds = [fd for fd, fname in temps] + + # unlink the files -- we won't need to reopen them + for fd, fname in temps: + os.unlink(fname) + + # write some data to what will become stdin, and rewind + os.write(temp_fds[1], b"STDIN") + os.lseek(temp_fds[1], 0, 0) + + # move the standard file descriptors out of the way + saved_fds = [os.dup(fd) for fd in range(3)] + try: + # duplicate the file objects over the standard fd's + for fd, temp_fd in enumerate(temp_fds): + os.dup2(temp_fd, fd) + + # now use those files in the "wrong" order, so that subprocess + # has to rearrange them in the child + p = subprocess.Popen([sys.executable, "-c", + 'import sys; got = sys.stdin.read();' + 'sys.stdout.write("got %s"%got); sys.stderr.write("err")'], + stdin=temp_fds[1], + stdout=temp_fds[2], + stderr=temp_fds[0]) + p.wait() + finally: + # restore the original fd's underneath sys.stdin, etc. + for std, saved in enumerate(saved_fds): + os.dup2(saved, std) + os.close(saved) + + for fd in temp_fds: + os.lseek(fd, 0, 0) + + out = os.read(temp_fds[2], 1024) + err = support.strip_python_stderr(os.read(temp_fds[0], 1024)) + self.assertEqual(out, b"got STDIN") + self.assertEqual(err, b"err") + + finally: + for fd in temp_fds: + os.close(fd) + def test_surrogates_error_message(self): def prepare(): raise ValueError("surrogate:\uDCff") From python-checkins at python.org Mon Jan 3 23:12:43 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 23:12:43 +0100 (CET) Subject: [Python-checkins] r87713 - python/branches/py3k/Lib/test/test_subprocess.py Message-ID: <20110103221243.BD1BCEE9F5@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 23:12:43 2011 New Revision: 87713 Log: Temporary debug output for intermittent failures in test_subprocess Modified: python/branches/py3k/Lib/test/test_subprocess.py Modified: python/branches/py3k/Lib/test/test_subprocess.py ============================================================================== --- python/branches/py3k/Lib/test/test_subprocess.py (original) +++ python/branches/py3k/Lib/test/test_subprocess.py Mon Jan 3 23:12:43 2011 @@ -1170,6 +1170,10 @@ remaining_fds = set(map(int, output.split(b','))) to_be_closed = open_fds - {fd} + # Temporary debug output for intermittent failures + if support.verbose: + print(" -- fds that should have been closed:", to_be_closed) + print(" -- fds that remained open:", remaining_fds) self.assertIn(fd, remaining_fds, "fd to be passed not passed") self.assertFalse(remaining_fds & to_be_closed, From python-checkins at python.org Mon Jan 3 23:24:52 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 3 Jan 2011 23:24:52 +0100 (CET) Subject: [Python-checkins] r87714 - python/branches/py3k/Lib/test/test_subprocess.py Message-ID: <20110103222452.C3736EE995@mail.python.org> Author: antoine.pitrou Date: Mon Jan 3 23:24:52 2011 New Revision: 87714 Log: Add some more output Modified: python/branches/py3k/Lib/test/test_subprocess.py Modified: python/branches/py3k/Lib/test/test_subprocess.py ============================================================================== --- python/branches/py3k/Lib/test/test_subprocess.py (original) +++ python/branches/py3k/Lib/test/test_subprocess.py Mon Jan 3 23:24:52 2011 @@ -1156,6 +1156,9 @@ open_fds = set() + if support.verbose: + print(" -- maxfd =", subprocess.MAXFD) + for x in range(5): fds = os.pipe() self.addCleanup(os.close, fds[0]) From python-checkins at python.org Mon Jan 3 23:35:43 2011 From: python-checkins at python.org (victor.stinner) Date: Mon, 3 Jan 2011 23:35:43 +0100 (CET) Subject: [Python-checkins] r87715 - in python/branches/release27-maint: Lib/test/test_pep277.py Message-ID: <20110103223543.AB76BEE9A0@mail.python.org> Author: victor.stinner Date: Mon Jan 3 23:35:43 2011 New Revision: 87715 Log: Recorded merge of revisions 85881,85897,85899 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r85881 | victor.stinner | 2010-10-28 13:20:31 +0200 (jeu., 28 oct. 2010) | 2 lines test_pep277: add identifiers to filenames ........ r85897 | victor.stinner | 2010-10-29 00:57:03 +0200 (ven., 29 oct. 2010) | 5 lines test_pep277: disable filenames 11, 12, 13, 14 on darwin Because darwin "normalizes" these filenames differently than Python's NFD normalization. ........ r85899 | victor.stinner | 2010-10-29 01:14:45 +0200 (ven., 29 oct. 2010) | 4 lines #10209, test_pep277: disable test_normalize and test_listdir on darwin These tests are irrevelant on this OS. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/test/test_pep277.py Modified: python/branches/release27-maint/Lib/test/test_pep277.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_pep277.py (original) +++ python/branches/release27-maint/Lib/test/test_pep277.py Mon Jan 3 23:35:43 2011 @@ -5,22 +5,17 @@ from test import test_support filenames = [ - 'abc', - u'ascii', - u'Gr\xfc\xdf-Gott', - u'\u0393\u03b5\u03b9\u03ac-\u03c3\u03b1\u03c2', - u'\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435', - u'\u306b\u307d\u3093', - u'\u05d4\u05e9\u05e7\u05e6\u05e5\u05e1', - u'\u66e8\u66e9\u66eb', - u'\u66e8\u05e9\u3093\u0434\u0393\xdf', + '1_abc', + u'2_ascii', + u'3_Gr\xfc\xdf-Gott', + u'4_\u0393\u03b5\u03b9\u03ac-\u03c3\u03b1\u03c2', + u'5_\u0417\u0434\u0440\u0430\u0432\u0441\u0442\u0432\u0443\u0439\u0442\u0435', + u'6_\u306b\u307d\u3093', + u'7_\u05d4\u05e9\u05e7\u05e6\u05e5\u05e1', + u'8_\u66e8\u66e9\u66eb', + u'9_\u66e8\u05e9\u3093\u0434\u0393\xdf', # Specific code points: fn, NFC(fn) and NFKC(fn) all differents - u'\u1fee\u1ffd', - # Specific code points: NFC(fn), NFD(fn), NFKC(fn) and NFKD(fn) all differents - u'\u0385\u03d3\u03d4', - u'\u00a8\u0301\u03d2\u0301\u03d2\u0308', # == NFD(u'\u0385\u03d3\u03d4') - u'\u0020\u0308\u0301\u038e\u03ab', # == NFKC(u'\u0385\u03d3\u03d4') - u'\u1e9b\u1fc1\u1fcd\u1fce\u1fcf\u1fdd\u1fde\u1fdf\u1fed', + u'10_\u1fee\u1ffd', ] # Mac OS X decomposes Unicode names, using Normal Form D. @@ -31,13 +26,19 @@ # U+2FAFF are not decomposed." if sys.platform != 'darwin': filenames.extend([ + # Specific code points: NFC(fn), NFD(fn), NFKC(fn) and NFKD(fn) all differents + u'11_\u0385\u03d3\u03d4', + u'12_\u00a8\u0301\u03d2\u0301\u03d2\u0308', # == NFD(u'\u0385\u03d3\u03d4') + u'13_\u0020\u0308\u0301\u038e\u03ab', # == NFKC(u'\u0385\u03d3\u03d4') + u'14_\u1e9b\u1fc1\u1fcd\u1fce\u1fcf\u1fdd\u1fde\u1fdf\u1fed', + # Specific code points: fn, NFC(fn) and NFKC(fn) all differents - u'\u1fee\u1ffd\ufad1', - u'\u2000\u2000\u2000A', - u'\u2001\u2001\u2001A', - u'\u2003\u2003\u2003A', # == NFC(u'\u2001\u2001\u2001A') - u'\u0020\u0020\u0020A', # u'\u0020' == u' ' == NFKC(u'\u2000') == - # NFKC(u'\u2001') == NFKC(u'\u2003') + u'15_\u1fee\u1ffd\ufad1', + u'16_\u2000\u2000\u2000A', + u'17_\u2001\u2001\u2001A', + u'18_\u2003\u2003\u2003A', # == NFC(u'\u2001\u2001\u2001A') + u'19_\u0020\u0020\u0020A', # u'\u0020' == u' ' == NFKC(u'\u2000') == + # NFKC(u'\u2001') == NFKC(u'\u2003') ]) @@ -121,19 +122,18 @@ f.close() os.stat(name) + # Skip the test on darwin, because darwin does normalize the filename to + # NFD (a variant of Unicode NFD form). Normalize the filename to NFC, NFKC, + # NFKD in Python is useless, because darwin will normalize it later and so + # open(), os.stat(), etc. don't raise any exception. + @unittest.skipIf(sys.platform == 'darwin', 'irrevelant test on Mac OS X') def test_normalize(self): files = set(f for f in self.files if isinstance(f, unicode)) others = set() for nf in set(['NFC', 'NFD', 'NFKC', 'NFKD']): others |= set(normalize(nf, file) for file in files) others -= files - if sys.platform == 'darwin': - files = set(normalize('NFD', file) for file in files) for name in others: - if sys.platform == 'darwin' and normalize('NFD', name) in files: - # Mac OS X decomposes Unicode names. See comment above. - os.stat(name) - continue self._apply_failure(open, name, IOError) self._apply_failure(os.stat, name, OSError) self._apply_failure(os.chdir, name, OSError) @@ -142,15 +142,15 @@ # listdir may append a wildcard to the filename, so dont check self._apply_failure(os.listdir, name, OSError, False) + # Skip the test on darwin, because darwin uses a normalization different + # than Python NFD normalization: filenames are different even if we use + # Python NFD normalization. + @unittest.skipIf(sys.platform == 'darwin', 'irrevelant test on Mac OS X') def test_listdir(self): sf0 = set(self.files) f1 = os.listdir(test_support.TESTFN) f2 = os.listdir(unicode(test_support.TESTFN, sys.getfilesystemencoding())) - if sys.platform == 'darwin': - # Mac OS X decomposes Unicode names. See comment above. - sf0 = set(normalize('NFD', unicode(f)) for f in self.files) - f2 = [normalize('NFD', unicode(f)) for f in f2] sf2 = set(os.path.join(unicode(test_support.TESTFN), f) for f in f2) self.assertEqual(sf0, sf2) self.assertEqual(len(f1), len(f2)) From python-checkins at python.org Tue Jan 4 00:42:02 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 4 Jan 2011 00:42:02 +0100 (CET) Subject: [Python-checkins] r87716 - python/branches/py3k/Lib/subprocess.py Message-ID: <20110103234202.149C7EE994@mail.python.org> Author: antoine.pitrou Date: Tue Jan 4 00:42:01 2011 New Revision: 87716 Log: Un-complicate some code Modified: python/branches/py3k/Lib/subprocess.py Modified: python/branches/py3k/Lib/subprocess.py ============================================================================== --- python/branches/py3k/Lib/subprocess.py (original) +++ python/branches/py3k/Lib/subprocess.py Tue Jan 4 00:42:01 2011 @@ -1092,15 +1092,9 @@ errread, errwrite) - def _close_fds(self, but): - os.closerange(3, but) - os.closerange(but + 1, MAXFD) - - - def _close_all_but_a_sorted_few_fds(self, fds_to_keep): - # precondition: fds_to_keep must be sorted and unique + def _close_fds(self, fds_to_keep): start_fd = 3 - for fd in fds_to_keep: + for fd in sorted(fds_to_keep): if fd >= start_fd: os.closerange(start_fd, fd) start_fd = fd + 1 @@ -1216,13 +1210,9 @@ # Close all other fds, if asked for if close_fds: - if pass_fds: - fds_to_keep = set(pass_fds) - fds_to_keep.add(errpipe_write) - self._close_all_but_a_sorted_few_fds( - sorted(fds_to_keep)) - else: - self._close_fds(but=errpipe_write) + fds_to_keep = set(pass_fds) + fds_to_keep.add(errpipe_write) + self._close_fds(fds_to_keep) if cwd is not None: From python-checkins at python.org Tue Jan 4 00:56:12 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 00:56:12 +0100 (CET) Subject: [Python-checkins] r87717 - in python/branches/py3k/Lib/unittest/test: test_assertions.py test_case.py Message-ID: <20110103235612.559BCEE98F@mail.python.org> Author: victor.stinner Date: Tue Jan 4 00:56:12 2011 New Revision: 87717 Log: fix test_unittest: ignore DeprecationWarning on assertDictContainsSubset() Modified: python/branches/py3k/Lib/unittest/test/test_assertions.py python/branches/py3k/Lib/unittest/test/test_case.py Modified: python/branches/py3k/Lib/unittest/test/test_assertions.py ============================================================================== --- python/branches/py3k/Lib/unittest/test/test_assertions.py (original) +++ python/branches/py3k/Lib/unittest/test/test_assertions.py Tue Jan 4 00:56:12 2011 @@ -1,5 +1,5 @@ import datetime - +import warnings import unittest @@ -224,10 +224,13 @@ "\+ \{'key': 'value'\} : oops$"]) def testAssertDictContainsSubset(self): - self.assertMessages('assertDictContainsSubset', ({'key': 'value'}, {}), - ["^Missing: 'key'$", "^oops$", - "^Missing: 'key'$", - "^Missing: 'key' : oops$"]) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + + self.assertMessages('assertDictContainsSubset', ({'key': 'value'}, {}), + ["^Missing: 'key'$", "^oops$", + "^Missing: 'key'$", + "^Missing: 'key' : oops$"]) def testAssertMultiLineEqual(self): self.assertMessages('assertMultiLineEqual', ("", "foo"), Modified: python/branches/py3k/Lib/unittest/test/test_case.py ============================================================================== --- python/branches/py3k/Lib/unittest/test/test_case.py (original) +++ python/branches/py3k/Lib/unittest/test/test_case.py Tue Jan 4 00:56:12 2011 @@ -489,31 +489,34 @@ animals) def testAssertDictContainsSubset(self): - self.assertDictContainsSubset({}, {}) - self.assertDictContainsSubset({}, {'a': 1}) - self.assertDictContainsSubset({'a': 1}, {'a': 1}) - self.assertDictContainsSubset({'a': 1}, {'a': 1, 'b': 2}) - self.assertDictContainsSubset({'a': 1, 'b': 2}, {'a': 1, 'b': 2}) + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) - with self.assertRaises(self.failureException): - self.assertDictContainsSubset({1: "one"}, {}) + self.assertDictContainsSubset({}, {}) + self.assertDictContainsSubset({}, {'a': 1}) + self.assertDictContainsSubset({'a': 1}, {'a': 1}) + self.assertDictContainsSubset({'a': 1}, {'a': 1, 'b': 2}) + self.assertDictContainsSubset({'a': 1, 'b': 2}, {'a': 1, 'b': 2}) - with self.assertRaises(self.failureException): - self.assertDictContainsSubset({'a': 2}, {'a': 1}) + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({1: "one"}, {}) - with self.assertRaises(self.failureException): - self.assertDictContainsSubset({'c': 1}, {'a': 1}) + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({'a': 2}, {'a': 1}) - with self.assertRaises(self.failureException): - self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1}) + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({'c': 1}, {'a': 1}) - with self.assertRaises(self.failureException): - self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1}) + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1}) - one = ''.join(chr(i) for i in range(255)) - # this used to cause a UnicodeDecodeError constructing the failure msg - with self.assertRaises(self.failureException): - self.assertDictContainsSubset({'foo': one}, {'foo': '\uFFFD'}) + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({'a': 1, 'c': 1}, {'a': 1}) + + one = ''.join(chr(i) for i in range(255)) + # this used to cause a UnicodeDecodeError constructing the failure msg + with self.assertRaises(self.failureException): + self.assertDictContainsSubset({'foo': one}, {'foo': '\uFFFD'}) def testAssertEqual(self): equal_pairs = [ From python-checkins at python.org Tue Jan 4 01:00:31 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 4 Jan 2011 01:00:31 +0100 (CET) Subject: [Python-checkins] r87718 - in python/branches/py3k: Include/objimpl.h Misc/NEWS Modules/gcmodule.c Modules/pyexpat.c Message-ID: <20110104000031.54E09EE995@mail.python.org> Author: antoine.pitrou Date: Tue Jan 4 01:00:31 2011 New Revision: 87718 Log: Issue #10333: Remove ancient GC API, which has been deprecated since Python 2.2. Modified: python/branches/py3k/Include/objimpl.h python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/gcmodule.c python/branches/py3k/Modules/pyexpat.c Modified: python/branches/py3k/Include/objimpl.h ============================================================================== --- python/branches/py3k/Include/objimpl.h (original) +++ python/branches/py3k/Include/objimpl.h Tue Jan 4 01:00:31 2011 @@ -242,9 +242,6 @@ #define PyObject_GC_Resize(type, op, n) \ ( (type *) _PyObject_GC_Resize((PyVarObject *)(op), (n)) ) -/* for source compatibility with 2.2 */ -#define _PyObject_GC_Del PyObject_GC_Del - /* GC information is stored BEFORE the object structure. */ #ifndef Py_LIMITED_API typedef union _gc_head { @@ -328,15 +325,6 @@ } \ } while (0) -/* This is here for the sake of backwards compatibility. Extensions that - * use the old GC API will still compile but the objects will not be - * tracked by the GC. */ -#define PyGC_HEAD_SIZE 0 -#define PyObject_GC_Init(op) -#define PyObject_GC_Fini(op) -#define PyObject_AS_GC(op) (op) -#define PyObject_FROM_GC(op) (op) - /* Test if a type supports weak references */ #define PyType_SUPPORTS_WEAKREFS(t) ((t)->tp_weaklistoffset > 0) Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Tue Jan 4 01:00:31 2011 @@ -101,6 +101,12 @@ - Deprecated assertDictContainsSubset() in the unittest module. +C-API +----- + +- Issue #10333: Remove ancient GC API, which has been deprecated since + Python 2.2. + Build ----- Modified: python/branches/py3k/Modules/gcmodule.c ============================================================================== --- python/branches/py3k/Modules/gcmodule.c (original) +++ python/branches/py3k/Modules/gcmodule.c Tue Jan 4 01:00:31 2011 @@ -1511,11 +1511,3 @@ } PyObject_FREE(g); } - -/* for binary compatibility with 2.2 */ -#undef _PyObject_GC_Del -void -_PyObject_GC_Del(PyObject *op) -{ - PyObject_GC_Del(op); -} Modified: python/branches/py3k/Modules/pyexpat.c ============================================================================== --- python/branches/py3k/Modules/pyexpat.c (original) +++ python/branches/py3k/Modules/pyexpat.c Tue Jan 4 01:00:31 2011 @@ -1522,7 +1522,7 @@ static PyTypeObject Xmlparsetype = { PyVarObject_HEAD_INIT(NULL, 0) "pyexpat.xmlparser", /*tp_name*/ - sizeof(xmlparseobject) + PyGC_HEAD_SIZE,/*tp_basicsize*/ + sizeof(xmlparseobject), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)xmlparse_dealloc, /*tp_dealloc*/ From python-checkins at python.org Tue Jan 4 01:04:44 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 01:04:44 +0100 (CET) Subject: [Python-checkins] r87719 - python/branches/py3k/Lib/test/test_array.py Message-ID: <20110104000444.C78EBEE995@mail.python.org> Author: victor.stinner Date: Tue Jan 4 01:04:44 2011 New Revision: 87719 Log: test_array: fix the DeprecationWarning('object.__init__() takes no parameters') Modified: python/branches/py3k/Lib/test/test_array.py Modified: python/branches/py3k/Lib/test/test_array.py ============================================================================== --- python/branches/py3k/Lib/test/test_array.py (original) +++ python/branches/py3k/Lib/test/test_array.py Tue Jan 4 01:04:44 2011 @@ -22,7 +22,7 @@ class ArraySubclassWithKwargs(array.array): def __init__(self, typecode, newarg=None): - array.array.__init__(self, typecode) + array.array.__init__(self) tests = [] # list to accumulate all tests typecodes = "ubBhHiIlLfd" From python-checkins at python.org Tue Jan 4 01:04:46 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 01:04:46 +0100 (CET) Subject: [Python-checkins] r87720 - python/branches/py3k/Lib/test/test_httplib.py Message-ID: <20110104000446.59F7BEE9E3@mail.python.org> Author: victor.stinner Date: Tue Jan 4 01:04:46 2011 New Revision: 87720 Log: test_httplib: fix a DeprecationWarning, assertEquals=>assertEqual Modified: python/branches/py3k/Lib/test/test_httplib.py Modified: python/branches/py3k/Lib/test/test_httplib.py ============================================================================== --- python/branches/py3k/Lib/test/test_httplib.py (original) +++ python/branches/py3k/Lib/test/test_httplib.py Tue Jan 4 01:04:46 2011 @@ -244,7 +244,7 @@ sock = FakeSocket("") conn.sock = sock conn.request('GET', '/foo', body(), {'Content-Length': '11'}) - self.assertEquals(sock.data, expected) + self.assertEqual(sock.data, expected) def test_chunked(self): chunked_start = ( From python-checkins at python.org Tue Jan 4 01:24:03 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 4 Jan 2011 01:24:03 +0100 (CET) Subject: [Python-checkins] r87721 - python/branches/py3k/Lib/test/test_ttk_guionly.py Message-ID: <20110104002403.9FF63EEA38@mail.python.org> Author: antoine.pitrou Date: Tue Jan 4 01:24:03 2011 New Revision: 87721 Log: Issue #10267: Fix refleak in test_ttk_guionly. Patch by Hirokazu Yamamoto. Modified: python/branches/py3k/Lib/test/test_ttk_guionly.py Modified: python/branches/py3k/Lib/test/test_ttk_guionly.py ============================================================================== --- python/branches/py3k/Lib/test/test_ttk_guionly.py (original) +++ python/branches/py3k/Lib/test/test_ttk_guionly.py Tue Jan 4 01:24:03 2011 @@ -8,6 +8,7 @@ from _tkinter import TclError from tkinter import ttk from tkinter.test import runtktests +from tkinter.test.support import get_tk_root try: ttk.Button() @@ -22,8 +23,11 @@ elif 'gui' not in support.use_resources: support.use_resources.append('gui') - support.run_unittest( - *runtktests.get_tests(text=False, packages=['test_ttk'])) + try: + support.run_unittest( + *runtktests.get_tests(text=False, packages=['test_ttk'])) + finally: + get_tk_root().destroy() if __name__ == '__main__': test_main(enable_gui=True) From python-checkins at python.org Tue Jan 4 01:29:35 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 01:29:35 +0100 (CET) Subject: [Python-checkins] r87722 - in python/branches/py3k: Misc/NEWS Modules/_io/fileio.c Modules/posixmodule.c Message-ID: <20110104002935.76B29EE989@mail.python.org> Author: victor.stinner Date: Tue Jan 4 01:29:35 2011 New Revision: 87722 Log: Issue #9015, #9611: FileIO.readinto(), FileIO.write() and os.write() clamp the length to 2^31-1 on Windows. Modified: python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/_io/fileio.c python/branches/py3k/Modules/posixmodule.c Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Tue Jan 4 01:29:35 2011 @@ -8,6 +8,9 @@ Core and Builtins ----------------- +- Issue #9015, #9611: FileIO.readinto(), FileIO.write() and os.write() clamp + the length to 2^31-1 on Windows. + - Issue #8278: On Windows and with a NTFS filesystem, os.stat() and os.utime() can now handle dates after 2038. Modified: python/branches/py3k/Modules/_io/fileio.c ============================================================================== --- python/branches/py3k/Modules/_io/fileio.c (original) +++ python/branches/py3k/Modules/_io/fileio.c Tue Jan 4 01:29:35 2011 @@ -506,7 +506,7 @@ fileio_readinto(fileio *self, PyObject *args) { Py_buffer pbuf; - Py_ssize_t n; + Py_ssize_t n, len; if (self->fd < 0) return err_closed(); @@ -517,9 +517,16 @@ return NULL; if (_PyVerify_fd(self->fd)) { + len = pbuf.len; Py_BEGIN_ALLOW_THREADS errno = 0; - n = read(self->fd, pbuf.buf, pbuf.len); +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (len > INT_MAX) + len = INT_MAX; + n = read(self->fd, pbuf.buf, (int)len); +#else + n = read(self->fd, pbuf.buf, (size_t)len); +#endif Py_END_ALLOW_THREADS } else n = -1; @@ -685,7 +692,7 @@ fileio_write(fileio *self, PyObject *args) { Py_buffer pbuf; - Py_ssize_t n; + Py_ssize_t n, len; if (self->fd < 0) return err_closed(); @@ -698,7 +705,14 @@ if (_PyVerify_fd(self->fd)) { Py_BEGIN_ALLOW_THREADS errno = 0; - n = write(self->fd, pbuf.buf, pbuf.len); + len = pbuf.len; +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (len > INT_MAX) + len = INT_MAX; + n = write(self->fd, pbuf.buf, (int)len); +#else + n = write(self->fd, pbuf.buf, (size_t)len); +#endif Py_END_ALLOW_THREADS } else n = -1; Modified: python/branches/py3k/Modules/posixmodule.c ============================================================================== --- python/branches/py3k/Modules/posixmodule.c (original) +++ python/branches/py3k/Modules/posixmodule.c Tue Jan 4 01:29:35 2011 @@ -5696,7 +5696,7 @@ { Py_buffer pbuf; int fd; - Py_ssize_t size; + Py_ssize_t size, len; if (!PyArg_ParseTuple(args, "iy*:write", &fd, &pbuf)) return NULL; @@ -5704,8 +5704,15 @@ PyBuffer_Release(&pbuf); return posix_error(); } + len = pbuf.len; Py_BEGIN_ALLOW_THREADS - size = write(fd, pbuf.buf, (size_t)pbuf.len); +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (len > INT_MAX) + len = INT_MAX; + size = write(fd, pbuf.buf, (int)len); +#else + size = write(fd, pbuf.buf, (size_t)len); +#endif Py_END_ALLOW_THREADS PyBuffer_Release(&pbuf); if (size < 0) From python-checkins at python.org Tue Jan 4 01:32:11 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 4 Jan 2011 01:32:11 +0100 (CET) Subject: [Python-checkins] r87723 - in python/branches/release27-maint: Lib/test/test_ttk_guionly.py Message-ID: <20110104003211.B2E5AEE989@mail.python.org> Author: antoine.pitrou Date: Tue Jan 4 01:32:11 2011 New Revision: 87723 Log: Merged revisions 87721 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87721 | antoine.pitrou | 2011-01-04 01:24:03 +0100 (mar., 04 janv. 2011) | 3 lines Issue #10267: Fix refleak in test_ttk_guionly. Patch by Hirokazu Yamamoto. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/test/test_ttk_guionly.py Modified: python/branches/release27-maint/Lib/test/test_ttk_guionly.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_ttk_guionly.py (original) +++ python/branches/release27-maint/Lib/test/test_ttk_guionly.py Tue Jan 4 01:32:11 2011 @@ -29,8 +29,12 @@ test_support.use_resources.append('gui') with test_support.DirsOnSysPath(lib_tk_test): - test_support.run_unittest( - *runtktests.get_tests(text=False, packages=['test_ttk'])) + from test_ttk.support import get_tk_root + try: + test_support.run_unittest( + *runtktests.get_tests(text=False, packages=['test_ttk'])) + finally: + get_tk_root().destroy() if __name__ == '__main__': test_main(enable_gui=True) From python-checkins at python.org Tue Jan 4 01:32:18 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 4 Jan 2011 01:32:18 +0100 (CET) Subject: [Python-checkins] r87724 - in python/branches/release31-maint: Lib/test/test_ttk_guionly.py Message-ID: <20110104003218.82552EEA2F@mail.python.org> Author: antoine.pitrou Date: Tue Jan 4 01:32:18 2011 New Revision: 87724 Log: Merged revisions 87721 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87721 | antoine.pitrou | 2011-01-04 01:24:03 +0100 (mar., 04 janv. 2011) | 3 lines Issue #10267: Fix refleak in test_ttk_guionly. Patch by Hirokazu Yamamoto. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/test/test_ttk_guionly.py Modified: python/branches/release31-maint/Lib/test/test_ttk_guionly.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_ttk_guionly.py (original) +++ python/branches/release31-maint/Lib/test/test_ttk_guionly.py Tue Jan 4 01:32:18 2011 @@ -9,6 +9,7 @@ from _tkinter import TclError from tkinter import ttk from tkinter.test import runtktests +from tkinter.test.support import get_tk_root try: ttk.Button() @@ -23,8 +24,11 @@ elif 'gui' not in support.use_resources: support.use_resources.append('gui') - support.run_unittest( - *runtktests.get_tests(text=False, packages=['test_ttk'])) + try: + support.run_unittest( + *runtktests.get_tests(text=False, packages=['test_ttk'])) + finally: + get_tk_root().destroy() if __name__ == '__main__': test_main(enable_gui=True) From python-checkins at python.org Tue Jan 4 01:50:39 2011 From: python-checkins at python.org (phillip.eby) Date: Tue, 4 Jan 2011 01:50:39 +0100 (CET) Subject: [Python-checkins] r87725 - peps/trunk/pep-3333.txt Message-ID: <20110104005039.3BC6CEEA26@mail.python.org> Author: phillip.eby Date: Tue Jan 4 01:50:38 2011 New Revision: 87725 Log: Update a couple of code samples for Python 3 Modified: peps/trunk/pep-3333.txt Modified: peps/trunk/pep-3333.txt ============================================================================== --- peps/trunk/pep-3333.txt (original) +++ peps/trunk/pep-3333.txt Tue Jan 4 01:50:38 2011 @@ -230,8 +230,7 @@ Here are two example application objects; one is a function, and the other is a class:: - # this would need to be a byte string in Python 3: - HELLO_WORLD = "Hello world!\n" + HELLO_WORLD = b"Hello world!\n" def simple_app(environ, start_response): """Simplest possible application object""" @@ -281,9 +280,14 @@ import os, sys - def run_with_cgi(application): + enc, esc = sys.getfilesystemencoding(), 'surrogateescape' + + def wsgi_string(u): + # Convert an environment variable to a WSGI "bytes-as-unicode" string + return u.encode(enc, esc).decode('iso-8859-1') - environ = dict(os.environ.items()) + def run_with_cgi(application): + environ = {k: wsgi_string(v) for k,v in os.environ.items()} environ['wsgi.input'] = sys.stdin environ['wsgi.errors'] = sys.stderr environ['wsgi.version'] = (1, 0) From python-checkins at python.org Tue Jan 4 01:51:50 2011 From: python-checkins at python.org (gregory.p.smith) Date: Tue, 4 Jan 2011 01:51:50 +0100 (CET) Subject: [Python-checkins] r87726 - in python/branches/release31-maint: Lib/test/test_threading.py Lib/threading.py Misc/NEWS Message-ID: <20110104005150.596EFEEA3B@mail.python.org> Author: gregory.p.smith Date: Tue Jan 4 01:51:50 2011 New Revision: 87726 Log: Merged revisions 87710 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87710 | gregory.p.smith | 2011-01-03 13:06:12 -0800 (Mon, 03 Jan 2011) | 4 lines issue6643 - Two locks held within the threading module on each thread instance needed to be reinitialized after fork(). Adds tests to confirm that they are and that a potential deadlock and crasher bug are fixed (platform dependant). ........ Modified: python/branches/release31-maint/Lib/test/test_threading.py python/branches/release31-maint/Lib/threading.py python/branches/release31-maint/Misc/NEWS Modified: python/branches/release31-maint/Lib/test/test_threading.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_threading.py (original) +++ python/branches/release31-maint/Lib/test/test_threading.py Tue Jan 4 01:51:50 2011 @@ -2,6 +2,7 @@ import test.support from test.support import verbose +import os import random import re import sys @@ -10,6 +11,7 @@ import time import unittest import weakref +import subprocess from test import lock_tests @@ -247,7 +249,6 @@ print("test_finalize_with_runnning_thread can't import ctypes") return # can't do anything - import subprocess rc = subprocess.call([sys.executable, "-c", """if 1: import ctypes, sys, time, _thread @@ -278,7 +279,6 @@ def test_finalize_with_trace(self): # Issue1733757 # Avoid a deadlock when sys.settrace steps into threading._shutdown - import subprocess p = subprocess.Popen([sys.executable, "-c", """if 1: import sys, threading @@ -311,7 +311,6 @@ def test_join_nondaemon_on_shutdown(self): # Issue 1722344 # Raising SystemExit skipped threading._shutdown - import subprocess p = subprocess.Popen([sys.executable, "-c", """if 1: import threading from time import sleep @@ -412,7 +411,6 @@ sys.stdout.flush() \n""" + script - import subprocess p = subprocess.Popen([sys.executable, "-c", script], stdout=subprocess.PIPE) rc = p.wait() data = p.stdout.read().decode().replace('\r', '') @@ -484,6 +482,152 @@ """ self._run_and_join(script) + def assertScriptHasOutput(self, script, expected_output): + p = subprocess.Popen([sys.executable, "-c", script], + stdout=subprocess.PIPE) + rc = p.wait() + data = p.stdout.read().decode().replace('\r', '') + self.assertEqual(rc, 0, "Unexpected error") + self.assertEqual(data, expected_output) + + @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + def test_4_joining_across_fork_in_worker_thread(self): + # There used to be a possible deadlock when forking from a child + # thread. See http://bugs.python.org/issue6643. + + # Skip platforms with known problems forking from a worker thread. + # See http://bugs.python.org/issue3863. + if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): + raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) + + # The script takes the following steps: + # - The main thread in the parent process starts a new thread and then + # tries to join it. + # - The join operation acquires the Lock inside the thread's _block + # Condition. (See threading.py:Thread.join().) + # - We stub out the acquire method on the condition to force it to wait + # until the child thread forks. (See LOCK ACQUIRED HERE) + # - The child thread forks. (See LOCK HELD and WORKER THREAD FORKS + # HERE) + # - The main thread of the parent process enters Condition.wait(), + # which releases the lock on the child thread. + # - The child process returns. Without the necessary fix, when the + # main thread of the child process (which used to be the child thread + # in the parent process) attempts to exit, it will try to acquire the + # lock in the Thread._block Condition object and hang, because the + # lock was held across the fork. + + script = """if 1: + import os, time, threading + + finish_join = False + start_fork = False + + def worker(): + # Wait until this thread's lock is acquired before forking to + # create the deadlock. + global finish_join + while not start_fork: + time.sleep(0.01) + # LOCK HELD: Main thread holds lock across this call. + childpid = os.fork() + finish_join = True + if childpid != 0: + # Parent process just waits for child. + os.waitpid(childpid, 0) + # Child process should just return. + + w = threading.Thread(target=worker) + + # Stub out the private condition variable's lock acquire method. + # This acquires the lock and then waits until the child has forked + # before returning, which will release the lock soon after. If + # someone else tries to fix this test case by acquiring this lock + # before forking instead of reseting it, the test case will + # deadlock when it shouldn't. + condition = w._block + orig_acquire = condition.acquire + call_count_lock = threading.Lock() + call_count = 0 + def my_acquire(): + global call_count + global start_fork + orig_acquire() # LOCK ACQUIRED HERE + start_fork = True + if call_count == 0: + while not finish_join: + time.sleep(0.01) # WORKER THREAD FORKS HERE + with call_count_lock: + call_count += 1 + condition.acquire = my_acquire + + w.start() + w.join() + print('end of main') + """ + self.assertScriptHasOutput(script, "end of main\n") + + @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + def test_5_clear_waiter_locks_to_avoid_crash(self): + # Check that a spawned thread that forks doesn't segfault on certain + # platforms, namely OS X. This used to happen if there was a waiter + # lock in the thread's condition variable's waiters list. Even though + # we know the lock will be held across the fork, it is not safe to + # release locks held across forks on all platforms, so releasing the + # waiter lock caused a segfault on OS X. Furthermore, since locks on + # OS X are (as of this writing) implemented with a mutex + condition + # variable instead of a semaphore, while we know that the Python-level + # lock will be acquired, we can't know if the internal mutex will be + # acquired at the time of the fork. + + # Skip platforms with known problems forking from a worker thread. + # See http://bugs.python.org/issue3863. + if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): + raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) + script = """if True: + import os, time, threading + + start_fork = False + + def worker(): + # Wait until the main thread has attempted to join this thread + # before continuing. + while not start_fork: + time.sleep(0.01) + childpid = os.fork() + if childpid != 0: + # Parent process just waits for child. + (cpid, rc) = os.waitpid(childpid, 0) + assert cpid == childpid + assert rc == 0 + print('end of worker thread') + else: + # Child process should just return. + pass + + w = threading.Thread(target=worker) + + # Stub out the private condition variable's _release_save method. + # This releases the condition's lock and flips the global that + # causes the worker to fork. At this point, the problematic waiter + # lock has been acquired once by the waiter and has been put onto + # the waiters list. + condition = w._block + orig_release_save = condition._release_save + def my_release_save(): + global start_fork + orig_release_save() + # Waiter lock held here, condition lock released. + start_fork = True + condition._release_save = my_release_save + + w.start() + w.join() + print('end of main thread') + """ + output = "end of worker thread\nend of main thread\n" + self.assertScriptHasOutput(script, output) + class ThreadingExceptionTests(unittest.TestCase): # A RuntimeError should be raised if Thread.start() is called Modified: python/branches/release31-maint/Lib/threading.py ============================================================================== --- python/branches/release31-maint/Lib/threading.py (original) +++ python/branches/release31-maint/Lib/threading.py Tue Jan 4 01:51:50 2011 @@ -856,6 +856,10 @@ # its new value since it can have changed. ident = _get_ident() thread._ident = ident + # Any condition variables hanging off of the active thread may + # be in an invalid state, so we reinitialize them. + thread._block.__init__() + thread._started._cond.__init__() new_active[ident] = thread else: # All the others are already stopped. Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Tue Jan 4 01:51:50 2011 @@ -27,6 +27,9 @@ Library ------- +- Issue #6643: Reinitialize locks held within the threading module after fork + to avoid a potential rare deadlock or crash on some platforms. + - Issue #10806, issue #9905: Fix subprocess pipes when some of the standard file descriptors (0, 1, 2) are closed in the parent process. Initial patch by Ross Lagerwall. From python-checkins at python.org Tue Jan 4 02:10:08 2011 From: python-checkins at python.org (gregory.p.smith) Date: Tue, 4 Jan 2011 02:10:08 +0100 (CET) Subject: [Python-checkins] r87727 - in python/branches/release27-maint/Lib: test/test_threading.py threading.py Message-ID: <20110104011008.73B04EEA42@mail.python.org> Author: gregory.p.smith Date: Tue Jan 4 02:10:08 2011 New Revision: 87727 Log: Merged revisions 87710 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87710 | gregory.p.smith | 2011-01-03 13:06:12 -0800 (Mon, 03 Jan 2011) | 4 lines issue6643 - Two locks held within the threading module on each thread instance needed to be reinitialized after fork(). Adds tests to confirm that they are and that a potential deadlock and crasher bug are fixed (platform dependant). ........ This required a bit more fiddling for 2.x as __block and __started are __ private as well as the __started Event's __cond. A new "private" _reset_internal_locks() method is added to Thread and _Event objects to address this. Modified: python/branches/release27-maint/Lib/test/test_threading.py python/branches/release27-maint/Lib/threading.py Modified: python/branches/release27-maint/Lib/test/test_threading.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_threading.py (original) +++ python/branches/release27-maint/Lib/test/test_threading.py Tue Jan 4 02:10:08 2011 @@ -10,6 +10,8 @@ import time import unittest import weakref +import os +import subprocess from test import lock_tests @@ -275,7 +277,6 @@ print("test_finalize_with_runnning_thread can't import ctypes") return # can't do anything - import subprocess rc = subprocess.call([sys.executable, "-c", """if 1: import ctypes, sys, time, thread @@ -306,7 +307,6 @@ def test_finalize_with_trace(self): # Issue1733757 # Avoid a deadlock when sys.settrace steps into threading._shutdown - import subprocess p = subprocess.Popen([sys.executable, "-c", """if 1: import sys, threading @@ -341,7 +341,6 @@ def test_join_nondaemon_on_shutdown(self): # Issue 1722344 # Raising SystemExit skipped threading._shutdown - import subprocess p = subprocess.Popen([sys.executable, "-c", """if 1: import threading from time import sleep @@ -428,7 +427,6 @@ print 'end of thread' \n""" + script - import subprocess p = subprocess.Popen([sys.executable, "-c", script], stdout=subprocess.PIPE) rc = p.wait() data = p.stdout.read().replace('\r', '') @@ -500,6 +498,152 @@ """ self._run_and_join(script) + def assertScriptHasOutput(self, script, expected_output): + p = subprocess.Popen([sys.executable, "-c", script], + stdout=subprocess.PIPE) + rc = p.wait() + data = p.stdout.read().decode().replace('\r', '') + self.assertEqual(rc, 0, "Unexpected error") + self.assertEqual(data, expected_output) + + @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + def test_4_joining_across_fork_in_worker_thread(self): + # There used to be a possible deadlock when forking from a child + # thread. See http://bugs.python.org/issue6643. + + # Skip platforms with known problems forking from a worker thread. + # See http://bugs.python.org/issue3863. + if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): + raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) + + # The script takes the following steps: + # - The main thread in the parent process starts a new thread and then + # tries to join it. + # - The join operation acquires the Lock inside the thread's _block + # Condition. (See threading.py:Thread.join().) + # - We stub out the acquire method on the condition to force it to wait + # until the child thread forks. (See LOCK ACQUIRED HERE) + # - The child thread forks. (See LOCK HELD and WORKER THREAD FORKS + # HERE) + # - The main thread of the parent process enters Condition.wait(), + # which releases the lock on the child thread. + # - The child process returns. Without the necessary fix, when the + # main thread of the child process (which used to be the child thread + # in the parent process) attempts to exit, it will try to acquire the + # lock in the Thread._block Condition object and hang, because the + # lock was held across the fork. + + script = """if 1: + import os, time, threading + + finish_join = False + start_fork = False + + def worker(): + # Wait until this thread's lock is acquired before forking to + # create the deadlock. + global finish_join + while not start_fork: + time.sleep(0.01) + # LOCK HELD: Main thread holds lock across this call. + childpid = os.fork() + finish_join = True + if childpid != 0: + # Parent process just waits for child. + os.waitpid(childpid, 0) + # Child process should just return. + + w = threading.Thread(target=worker) + + # Stub out the private condition variable's lock acquire method. + # This acquires the lock and then waits until the child has forked + # before returning, which will release the lock soon after. If + # someone else tries to fix this test case by acquiring this lock + # before forking instead of reseting it, the test case will + # deadlock when it shouldn't. + condition = w._block + orig_acquire = condition.acquire + call_count_lock = threading.Lock() + call_count = 0 + def my_acquire(): + global call_count + global start_fork + orig_acquire() # LOCK ACQUIRED HERE + start_fork = True + if call_count == 0: + while not finish_join: + time.sleep(0.01) # WORKER THREAD FORKS HERE + with call_count_lock: + call_count += 1 + condition.acquire = my_acquire + + w.start() + w.join() + print('end of main') + """ + self.assertScriptHasOutput(script, "end of main\n") + + @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") + def test_5_clear_waiter_locks_to_avoid_crash(self): + # Check that a spawned thread that forks doesn't segfault on certain + # platforms, namely OS X. This used to happen if there was a waiter + # lock in the thread's condition variable's waiters list. Even though + # we know the lock will be held across the fork, it is not safe to + # release locks held across forks on all platforms, so releasing the + # waiter lock caused a segfault on OS X. Furthermore, since locks on + # OS X are (as of this writing) implemented with a mutex + condition + # variable instead of a semaphore, while we know that the Python-level + # lock will be acquired, we can't know if the internal mutex will be + # acquired at the time of the fork. + + # Skip platforms with known problems forking from a worker thread. + # See http://bugs.python.org/issue3863. + if sys.platform in ('freebsd4', 'freebsd5', 'freebsd6', 'os2emx'): + raise unittest.SkipTest('due to known OS bugs on ' + sys.platform) + script = """if True: + import os, time, threading + + start_fork = False + + def worker(): + # Wait until the main thread has attempted to join this thread + # before continuing. + while not start_fork: + time.sleep(0.01) + childpid = os.fork() + if childpid != 0: + # Parent process just waits for child. + (cpid, rc) = os.waitpid(childpid, 0) + assert cpid == childpid + assert rc == 0 + print('end of worker thread') + else: + # Child process should just return. + pass + + w = threading.Thread(target=worker) + + # Stub out the private condition variable's _release_save method. + # This releases the condition's lock and flips the global that + # causes the worker to fork. At this point, the problematic waiter + # lock has been acquired once by the waiter and has been put onto + # the waiters list. + condition = w._block + orig_release_save = condition._release_save + def my_release_save(): + global start_fork + orig_release_save() + # Waiter lock held here, condition lock released. + start_fork = True + condition._release_save = my_release_save + + w.start() + w.join() + print('end of main thread') + """ + output = "end of worker thread\nend of main thread\n" + self.assertScriptHasOutput(script, output) + class ThreadingExceptionTests(BaseTestCase): # A RuntimeError should be raised if Thread.start() is called Modified: python/branches/release27-maint/Lib/threading.py ============================================================================== --- python/branches/release27-maint/Lib/threading.py (original) +++ python/branches/release27-maint/Lib/threading.py Tue Jan 4 02:10:08 2011 @@ -373,6 +373,10 @@ self.__cond = Condition(Lock()) self.__flag = False + def _reset_internal_locks(self): + # private! called by Thread._reset_internal_locks by _after_fork() + self.__cond.__init__() + def isSet(self): return self.__flag @@ -449,6 +453,17 @@ # sys.exc_info since it can be changed between instances self.__stderr = _sys.stderr + def _reset_internal_locks(self): + # private! Called by _after_fork() to reset our internal locks as + # they may be in an invalid state leading to a deadlock or crash. + self.__block.__init__() + self.__started._reset_internal_locks() + + @property + def _block(self): + # used by a unittest + return self.__block + def _set_daemon(self): # Overridden in _MainThread and _DummyThread return current_thread().daemon @@ -867,6 +882,9 @@ # its new value since it can have changed. ident = _get_ident() thread._Thread__ident = ident + # Any condition variables hanging off of the active thread may + # be in an invalid state, so we reinitialize them. + thread._reset_internal_locks() new_active[ident] = thread else: # All the others are already stopped. From python-checkins at python.org Tue Jan 4 03:07:34 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 03:07:34 +0100 (CET) Subject: [Python-checkins] r87728 - in python/branches/py3k: Lib/test/test_xml_etree_c.py Misc/NEWS Python/getargs.c Message-ID: <20110104020734.E20CCEEA95@mail.python.org> Author: victor.stinner Date: Tue Jan 4 03:07:34 2011 New Revision: 87728 Log: Issue #8651: PyArg_Parse*() functions raise an OverflowError if the file doesn't have PY_SSIZE_T_CLEAN define and the size doesn't fit in an int (length bigger than 2^31-1). Modified: python/branches/py3k/Lib/test/test_xml_etree_c.py python/branches/py3k/Misc/NEWS python/branches/py3k/Python/getargs.c Modified: python/branches/py3k/Lib/test/test_xml_etree_c.py ============================================================================== --- python/branches/py3k/Lib/test/test_xml_etree_c.py (original) +++ python/branches/py3k/Lib/test/test_xml_etree_c.py Tue Jan 4 03:07:34 2011 @@ -1,6 +1,8 @@ # xml.etree test for cElementTree from test import support +from test.support import precisionbigmemtest, _2G +import unittest cET = support.import_module('xml.etree.cElementTree') @@ -31,12 +33,28 @@ """ +class MiscTests(unittest.TestCase): + # Issue #8651. + @support.precisionbigmemtest(size=support._2G + 100, memuse=1) + def test_length_overflow(self, size): + if size < support._2G + 100: + self.skipTest("not enough free memory, need at least 2 GB") + data = b'x' * size + parser = cET.XMLParser() + try: + self.assertRaises(OverflowError, parser.feed, data) + finally: + data = None + + def test_main(): from test import test_xml_etree, test_xml_etree_c # Run the tests specific to the C implementation support.run_doctest(test_xml_etree_c, verbosity=True) + support.run_unittest(MiscTests) + # Assign the C implementation before running the doctests # Patch the __name__, to prevent confusion with the pure Python test pyET = test_xml_etree.ET Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Tue Jan 4 03:07:34 2011 @@ -8,6 +8,10 @@ Core and Builtins ----------------- +- Issue #8651: PyArg_Parse*() functions raise an OverflowError if the file + doesn't have PY_SSIZE_T_CLEAN define and the size doesn't fit in an int + (length bigger than 2^31-1 bytes). + - Issue #9015, #9611: FileIO.readinto(), FileIO.write() and os.write() clamp the length to 2^31-1 on Windows. Modified: python/branches/py3k/Python/getargs.c ============================================================================== --- python/branches/py3k/Python/getargs.c (original) +++ python/branches/py3k/Python/getargs.c Tue Jan 4 03:07:34 2011 @@ -597,7 +597,17 @@ #define FETCH_SIZE int *q=NULL;Py_ssize_t *q2=NULL;\ if (flags & FLAG_SIZE_T) q2=va_arg(*p_va, Py_ssize_t*); \ else q=va_arg(*p_va, int*); -#define STORE_SIZE(s) if (flags & FLAG_SIZE_T) *q2=s; else *q=s; +#define STORE_SIZE(s) \ + if (flags & FLAG_SIZE_T) \ + *q2=s; \ + else { \ + if (INT_MAX < s) { \ + PyErr_SetString(PyExc_OverflowError, \ + "size does not fit in an int"); \ + return converterr("", arg, msgbuf, bufsize); \ + } \ + *q=s; \ + } #define BUFFER_LEN ((flags & FLAG_SIZE_T) ? *q2:*q) const char *format = *p_format; From python-checkins at python.org Tue Jan 4 03:07:36 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 03:07:36 +0100 (CET) Subject: [Python-checkins] r87729 - in python/branches/py3k: Lib/test/test_zlib.py Misc/NEWS Modules/zlibmodule.c Message-ID: <20110104020736.BDBD4EEA44@mail.python.org> Author: victor.stinner Date: Tue Jan 4 03:07:36 2011 New Revision: 87729 Log: Issue #8650: zlib.compress() and zlib.decompress() raise an OverflowError if the input buffer length doesn't fit into an unsigned int (length bigger than 2^32-1 bytes). Modified: python/branches/py3k/Lib/test/test_zlib.py python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/zlibmodule.c Modified: python/branches/py3k/Lib/test/test_zlib.py ============================================================================== --- python/branches/py3k/Lib/test/test_zlib.py (original) +++ python/branches/py3k/Lib/test/test_zlib.py Tue Jan 4 03:07:36 2011 @@ -2,7 +2,7 @@ from test import support import binascii import random -from test.support import precisionbigmemtest, _1G +from test.support import precisionbigmemtest, _1G, _4G zlib = support.import_module('zlib') @@ -158,6 +158,16 @@ def test_big_decompress_buffer(self, size): self.check_big_decompress_buffer(size, zlib.decompress) + @precisionbigmemtest(size=_4G + 100, memuse=1) + def test_length_overflow(self, size): + if size < _4G + 100: + self.skipTest("not enough free memory, need at least 4 GB") + data = b'x' * size + try: + self.assertRaises(OverflowError, zlib.compress, data, 1) + finally: + data = None + class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase): # Test compression object Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Tue Jan 4 03:07:36 2011 @@ -30,6 +30,10 @@ Library ------- +- Issue #8650: zlib.compress() and zlib.decompress() raise an OverflowError if + the input buffer length doesn't fit into an unsigned int (length bigger than + 2^32-1 bytes). + - Issue #6643: Reinitialize locks held within the threading module after fork to avoid a potential rare deadlock or crash on some platforms. Modified: python/branches/py3k/Modules/zlibmodule.c ============================================================================== --- python/branches/py3k/Modules/zlibmodule.c (original) +++ python/branches/py3k/Modules/zlibmodule.c Tue Jan 4 03:07:36 2011 @@ -117,14 +117,21 @@ PyObject *ReturnVal = NULL; Py_buffer pinput; Byte *input, *output; - int length, level=Z_DEFAULT_COMPRESSION, err; + unsigned int length; + int level=Z_DEFAULT_COMPRESSION, err; z_stream zst; /* require Python string object, optional 'level' arg */ if (!PyArg_ParseTuple(args, "y*|i:compress", &pinput, &level)) return NULL; - input = pinput.buf; + + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "size does not fit in an unsigned int"); + return NULL; + } length = pinput.len; + input = pinput.buf; zst.avail_out = length + length/1000 + 12 + 1; @@ -199,7 +206,8 @@ PyObject *result_str; Py_buffer pinput; Byte *input; - int length, err; + unsigned int length; + int err; int wsize=DEF_WBITS; Py_ssize_t r_strlen=DEFAULTALLOC; z_stream zst; @@ -207,8 +215,14 @@ if (!PyArg_ParseTuple(args, "y*|in:decompress", &pinput, &wsize, &r_strlen)) return NULL; - input = pinput.buf; + + if (pinput.len > UINT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "size does not fit in an unsigned int"); + return NULL; + } length = pinput.len; + input = pinput.buf; if (r_strlen <= 0) r_strlen = 1; From solipsis at pitrou.net Tue Jan 4 05:06:43 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 04 Jan 2011 05:06:43 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r87729): sum=0 Message-ID: py3k results for svn r87729 (hg cset 652eaf09f6ab) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/refloguiVzbJ', '-x'] From python-checkins at python.org Tue Jan 4 12:00:45 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 12:00:45 +0100 (CET) Subject: [Python-checkins] r87730 - in python/branches/py3k: Lib/socket.py Lib/test/test_socket.py Misc/NEWS Message-ID: <20110104110045.990DEEE98F@mail.python.org> Author: victor.stinner Date: Tue Jan 4 12:00:45 2011 New Revision: 87730 Log: Issue #10819: SocketIO.name property returns -1 when its closed, instead of raising a ValueError, to fix repr(). Modified: python/branches/py3k/Lib/socket.py python/branches/py3k/Lib/test/test_socket.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/socket.py ============================================================================== --- python/branches/py3k/Lib/socket.py (original) +++ python/branches/py3k/Lib/socket.py Tue Jan 4 12:00:45 2011 @@ -307,7 +307,10 @@ @property def name(self): - return self.fileno() + if not self.closed: + return self.fileno() + else: + return -1 @property def mode(self): Modified: python/branches/py3k/Lib/test/test_socket.py ============================================================================== --- python/branches/py3k/Lib/test/test_socket.py (original) +++ python/branches/py3k/Lib/test/test_socket.py Tue Jan 4 12:00:45 2011 @@ -738,6 +738,12 @@ f = None support.gc_collect() + def test_name_closed_socketio(self): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + fp = sock.makefile("rb") + fp.close() + self.assertEqual(repr(fp), "<_io.BufferedReader name=-1>") + @unittest.skipUnless(thread, 'Threading required for this test.') class BasicTCPTest(SocketConnectedTest): Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Tue Jan 4 12:00:45 2011 @@ -30,6 +30,9 @@ Library ------- +- Issue #10819: SocketIO.name property returns -1 when its closed, instead of + raising a ValueError, to fix repr(). + - Issue #8650: zlib.compress() and zlib.decompress() raise an OverflowError if the input buffer length doesn't fit into an unsigned int (length bigger than 2^32-1 bytes). From python-checkins at python.org Tue Jan 4 12:16:48 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 12:16:48 +0100 (CET) Subject: [Python-checkins] r87731 - python/branches/py3k/Python/getargs.c Message-ID: <20110104111648.29BF7EE982@mail.python.org> Author: victor.stinner Date: Tue Jan 4 12:16:48 2011 New Revision: 87731 Log: Issue #8992: Simplify addcleanup() API Don't need to handle unknown destructor anymore. Modified: python/branches/py3k/Python/getargs.c Modified: python/branches/py3k/Python/getargs.c ============================================================================== --- python/branches/py3k/Python/getargs.c (original) +++ python/branches/py3k/Python/getargs.c Tue Jan 4 12:16:48 2011 @@ -146,10 +146,19 @@ } static int -addcleanup(void *ptr, PyObject **freelist, PyCapsule_Destructor destr) +addcleanup(void *ptr, PyObject **freelist, int is_buffer) { PyObject *cobj; const char *name; + PyCapsule_Destructor destr; + + if (is_buffer) { + destr = cleanup_buffer; + name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER; + } else { + destr = cleanup_ptr; + name = GETARGS_CAPSULE_NAME_CLEANUP_PTR; + } if (!*freelist) { *freelist = PyList_New(0); @@ -159,13 +168,6 @@ } } - if (destr == cleanup_ptr) { - name = GETARGS_CAPSULE_NAME_CLEANUP_PTR; - } else if (destr == cleanup_buffer) { - name = GETARGS_CAPSULE_NAME_CLEANUP_BUFFER; - } else { - return -1; - } cobj = PyCapsule_New(ptr, name, destr); if (!cobj) { destr(ptr); @@ -855,7 +857,7 @@ if (getbuffer(arg, (Py_buffer*)p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); format++; - if (addcleanup(p, freelist, cleanup_buffer)) { + if (addcleanup(p, freelist, 1)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -901,7 +903,7 @@ if (getbuffer(arg, p, &buf) < 0) return converterr(buf, arg, msgbuf, bufsize); } - if (addcleanup(p, freelist, cleanup_buffer)) { + if (addcleanup(p, freelist, 1)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); @@ -1109,7 +1111,7 @@ "(memory error)", arg, msgbuf, bufsize); } - if (addcleanup(*buffer, freelist, cleanup_ptr)) { + if (addcleanup(*buffer, freelist, 0)) { Py_DECREF(s); return converterr( "(cleanup problem)", @@ -1152,7 +1154,7 @@ return converterr("(memory error)", arg, msgbuf, bufsize); } - if (addcleanup(*buffer, freelist, cleanup_ptr)) { + if (addcleanup(*buffer, freelist, 0)) { Py_DECREF(s); return converterr("(cleanup problem)", arg, msgbuf, bufsize); @@ -1244,7 +1246,7 @@ PyBuffer_Release((Py_buffer*)p); return converterr("contiguous buffer", arg, msgbuf, bufsize); } - if (addcleanup(p, freelist, cleanup_buffer)) { + if (addcleanup(p, freelist, 1)) { return converterr( "(cleanup problem)", arg, msgbuf, bufsize); From python-checkins at python.org Tue Jan 4 12:16:49 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 12:16:49 +0100 (CET) Subject: [Python-checkins] r87732 - python/branches/py3k/Python/getargs.c Message-ID: <20110104111649.959CDEE993@mail.python.org> Author: victor.stinner Date: Tue Jan 4 12:16:49 2011 New Revision: 87732 Log: Issue #8992: convertsimple() doesn't need to fill msgbuf if an error occurred Return msgbug on error is enough. Modified: python/branches/py3k/Python/getargs.c Modified: python/branches/py3k/Python/getargs.c ============================================================================== --- python/branches/py3k/Python/getargs.c (original) +++ python/branches/py3k/Python/getargs.c Tue Jan 4 12:16:49 2011 @@ -611,6 +611,7 @@ *q=s; \ } #define BUFFER_LEN ((flags & FLAG_SIZE_T) ? *q2:*q) +#define RETURN_ERR_OCCURRED return msgbuf const char *format = *p_format; char c = *format++; @@ -622,19 +623,19 @@ char *p = va_arg(*p_va, char *); long ival; if (float_argument_error(arg)) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else if (ival < 0) { PyErr_SetString(PyExc_OverflowError, - "unsigned byte integer is less than minimum"); - return converterr("integer", arg, msgbuf, bufsize); + "unsigned byte integer is less than minimum"); + RETURN_ERR_OCCURRED; } else if (ival > UCHAR_MAX) { PyErr_SetString(PyExc_OverflowError, - "unsigned byte integer is greater than maximum"); - return converterr("integer", arg, msgbuf, bufsize); + "unsigned byte integer is greater than maximum"); + RETURN_ERR_OCCURRED; } else *p = (unsigned char) ival; @@ -646,10 +647,10 @@ char *p = va_arg(*p_va, char *); long ival; if (float_argument_error(arg)) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsUnsignedLongMask(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = (unsigned char) ival; break; @@ -659,19 +660,19 @@ short *p = va_arg(*p_va, short *); long ival; if (float_argument_error(arg)) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else if (ival < SHRT_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is less than minimum"); - return converterr("integer", arg, msgbuf, bufsize); + "signed short integer is less than minimum"); + RETURN_ERR_OCCURRED; } else if (ival > SHRT_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed short integer is greater than maximum"); - return converterr("integer", arg, msgbuf, bufsize); + "signed short integer is greater than maximum"); + RETURN_ERR_OCCURRED; } else *p = (short) ival; @@ -683,10 +684,10 @@ unsigned short *p = va_arg(*p_va, unsigned short *); long ival; if (float_argument_error(arg)) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsUnsignedLongMask(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = (unsigned short) ival; break; @@ -696,19 +697,19 @@ int *p = va_arg(*p_va, int *); long ival; if (float_argument_error(arg)) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else if (ival > INT_MAX) { PyErr_SetString(PyExc_OverflowError, - "signed integer is greater than maximum"); - return converterr("integer", arg, msgbuf, bufsize); + "signed integer is greater than maximum"); + RETURN_ERR_OCCURRED; } else if (ival < INT_MIN) { PyErr_SetString(PyExc_OverflowError, - "signed integer is less than minimum"); - return converterr("integer", arg, msgbuf, bufsize); + "signed integer is less than minimum"); + RETURN_ERR_OCCURRED; } else *p = ival; @@ -720,10 +721,10 @@ unsigned int *p = va_arg(*p_va, unsigned int *); unsigned int ival; if (float_argument_error(arg)) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = (unsigned int)PyLong_AsUnsignedLongMask(arg); if (ival == (unsigned int)-1 && PyErr_Occurred()) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = ival; break; @@ -735,14 +736,14 @@ Py_ssize_t *p = va_arg(*p_va, Py_ssize_t *); Py_ssize_t ival = -1; if (float_argument_error(arg)) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; iobj = PyNumber_Index(arg); if (iobj != NULL) { ival = PyLong_AsSsize_t(iobj); Py_DECREF(iobj); } if (ival == -1 && PyErr_Occurred()) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; *p = ival; break; } @@ -750,10 +751,10 @@ long *p = va_arg(*p_va, long *); long ival; if (float_argument_error(arg)) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsLong(arg); if (ival == -1 && PyErr_Occurred()) - return converterr("integer", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = ival; break; @@ -775,10 +776,10 @@ PY_LONG_LONG *p = va_arg( *p_va, PY_LONG_LONG * ); PY_LONG_LONG ival; if (float_argument_error(arg)) - return converterr("long", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; ival = PyLong_AsLongLong(arg); if (ival == (PY_LONG_LONG)-1 && PyErr_Occurred()) - return converterr("long", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = ival; break; @@ -800,7 +801,7 @@ float *p = va_arg(*p_va, float *); double dval = PyFloat_AsDouble(arg); if (PyErr_Occurred()) - return converterr("float", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = (float) dval; break; @@ -810,7 +811,7 @@ double *p = va_arg(*p_va, double *); double dval = PyFloat_AsDouble(arg); if (PyErr_Occurred()) - return converterr("float", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = dval; break; @@ -821,7 +822,7 @@ Py_complex cval; cval = PyComplex_AsCComplex(arg); if (PyErr_Occurred()) - return converterr("complex", arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; else *p = cval; break; @@ -1107,9 +1108,7 @@ if (*buffer == NULL) { Py_DECREF(s); PyErr_NoMemory(); - return converterr( - "(memory error)", - arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; } if (addcleanup(*buffer, freelist, 0)) { Py_DECREF(s); @@ -1151,8 +1150,7 @@ if (*buffer == NULL) { Py_DECREF(s); PyErr_NoMemory(); - return converterr("(memory error)", - arg, msgbuf, bufsize); + RETURN_ERR_OCCURRED; } if (addcleanup(*buffer, freelist, 0)) { Py_DECREF(s); @@ -1261,6 +1259,11 @@ *p_format = format; return NULL; + +#undef FETCH_SIZE +#undef STORE_SIZE +#undef BUFFER_LEN +#undef RETURN_ERR_OCCURRED } static Py_ssize_t From nnorwitz at gmail.com Tue Jan 4 12:56:02 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Tue, 4 Jan 2011 06:56:02 -0500 Subject: [Python-checkins] Python Regression Test Failures refleak (1) Message-ID: <20110104115602.GA25469@kbk-i386-bb.dyndns.org> More important issues: ---------------------- test_bz2 leaked [0, 0, 69] references, sum=69 Less important issues: ---------------------- From python-checkins at python.org Tue Jan 4 13:59:16 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 13:59:16 +0100 (CET) Subject: [Python-checkins] r87733 - in python/branches/py3k: Modules/_ctypes/_ctypes.c Modules/_testcapimodule.c Modules/audioop.c Modules/md5module.c Modules/pyexpat.c Modules/selectmodule.c Modules/sha1module.c Modules/sha256module.c Modules/sha512module.c Modules/unicodedata.c Objects/codeobject.c Objects/listobject.c Objects/typeobject.c Python/pythonrun.c Message-ID: <20110104125916.1FD43EE98C@mail.python.org> Author: victor.stinner Date: Tue Jan 4 13:59:15 2011 New Revision: 87733 Log: Issue #9566: use Py_ssize_t instead of int Modified: python/branches/py3k/Modules/_ctypes/_ctypes.c python/branches/py3k/Modules/_testcapimodule.c python/branches/py3k/Modules/audioop.c python/branches/py3k/Modules/md5module.c python/branches/py3k/Modules/pyexpat.c python/branches/py3k/Modules/selectmodule.c python/branches/py3k/Modules/sha1module.c python/branches/py3k/Modules/sha256module.c python/branches/py3k/Modules/sha512module.c python/branches/py3k/Modules/unicodedata.c python/branches/py3k/Objects/codeobject.c python/branches/py3k/Objects/listobject.c python/branches/py3k/Objects/typeobject.c python/branches/py3k/Python/pythonrun.c Modified: python/branches/py3k/Modules/_ctypes/_ctypes.c ============================================================================== --- python/branches/py3k/Modules/_ctypes/_ctypes.c (original) +++ python/branches/py3k/Modules/_ctypes/_ctypes.c Tue Jan 4 13:59:15 2011 @@ -3925,14 +3925,14 @@ Returns -1 on error, or the index of next argument on success. */ -static int +static Py_ssize_t _init_pos_args(PyObject *self, PyTypeObject *type, PyObject *args, PyObject *kwds, - int index) + Py_ssize_t index) { StgDictObject *dict; PyObject *fields; - int i; + Py_ssize_t i; if (PyType_stgdict((PyObject *)type->tp_base)) { index = _init_pos_args(self, type->tp_base, Modified: python/branches/py3k/Modules/_testcapimodule.c ============================================================================== --- python/branches/py3k/Modules/_testcapimodule.c (original) +++ python/branches/py3k/Modules/_testcapimodule.c Tue Jan 4 13:59:15 2011 @@ -2188,7 +2188,7 @@ /* argument converter not called? */ return NULL; /* Should be 1 */ - res = PyLong_FromLong(Py_REFCNT(str2)); + res = PyLong_FromSsize_t(Py_REFCNT(str2)); Py_DECREF(str2); PyErr_Clear(); return res; Modified: python/branches/py3k/Modules/audioop.c ============================================================================== --- python/branches/py3k/Modules/audioop.c (original) +++ python/branches/py3k/Modules/audioop.c Tue Jan 4 13:59:15 2011 @@ -309,7 +309,7 @@ } static int -audioop_check_parameters(int len, int size) +audioop_check_parameters(Py_ssize_t len, int size) { if (!audioop_check_size(size)) return 0; Modified: python/branches/py3k/Modules/md5module.c ============================================================================== --- python/branches/py3k/Modules/md5module.c (original) +++ python/branches/py3k/Modules/md5module.c Tue Jan 4 13:59:15 2011 @@ -228,9 +228,9 @@ @param inlen The length of the data (octets) */ void md5_process(struct md5_state *md5, - const unsigned char *in, unsigned long inlen) + const unsigned char *in, Py_ssize_t inlen) { - unsigned long n; + Py_ssize_t n; assert(md5 != NULL); assert(in != NULL); Modified: python/branches/py3k/Modules/pyexpat.c ============================================================================== --- python/branches/py3k/Modules/pyexpat.c (original) +++ python/branches/py3k/Modules/pyexpat.c Tue Jan 4 13:59:15 2011 @@ -800,7 +800,7 @@ PyObject *arg = NULL; PyObject *bytes = NULL; PyObject *str = NULL; - int len = -1; + Py_ssize_t len = -1; char *ptr; if ((bytes = PyLong_FromLong(buf_size)) == NULL) @@ -831,7 +831,7 @@ if (len > buf_size) { PyErr_Format(PyExc_ValueError, "read() returned too much data: " - "%i bytes requested, %i returned", + "%i bytes requested, %zi returned", buf_size, len); goto finally; } @@ -839,7 +839,7 @@ finally: Py_XDECREF(arg); Py_XDECREF(str); - return len; + return (int)len; } PyDoc_STRVAR(xmlparse_ParseFile__doc__, @@ -1807,7 +1807,7 @@ Py_XDECREF(rev_codes_dict); return NULL; } - + #define MYCONST(name) \ if (PyModule_AddStringConstant(errors_module, #name, \ (char *)XML_ErrorString(name)) < 0) \ @@ -1873,7 +1873,7 @@ return NULL; if (PyModule_AddObject(errors_module, "messages", rev_codes_dict) < 0) return NULL; - + #undef MYCONST #define MYCONST(c) PyModule_AddIntConstant(m, #c, c) Modified: python/branches/py3k/Modules/selectmodule.c ============================================================================== --- python/branches/py3k/Modules/selectmodule.c (original) +++ python/branches/py3k/Modules/selectmodule.c Tue Jan 4 13:59:15 2011 @@ -81,10 +81,9 @@ static int seq2set(PyObject *seq, fd_set *set, pylist fd2obj[FD_SETSIZE + 1]) { - int i; int max = -1; int index = 0; - int len = -1; + Py_ssize_t i, len = -1; PyObject* fast_seq = NULL; PyObject* o = NULL; Modified: python/branches/py3k/Modules/sha1module.c ============================================================================== --- python/branches/py3k/Modules/sha1module.c (original) +++ python/branches/py3k/Modules/sha1module.c Tue Jan 4 13:59:15 2011 @@ -203,9 +203,9 @@ @param inlen The length of the data (octets) */ void sha1_process(struct sha1_state *sha1, - const unsigned char *in, unsigned long inlen) + const unsigned char *in, Py_ssize_t inlen) { - unsigned long n; + Py_ssize_t n; assert(sha1 != NULL); assert(in != NULL); Modified: python/branches/py3k/Modules/sha256module.c ============================================================================== --- python/branches/py3k/Modules/sha256module.c (original) +++ python/branches/py3k/Modules/sha256module.c Tue Jan 4 13:59:15 2011 @@ -265,9 +265,9 @@ /* update the SHA digest */ static void -sha_update(SHAobject *sha_info, SHA_BYTE *buffer, int count) +sha_update(SHAobject *sha_info, SHA_BYTE *buffer, Py_ssize_t count) { - int i; + Py_ssize_t i; SHA_INT32 clo; clo = sha_info->count_lo + ((SHA_INT32) count << 3); Modified: python/branches/py3k/Modules/sha512module.c ============================================================================== --- python/branches/py3k/Modules/sha512module.c (original) +++ python/branches/py3k/Modules/sha512module.c Tue Jan 4 13:59:15 2011 @@ -291,9 +291,9 @@ /* update the SHA digest */ static void -sha512_update(SHAobject *sha_info, SHA_BYTE *buffer, int count) +sha512_update(SHAobject *sha_info, SHA_BYTE *buffer, Py_ssize_t count) { - int i; + Py_ssize_t i; SHA_INT32 clo; clo = sha_info->count_lo + ((SHA_INT32) count << 3); Modified: python/branches/py3k/Modules/unicodedata.c ============================================================================== --- python/branches/py3k/Modules/unicodedata.c (original) +++ python/branches/py3k/Modules/unicodedata.c Tue Jan 4 13:59:15 2011 @@ -403,7 +403,8 @@ { PyUnicodeObject *v; char decomp[256]; - int code, index, count, i; + int code, index, count; + size_t i; unsigned int prefix_index; Py_UCS4 c; @@ -450,15 +451,12 @@ while (count-- > 0) { if (i) decomp[i++] = ' '; - assert((size_t)i < sizeof(decomp)); + assert(i < sizeof(decomp)); PyOS_snprintf(decomp + i, sizeof(decomp) - i, "%04X", decomp_data[++index]); i += strlen(decomp + i); } - - decomp[i] = '\0'; - - return PyUnicode_FromString(decomp); + return PyUnicode_FromStringAndSize(decomp, i); } static void Modified: python/branches/py3k/Objects/codeobject.c ============================================================================== --- python/branches/py3k/Objects/codeobject.c (original) +++ python/branches/py3k/Objects/codeobject.c Tue Jan 4 13:59:15 2011 @@ -492,7 +492,7 @@ int PyCode_Addr2Line(PyCodeObject *co, int addrq) { - int size = PyBytes_Size(co->co_lnotab) / 2; + Py_ssize_t size = PyBytes_Size(co->co_lnotab) / 2; unsigned char *p = (unsigned char*)PyBytes_AsString(co->co_lnotab); int line = co->co_firstlineno; int addr = 0; @@ -510,7 +510,8 @@ int _PyCode_CheckLineNumber(PyCodeObject* co, int lasti, PyAddrPair *bounds) { - int size, addr, line; + Py_ssize_t size; + int addr, line; unsigned char* p; p = (unsigned char*)PyBytes_AS_STRING(co->co_lnotab); Modified: python/branches/py3k/Objects/listobject.c ============================================================================== --- python/branches/py3k/Objects/listobject.c (original) +++ python/branches/py3k/Objects/listobject.c Tue Jan 4 13:59:15 2011 @@ -1381,7 +1381,7 @@ /* Conceptually a MergeState's constructor. */ static void -merge_init(MergeState *ms, int list_size, int has_keyfunc) +merge_init(MergeState *ms, Py_ssize_t list_size, int has_keyfunc) { assert(ms != NULL); if (has_keyfunc) { Modified: python/branches/py3k/Objects/typeobject.c ============================================================================== --- python/branches/py3k/Objects/typeobject.c (original) +++ python/branches/py3k/Objects/typeobject.c Tue Jan 4 13:59:15 2011 @@ -2325,7 +2325,7 @@ res->ht_type.tp_basicsize = spec->basicsize; res->ht_type.tp_itemsize = spec->itemsize; res->ht_type.tp_flags = spec->flags | Py_TPFLAGS_HEAPTYPE; - + for (slot = spec->slots; slot->slot; slot++) { if (slot->slot >= sizeof(slotoffsets)/sizeof(slotoffsets[0])) { PyErr_SetString(PyExc_RuntimeError, "invalid slot offset"); @@ -2335,7 +2335,7 @@ } return (PyObject*)res; - + fail: Py_DECREF(res); return NULL; @@ -6202,7 +6202,7 @@ and first local variable on the stack. */ PyFrameObject *f = PyThreadState_GET()->frame; PyCodeObject *co = f->f_code; - int i, n; + Py_ssize_t i, n; if (co == NULL) { PyErr_SetString(PyExc_SystemError, "super(): no code object"); Modified: python/branches/py3k/Python/pythonrun.c ============================================================================== --- python/branches/py3k/Python/pythonrun.c (original) +++ python/branches/py3k/Python/pythonrun.c Tue Jan 4 13:59:15 2011 @@ -1202,7 +1202,8 @@ { PyObject *m, *d, *v; const char *ext; - int set_file_name = 0, ret, len; + int set_file_name = 0, ret; + size_t len; m = PyImport_AddModule("__main__"); if (m == NULL) From python-checkins at python.org Tue Jan 4 14:15:39 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 14:15:39 +0100 (CET) Subject: [Python-checkins] r87734 - in python/branches/py3k: Misc/NEWS Objects/fileobject.c Message-ID: <20110104131539.72678EE986@mail.python.org> Author: victor.stinner Date: Tue Jan 4 14:15:39 2011 New Revision: 87734 Log: Issue #9015, #9611: stdprinter.write() clamps the length to 2^31-1 on Windows Modified: python/branches/py3k/Misc/NEWS python/branches/py3k/Objects/fileobject.c Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Tue Jan 4 14:15:39 2011 @@ -12,8 +12,8 @@ doesn't have PY_SSIZE_T_CLEAN define and the size doesn't fit in an int (length bigger than 2^31-1 bytes). -- Issue #9015, #9611: FileIO.readinto(), FileIO.write() and os.write() clamp - the length to 2^31-1 on Windows. +- Issue #9015, #9611: FileIO.readinto(), FileIO.write(), os.write() and + stdprinter.write() clamp the length to 2^31-1 on Windows. - Issue #8278: On Windows and with a NTFS filesystem, os.stat() and os.utime() can now handle dates after 2038. Modified: python/branches/py3k/Objects/fileobject.c ============================================================================== --- python/branches/py3k/Objects/fileobject.c (original) +++ python/branches/py3k/Objects/fileobject.c Tue Jan 4 14:15:39 2011 @@ -344,7 +344,7 @@ } static int -fileio_init(PyObject *self, PyObject *args, PyObject *kwds) +stdprinter_init(PyObject *self, PyObject *args, PyObject *kwds) { PyErr_SetString(PyExc_TypeError, "cannot create 'stderrprinter' instances"); @@ -390,7 +390,13 @@ Py_BEGIN_ALLOW_THREADS errno = 0; +#if defined(MS_WIN64) || defined(MS_WINDOWS) + if (n > INT_MAX) + n = INT_MAX; + n = write(self->fd, c, (int)n); +#else n = write(self->fd, c, n); +#endif Py_END_ALLOW_THREADS if (n < 0) { @@ -509,7 +515,7 @@ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ - fileio_init, /* tp_init */ + stdprinter_init, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ stdprinter_new, /* tp_new */ PyObject_Del, /* tp_free */ From python-checkins at python.org Tue Jan 4 14:58:49 2011 From: python-checkins at python.org (vinay.sajip) Date: Tue, 4 Jan 2011 14:58:49 +0100 (CET) Subject: [Python-checkins] r87735 - python/branches/py3k/Doc/howto/logging.rst Message-ID: <20110104135849.46F9BEE983@mail.python.org> Author: vinay.sajip Date: Tue Jan 4 14:58:49 2011 New Revision: 87735 Log: logging HOWTO: fixed markup for numbered handler list. Modified: python/branches/py3k/Doc/howto/logging.rst Modified: python/branches/py3k/Doc/howto/logging.rst ============================================================================== --- python/branches/py3k/Doc/howto/logging.rst (original) +++ python/branches/py3k/Doc/howto/logging.rst Tue Jan 4 14:58:49 2011 @@ -857,50 +857,46 @@ #. :class:`FileHandler` instances send messages to disk files. -.. currentmodule:: logging.handlers - -#. :class:`BaseRotatingHandler` is the base class for handlers that +#. :class:`~handlers.BaseRotatingHandler` is the base class for handlers that rotate log files at a certain point. It is not meant to be instantiated - directly. Instead, use :class:`RotatingFileHandler` or - :class:`TimedRotatingFileHandler`. + directly. Instead, use :class:`~handlers.RotatingFileHandler` or + :class:`~handlers.TimedRotatingFileHandler`. -#. :class:`RotatingFileHandler` instances send messages to disk +#. :class:`~handlers.RotatingFileHandler` instances send messages to disk files, with support for maximum log file sizes and log file rotation. -#. :class:`TimedRotatingFileHandler` instances send messages to +#. :class:`~handlers.TimedRotatingFileHandler` instances send messages to disk files, rotating the log file at certain timed intervals. -#. :class:`SocketHandler` instances send messages to TCP/IP +#. :class:`~handlers.SocketHandler` instances send messages to TCP/IP sockets. -#. :class:`DatagramHandler` instances send messages to UDP +#. :class:`~handlers.DatagramHandler` instances send messages to UDP sockets. -#. :class:`SMTPHandler` instances send messages to a designated +#. :class:`~handlers.SMTPHandler` instances send messages to a designated email address. -#. :class:`SysLogHandler` instances send messages to a Unix +#. :class:`~handlers.SysLogHandler` instances send messages to a Unix syslog daemon, possibly on a remote machine. -#. :class:`NTEventLogHandler` instances send messages to a +#. :class:`~handlers.NTEventLogHandler` instances send messages to a Windows NT/2000/XP event log. -#. :class:`MemoryHandler` instances send messages to a buffer +#. :class:`~handlers.MemoryHandler` instances send messages to a buffer in memory, which is flushed whenever specific criteria are met. -#. :class:`HTTPHandler` instances send messages to an HTTP +#. :class:`~handlers.HTTPHandler` instances send messages to an HTTP server using either ``GET`` or ``POST`` semantics. -#. :class:`WatchedFileHandler` instances watch the file they are +#. :class:`~handlers.WatchedFileHandler` instances watch the file they are logging to. If the file changes, it is closed and reopened using the file name. This handler is only useful on Unix-like systems; Windows does not support the underlying mechanism used. -#. :class:`QueueHandler` instances send messages to a queue, such as +#. :class:`~handlers.QueueHandler` instances send messages to a queue, such as those implemented in the :mod:`queue` or :mod:`multiprocessing` modules. -.. currentmodule:: logging - #. :class:`NullHandler` instances do nothing with error messages. They are used by library developers who want to use logging, but want to avoid the 'No handlers could be found for logger XXX' message which can be displayed if @@ -911,7 +907,7 @@ The :class:`NullHandler` class. .. versionadded:: 3.2 - The :class:`~logging.handlers.QueueHandler` class. + The :class:`~handlers.QueueHandler` class. The :class:`NullHandler`, :class:`StreamHandler` and :class:`FileHandler` classes are defined in the core logging package. The other handlers are From python-checkins at python.org Tue Jan 4 17:34:30 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Tue, 4 Jan 2011 17:34:30 +0100 (CET) Subject: [Python-checkins] r87736 - in python/branches/py3k: Doc/library/time.rst Lib/test/test_time.py Misc/NEWS Modules/timemodule.c Message-ID: <20110104163430.F3243D44A@mail.python.org> Author: alexander.belopolsky Date: Tue Jan 4 17:34:30 2011 New Revision: 87736 Log: Issue #8013: time.asctime and time.ctime no longer call system asctime and ctime functions. The year range for time.asctime is now 1900 through maxint. The range for time.ctime is the same as for time.localtime. The string produced by these functions is longer than 24 characters when year is greater than 9999. Modified: python/branches/py3k/Doc/library/time.rst python/branches/py3k/Lib/test/test_time.py python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Doc/library/time.rst ============================================================================== --- python/branches/py3k/Doc/library/time.rst (original) +++ python/branches/py3k/Doc/library/time.rst Tue Jan 4 17:34:30 2011 @@ -125,7 +125,7 @@ .. function:: asctime([t]) Convert a tuple or :class:`struct_time` representing a time as returned by - :func:`gmtime` or :func:`localtime` to a 24-character string of the following + :func:`gmtime` or :func:`localtime` to a string of the following form: ``'Sun Jun 20 23:21:05 1993'``. If *t* is not provided, the current time as returned by :func:`localtime` is used. Locale information is not used by :func:`asctime`. Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Tue Jan 4 17:34:30 2011 @@ -2,6 +2,7 @@ import time import unittest import locale +import sysconfig class TimeTestCase(unittest.TestCase): @@ -121,34 +122,32 @@ def test_asctime(self): time.asctime(time.gmtime(self.t)) + + # Max year is only limited by the size of C int. + sizeof_int = sysconfig.get_config_vars('SIZEOF_INT')[0] + bigyear = (1 << 8 * sizeof_int - 1) - 1 + asc = time.asctime((bigyear, 6, 1) + (0,)*6) + self.assertEqual(asc[-len(str(bigyear)):], str(bigyear)) + self.assertRaises(OverflowError, time.asctime, (bigyear + 1,) + (0,)*8) self.assertRaises(TypeError, time.asctime, 0) self.assertRaises(TypeError, time.asctime, ()) - # XXX: POSIX-compliant asctime should refuse to convert year > 9999, - # but glibc implementation does not. For now, just check it doesn't - # segfault as it did before, and the result contains no newline. - try: - result = time.asctime((12345, 1, 0, 0, 0, 0, 0, 0, 0)) - except ValueError: - # for POSIX-compliant runtimes - pass - else: - self.assertNotIn('\n', result) def test_asctime_bounding_check(self): self._bounds_checking(time.asctime) def test_ctime(self): - # XXX: POSIX-compliant ctime should refuse to convert year > 9999, - # but glibc implementation does not. For now, just check it doesn't - # segfault as it did before, and the result contains no newline. + t = time.mktime((1973, 9, 16, 1, 3, 52, 0, 0, -1)) + self.assertEqual(time.ctime(t), 'Sun Sep 16 01:03:52 1973') + t = time.mktime((2000, 1, 1, 0, 0, 0, 0, 0, -1)) + self.assertEqual(time.ctime(t), 'Sat Jan 1 00:00:00 2000') try: - result = time.ctime(1e12) + bigval = time.mktime((10000, 1, 10) + (0,)*6) except ValueError: - # for POSIX-compliant runtimes (or 32-bit systems, where time_t - # cannot hold timestamps with a five-digit year) + # If mktime fails, ctime will fail too. This may happen + # on some platforms. pass else: - self.assertNotIn('\n', result) + self.assertEquals(time.ctime(bigval)[-5:], '10000') @unittest.skipIf(not hasattr(time, "tzset"), "time module has no attribute tzset") Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Tue Jan 4 17:34:30 2011 @@ -1422,6 +1422,12 @@ Extension Modules ----------------- +- Issue #8013: time.asctime and time.ctime no longer call system + asctime and ctime functions. The year range for time.asctime is now + 1900 through maxint. The range for time.ctime is the same as for + time.localtime. The string produced by these functions is longer + than 24 characters when year is greater than 9999. + - Issue #6608: time.asctime is now checking struct tm fields its input before passing it to the system asctime. Patch by MunSic Jeong. Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Tue Jan 4 17:34:30 2011 @@ -599,19 +599,51 @@ return strptime_result; } + PyDoc_STRVAR(strptime_doc, "strptime(string, format) -> struct_time\n\ \n\ Parse a string to a time tuple according to a format specification.\n\ See the library reference manual for formatting codes (same as strftime())."); +static PyObject * +_asctime(struct tm *timeptr) +{ + /* Inspired by Open Group reference implementation available at + * http://pubs.opengroup.org/onlinepubs/009695399/functions/asctime.html */ + static char wday_name[7][3] = { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; + static char mon_name[12][3] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + char buf[20]; /* 'Sun Sep 16 01:03:52\0' */ + int n; + + n = snprintf(buf, sizeof(buf), "%.3s %.3s%3d %.2d:%.2d:%.2d", + wday_name[timeptr->tm_wday], + mon_name[timeptr->tm_mon], + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec); + /* XXX: since the fields used by snprintf above are validated in checktm, + * the following condition should never trigger. We keep the check because + * historically fixed size buffer used in asctime was the source of + * crashes. */ + if (n + 1 != sizeof(buf)) { + PyErr_SetString(PyExc_ValueError, "unconvertible time"); + return NULL; + } + + return PyUnicode_FromFormat("%s %d", buf, 1900 + timeptr->tm_year); +} static PyObject * time_asctime(PyObject *self, PyObject *args) { PyObject *tup = NULL; struct tm buf; - char *p, *q; + if (!PyArg_UnpackTuple(args, "asctime", 0, 1, &tup)) return NULL; if (tup == NULL) { @@ -619,17 +651,7 @@ buf = *localtime(&tt); } else if (!gettmarg(tup, &buf) || !checktm(&buf)) return NULL; - p = asctime(&buf); - if (p == NULL) { - PyErr_SetString(PyExc_ValueError, "unconvertible time"); - return NULL; - } - /* Replace a terminating newline by a null byte, normally at position 24. - * It can occur later if the year has more than four digits. */ - for (q = p+24; *q != '\0'; q++) - if (*q == '\n') - *q = '\0'; - return PyUnicode_FromString(p); + return _asctime(&buf); } PyDoc_STRVAR(asctime_doc, @@ -644,7 +666,7 @@ { PyObject *ot = NULL; time_t tt; - char *p, *q; + struct tm *timeptr; if (!PyArg_UnpackTuple(args, "ctime", 0, 1, &ot)) return NULL; @@ -658,17 +680,12 @@ if (tt == (time_t)-1 && PyErr_Occurred()) return NULL; } - p = ctime(&tt); - if (p == NULL) { + timeptr = localtime(&tt); + if (timeptr == NULL) { PyErr_SetString(PyExc_ValueError, "unconvertible time"); - return NULL; + return NULL; } - /* Replace a terminating newline by a null byte, normally at position 24. - * It can occur later if the year has more than four digits. */ - for (q = p+24; *q != '\0'; q++) - if (*q == '\n') - *q = '\0'; - return PyUnicode_FromString(p); + return _asctime(timeptr); } PyDoc_STRVAR(ctime_doc, From python-checkins at python.org Tue Jan 4 18:08:04 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Tue, 4 Jan 2011 18:08:04 +0100 (CET) Subject: [Python-checkins] r87737 - python/branches/py3k/Lib/test/test_time.py Message-ID: <20110104170804.BB433EE9A0@mail.python.org> Author: alexander.belopolsky Date: Tue Jan 4 18:08:04 2011 New Revision: 87737 Log: Issue #8013: Fix time.ctime test failure on 32-bit platforms. Modified: python/branches/py3k/Lib/test/test_time.py Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Tue Jan 4 18:08:04 2011 @@ -142,7 +142,7 @@ self.assertEqual(time.ctime(t), 'Sat Jan 1 00:00:00 2000') try: bigval = time.mktime((10000, 1, 10) + (0,)*6) - except ValueError: + except ValueError, OverflowError: # If mktime fails, ctime will fail too. This may happen # on some platforms. pass From python-checkins at python.org Tue Jan 4 18:15:52 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Tue, 4 Jan 2011 18:15:52 +0100 (CET) Subject: [Python-checkins] r87738 - python/branches/py3k/Modules/timemodule.c Message-ID: <20110104171552.5E61FEE9AB@mail.python.org> Author: alexander.belopolsky Date: Tue Jan 4 18:15:52 2011 New Revision: 87738 Log: Whitespace cleanup Modified: python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Tue Jan 4 18:15:52 2011 @@ -1,4 +1,3 @@ - /* Time module */ #include "Python.h" @@ -683,7 +682,7 @@ timeptr = localtime(&tt); if (timeptr == NULL) { PyErr_SetString(PyExc_ValueError, "unconvertible time"); - return NULL; + return NULL; } return _asctime(timeptr); } From python-checkins at python.org Tue Jan 4 18:27:13 2011 From: python-checkins at python.org (georg.brandl) Date: Tue, 4 Jan 2011 18:27:13 +0100 (CET) Subject: [Python-checkins] r87739 - python/branches/py3k/Lib/test/test_time.py Message-ID: <20110104172713.544A3D55F@mail.python.org> Author: georg.brandl Date: Tue Jan 4 18:27:13 2011 New Revision: 87739 Log: Fix exception catching. Modified: python/branches/py3k/Lib/test/test_time.py Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Tue Jan 4 18:27:13 2011 @@ -142,7 +142,7 @@ self.assertEqual(time.ctime(t), 'Sat Jan 1 00:00:00 2000') try: bigval = time.mktime((10000, 1, 10) + (0,)*6) - except ValueError, OverflowError: + except (ValueError, OverflowError): # If mktime fails, ctime will fail too. This may happen # on some platforms. pass From python-checkins at python.org Tue Jan 4 19:33:38 2011 From: python-checkins at python.org (gregory.p.smith) Date: Tue, 4 Jan 2011 19:33:38 +0100 (CET) Subject: [Python-checkins] r87740 - python/branches/py3k/Lib/threading.py Message-ID: <20110104183338.A5953EE995@mail.python.org> Author: gregory.p.smith Date: Tue Jan 4 19:33:38 2011 New Revision: 87740 Log: Fix the new bug introduced in the r87710 fix for issue 6643. DummyThread deletes its _block attribute, deal with that. This prevents an uncaught exception in a thread during test_thread. This refactors a bit to better match what I did in the r87727 backport to 2.7. Modified: python/branches/py3k/Lib/threading.py Modified: python/branches/py3k/Lib/threading.py ============================================================================== --- python/branches/py3k/Lib/threading.py (original) +++ python/branches/py3k/Lib/threading.py Tue Jan 4 19:33:38 2011 @@ -395,6 +395,10 @@ self._cond = Condition(Lock()) self._flag = False + def _reset_internal_locks(self): + # private! called by Thread._reset_internal_locks by _after_fork() + self._cond.__init__() + def is_set(self): return self._flag @@ -642,6 +646,13 @@ # sys.exc_info since it can be changed between instances self._stderr = _sys.stderr + def _reset_internal_locks(self): + # private! Called by _after_fork() to reset our internal locks as + # they may be in an invalid state leading to a deadlock or crash. + if hasattr(self, '_block'): # DummyThread deletes _block + self._block.__init__() + self._started._reset_internal_locks() + def _set_daemon(self): # Overridden in _MainThread and _DummyThread return current_thread().daemon @@ -984,12 +995,11 @@ def __init__(self): Thread.__init__(self, name=_newname("Dummy-%d")) - # Thread.__block consumes an OS-level locking primitive, which + # Thread._block consumes an OS-level locking primitive, which # can never be used by a _DummyThread. Since a _DummyThread # instance is immortal, that's bad, so release this resource. del self._block - self._started.set() self._set_ident() with _active_limbo_lock: @@ -1066,8 +1076,7 @@ thread._ident = ident # Any condition variables hanging off of the active thread may # be in an invalid state, so we reinitialize them. - thread._block.__init__() - thread._started._cond.__init__() + thread._reset_internal_locks() new_active[ident] = thread else: # All the others are already stopped. From python-checkins at python.org Tue Jan 4 19:39:25 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 19:39:25 +0100 Subject: [Python-checkins] devguide: Add sphinx roles and such as created by sphinx-quickstart. Message-ID: brett.cannon pushed 74c36331fcc4 to devguide: http://hg.python.org/devguide/rev/74c36331fcc4 changeset: 3:74c36331fcc4 user: Brett Cannon date: Tue Jan 04 10:36:19 2011 -0800 summary: Add sphinx roles and such as created by sphinx-quickstart. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -1,5 +1,11 @@ -Python Language / CPython interpreter Developer's Guide -======================================================= +Welcome to Python Developer's Guide's documentation! +==================================================== + +Contents: + +.. toctree:: + :maxdepth: 2 + Contributing ------------ @@ -48,6 +54,14 @@ * `Buildbot builders `_ - .. _PEP 7: http://www.python.org/dev/peps/pep-0007 .. _PEP 8: http://www.python.org/dev/peps/pep-0008 + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 19:39:25 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 19:39:25 +0100 Subject: [Python-checkins] devguide: sphinx-quickstart uses single quotes for everything; not godo when you Message-ID: brett.cannon pushed 8bb09b6f7e1c to devguide: http://hg.python.org/devguide/rev/8bb09b6f7e1c changeset: 5:8bb09b6f7e1c tag: tip user: Brett Cannon date: Tue Jan 04 10:39:10 2011 -0800 summary: sphinx-quickstart uses single quotes for everything; not godo when you use an apostrophe in your project title. files: conf.py diff --git a/conf.py b/conf.py --- a/conf.py +++ b/conf.py @@ -211,6 +211,6 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ - ('index', 'pythondevelopersguide', u'Python Developer's Guide Documentation', + ('index', 'pythondevelopersguide', u"Python Developer's Guide Documentation", [u'Brett Cannon'], 1) ] -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 19:39:25 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 19:39:25 +0100 Subject: [Python-checkins] devguide: Add placeholder links to make sure that the reST markup will compile. Message-ID: brett.cannon pushed 2e69dc621d8d to devguide: http://hg.python.org/devguide/rev/2e69dc621d8d changeset: 2:2e69dc621d8d user: Brett Cannon date: Tue Jan 04 10:25:14 2011 -0800 summary: Add placeholder links to make sure that the reST markup will compile. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -1,47 +1,46 @@ -.. comment:: - This file acts as a TODO list, w/ anything that is specified as a - link which does not point to a specific file as something that needs doing. +Python Language / CPython interpreter Developer's Guide +======================================================= Contributing -============ +------------ This list is in an overall suggested order for people wanting to contribute to the Python programming language and/or the CPython interpreter. People should follow the top-level bullet points in order, while sub-level bullet points can be done in any order. -* `Getting set up`_ +* `Getting set up `_ * Coding style guides * `PEP 7`_ * `PEP 8`_ -* `Using the buildbots`_ -* `Submitting a patch`_ +* `Using the buildbots `_ +* `Submitting a patch `_ * Projects to get familiar with the development process - * `Help increase test coverage`_ - * `Make all unit tests discoverable by unittest`_ - * `Fixing documentation bugs`_ + * `Help increase test coverage `_ + * `Make all unit tests discoverable by unittest `_ + * `Fixing documentation bugs `_ * Projects for once you are comfortable - * `Helping triage issues`_ - * `Fixing issues considered "easy"`_ (and beyond) -* `Gaining 'Developer' privileges for the issue tracker`_ - * `Triaging issues`_ - * `Reviewing patches`_ -* `Gaining commit privileges`_ - * `Committing patches`_ + * `Helping triage issues `_ + * `Fixing issues considered "easy" `_ (and beyond) +* `Gaining 'Developer' privileges for the issue tracker `_ + * `Triaging issues `_ + * `Reviewing patches `_ +* `Gaining commit privileges `_ + * `Committing patches `_ Making changes to Python itself -=============================== +------------------------------- -* `Changing something already in the stdlib`_ +* `Changing something already in the stdlib `_ * Adding to the stdblib - * `Adding to a pre-existing module`_ - * `Adding a new module`_ -* `Changing the language`_ + * `Adding to a pre-existing module `_ + * `Adding a new module `_ +* `Changing the language `_ Resources -========= +--------- * `Issue tracker `_ * `Meta tracker `_ (issue -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 19:39:25 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 19:39:25 +0100 Subject: [Python-checkins] devguide: Add config and build files from sphinx-quickstart. Message-ID: brett.cannon pushed 4253883f1207 to devguide: http://hg.python.org/devguide/rev/4253883f1207 changeset: 4:4253883f1207 user: Brett Cannon date: Tue Jan 04 10:36:33 2011 -0800 summary: Add config and build files from sphinx-quickstart. files: Makefile conf.py make.bat diff --git a/Makefile b/Makefile new file mode 100644 --- /dev/null +++ b/Makefile @@ -0,0 +1,130 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PythonDevelopersGuide.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PythonDevelopersGuide.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/PythonDevelopersGuide" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/PythonDevelopersGuide" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + make -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." diff --git a/conf.py b/conf.py new file mode 100644 --- /dev/null +++ b/conf.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +# +# Python Developer's Guide documentation build configuration file, created by +# sphinx-quickstart on Tue Jan 4 10:34:03 2011. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Python Developer\'s Guide' +copyright = u'2011, Brett Cannon' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0a0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'PythonDevelopersGuidedoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'PythonDevelopersGuide.tex', u'Python Developer\'s Guide Documentation', + u'Brett Cannon', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'pythondevelopersguide', u'Python Developer's Guide Documentation', + [u'Brett Cannon'], 1) +] diff --git a/make.bat b/make.bat new file mode 100644 --- /dev/null +++ b/make.bat @@ -0,0 +1,170 @@ + at ECHO OFF + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set BUILDDIR=_build +set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . +if NOT "%PAPER%" == "" ( + set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% +) + +if "%1" == "" goto help + +if "%1" == "help" ( + :help + echo.Please use `make ^` where ^ is one of + echo. html to make standalone HTML files + echo. dirhtml to make HTML files named index.html in directories + echo. singlehtml to make a single large HTML file + echo. pickle to make pickle files + echo. json to make JSON files + echo. htmlhelp to make HTML files and a HTML help project + echo. qthelp to make HTML files and a qthelp project + echo. devhelp to make HTML files and a Devhelp project + echo. epub to make an epub + echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. text to make text files + echo. man to make manual pages + echo. changes to make an overview over all changed/added/deprecated items + echo. linkcheck to check all external links for integrity + echo. doctest to run all doctests embedded in the documentation if enabled + goto end +) + +if "%1" == "clean" ( + for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i + del /q /s %BUILDDIR%\* + goto end +) + +if "%1" == "html" ( + %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/html. + goto end +) + +if "%1" == "dirhtml" ( + %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. + goto end +) + +if "%1" == "singlehtml" ( + %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. + goto end +) + +if "%1" == "pickle" ( + %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the pickle files. + goto end +) + +if "%1" == "json" ( + %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can process the JSON files. + goto end +) + +if "%1" == "htmlhelp" ( + %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run HTML Help Workshop with the ^ +.hhp project file in %BUILDDIR%/htmlhelp. + goto end +) + +if "%1" == "qthelp" ( + %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; now you can run "qcollectiongenerator" with the ^ +.qhcp project file in %BUILDDIR%/qthelp, like this: + echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PythonDevelopersGuide.qhcp + echo.To view the help file: + echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PythonDevelopersGuide.ghc + goto end +) + +if "%1" == "devhelp" ( + %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. + goto end +) + +if "%1" == "epub" ( + %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The epub file is in %BUILDDIR%/epub. + goto end +) + +if "%1" == "latex" ( + %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex + if errorlevel 1 exit /b 1 + echo. + echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. + goto end +) + +if "%1" == "text" ( + %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The text files are in %BUILDDIR%/text. + goto end +) + +if "%1" == "man" ( + %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man + if errorlevel 1 exit /b 1 + echo. + echo.Build finished. The manual pages are in %BUILDDIR%/man. + goto end +) + +if "%1" == "changes" ( + %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes + if errorlevel 1 exit /b 1 + echo. + echo.The overview file is in %BUILDDIR%/changes. + goto end +) + +if "%1" == "linkcheck" ( + %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck + if errorlevel 1 exit /b 1 + echo. + echo.Link check complete; look for any errors in the above output ^ +or in %BUILDDIR%/linkcheck/output.txt. + goto end +) + +if "%1" == "doctest" ( + %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest + if errorlevel 1 exit /b 1 + echo. + echo.Testing of doctests in the sources finished, look at the ^ +results in %BUILDDIR%/doctest/output.txt. + goto end +) + +:end -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 19:42:29 2011 From: python-checkins at python.org (gregory.p.smith) Date: Tue, 4 Jan 2011 19:42:29 +0100 (CET) Subject: [Python-checkins] r87741 - in python/branches/release31-maint: Lib/threading.py Message-ID: <20110104184229.E634FEE9C7@mail.python.org> Author: gregory.p.smith Date: Tue Jan 4 19:42:29 2011 New Revision: 87741 Log: Merged revisions 87740 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87740 | gregory.p.smith | 2011-01-04 10:33:38 -0800 (Tue, 04 Jan 2011) | 6 lines Fix the new bug introduced in the r87710 fix for issue 6643. DummyThread deletes its _block attribute, deal with that. This prevents an uncaught exception in a thread during test_thread. This refactors a bit to better match what I did in the r87727 backport to 2.7. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/threading.py Modified: python/branches/release31-maint/Lib/threading.py ============================================================================== --- python/branches/release31-maint/Lib/threading.py (original) +++ python/branches/release31-maint/Lib/threading.py Tue Jan 4 19:42:29 2011 @@ -358,6 +358,10 @@ self._cond = Condition(Lock()) self._flag = False + def _reset_internal_locks(self): + # private! called by Thread._reset_internal_locks by _after_fork() + self._cond.__init__() + def is_set(self): return self._flag @@ -434,6 +438,13 @@ # sys.exc_info since it can be changed between instances self._stderr = _sys.stderr + def _reset_internal_locks(self): + # private! Called by _after_fork() to reset our internal locks as + # they may be in an invalid state leading to a deadlock or crash. + if hasattr(self, '_block'): # DummyThread deletes _block + self._block.__init__() + self._started._reset_internal_locks() + def _set_daemon(self): # Overridden in _MainThread and _DummyThread return current_thread().daemon @@ -776,12 +787,11 @@ def __init__(self): Thread.__init__(self, name=_newname("Dummy-%d")) - # Thread.__block consumes an OS-level locking primitive, which + # Thread._block consumes an OS-level locking primitive, which # can never be used by a _DummyThread. Since a _DummyThread # instance is immortal, that's bad, so release this resource. del self._block - self._started.set() self._set_ident() with _active_limbo_lock: @@ -858,8 +868,7 @@ thread._ident = ident # Any condition variables hanging off of the active thread may # be in an invalid state, so we reinitialize them. - thread._block.__init__() - thread._started._cond.__init__() + thread._reset_internal_locks() new_active[ident] = thread else: # All the others are already stopped. From python-checkins at python.org Tue Jan 4 19:43:54 2011 From: python-checkins at python.org (gregory.p.smith) Date: Tue, 4 Jan 2011 19:43:54 +0100 (CET) Subject: [Python-checkins] r87742 - python/branches/release27-maint/Lib/threading.py Message-ID: <20110104184354.55933EE98B@mail.python.org> Author: gregory.p.smith Date: Tue Jan 4 19:43:54 2011 New Revision: 87742 Log: backport fix from r87741 related to the issue6643 fix in r87727. Modified: python/branches/release27-maint/Lib/threading.py Modified: python/branches/release27-maint/Lib/threading.py ============================================================================== --- python/branches/release27-maint/Lib/threading.py (original) +++ python/branches/release27-maint/Lib/threading.py Tue Jan 4 19:43:54 2011 @@ -456,7 +456,8 @@ def _reset_internal_locks(self): # private! Called by _after_fork() to reset our internal locks as # they may be in an invalid state leading to a deadlock or crash. - self.__block.__init__() + if hasattr(self, '_Thread__block'): # DummyThread deletes self.__block + self.__block.__init__() self.__started._reset_internal_locks() @property @@ -884,7 +885,8 @@ thread._Thread__ident = ident # Any condition variables hanging off of the active thread may # be in an invalid state, so we reinitialize them. - thread._reset_internal_locks() + if hasattr(thread, '_reset_internal_locks'): + thread._reset_internal_locks() new_active[ident] = thread else: # All the others are already stopped. From python-checkins at python.org Tue Jan 4 19:47:18 2011 From: python-checkins at python.org (daniel.stutzbach) Date: Tue, 4 Jan 2011 19:47:18 +0100 (CET) Subject: [Python-checkins] r87743 - python/branches/release27-maint/Misc/NEWS Message-ID: <20110104184718.31674EE9C5@mail.python.org> Author: daniel.stutzbach Date: Tue Jan 4 19:47:17 2011 New Revision: 87743 Log: Fix typo Modified: python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Tue Jan 4 19:47:17 2011 @@ -53,7 +53,7 @@ - Issue #10750: The ``raw`` attribute of buffered IO objects is now read-only. -- Issue #10242: unittest.TestCase.assertItemsEqual makes too many assumgptions +- Issue #10242: unittest.TestCase.assertItemsEqual makes too many assumptions about input. - Issue #10611: SystemExit should not cause a unittest test run to exit. From python-checkins at python.org Tue Jan 4 20:07:07 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 4 Jan 2011 20:07:07 +0100 (CET) Subject: [Python-checkins] r87744 - python/branches/py3k/Lib/subprocess.py Message-ID: <20110104190707.3B0E6EE9DA@mail.python.org> Author: antoine.pitrou Date: Tue Jan 4 20:07:07 2011 New Revision: 87744 Log: In subprocess, wrap pipe fds before launching the child. Hopefully this will fix intermittent failures on some buildbots (issue #8458). Modified: python/branches/py3k/Lib/subprocess.py Modified: python/branches/py3k/Lib/subprocess.py ============================================================================== --- python/branches/py3k/Lib/subprocess.py (original) +++ python/branches/py3k/Lib/subprocess.py Tue Jan 4 20:07:07 2011 @@ -699,13 +699,9 @@ c2pread, c2pwrite, errread, errwrite) = self._get_handles(stdin, stdout, stderr) - self._execute_child(args, executable, preexec_fn, close_fds, - pass_fds, cwd, env, universal_newlines, - startupinfo, creationflags, shell, - p2cread, p2cwrite, - c2pread, c2pwrite, - errread, errwrite, - restore_signals, start_new_session) + # We wrap OS handles *before* launching the child, otherwise a + # quickly terminating child could make our fds unwrappable + # (see #8458). if mswindows: if p2cwrite != -1: @@ -730,6 +726,24 @@ if universal_newlines: self.stderr = io.TextIOWrapper(self.stderr) + try: + self._execute_child(args, executable, preexec_fn, close_fds, + pass_fds, cwd, env, universal_newlines, + startupinfo, creationflags, shell, + p2cread, p2cwrite, + c2pread, c2pwrite, + errread, errwrite, + restore_signals, start_new_session) + except: + # Cleanup if the child failed starting + for f in filter(None, [self.stdin, self.stdout, self.stderr]): + try: + f.close() + except EnvironmentError: + # Ignore EBADF or other errors + pass + raise + def _translate_newlines(self, data, encoding): data = data.replace(b"\r\n", b"\n").replace(b"\r", b"\n") From python-checkins at python.org Tue Jan 4 20:55:49 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 20:55:49 +0100 Subject: [Python-checkins] devguide: Ignore _build directories. Message-ID: brett.cannon pushed 875c89e31381 to devguide: http://hg.python.org/devguide/rev/875c89e31381 changeset: 6:875c89e31381 user: Brett Cannon date: Tue Jan 04 10:50:06 2011 -0800 summary: Ignore _build directories. files: .hgignore diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -1,3 +1,4 @@ syntax: glob *.swp +_build -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 20:55:50 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 20:55:50 +0100 Subject: [Python-checkins] devguide: Copy of the 'Getting Set Up' doc from the website (needs editing). Message-ID: brett.cannon pushed 6c6251af7d96 to devguide: http://hg.python.org/devguide/rev/6c6251af7d96 changeset: 8:6c6251af7d96 user: Brett Cannon date: Tue Jan 04 10:53:45 2011 -0800 summary: Copy of the 'Getting Set Up' doc from the website (needs editing). files: setup.rst diff --git a/setup.rst b/setup.rst new file mode 100644 --- /dev/null +++ b/setup.rst @@ -0,0 +1,101 @@ +Getting Set Up +============== + +.. contents:: + + +Checking out the code +===================== + +Python always has the in-development version of the current major versions +along with the last minor release of each major version. For instance, if +Python 2.6 was the latest release (and thus has a major version of *2* and a +minor version of *6*), then the in-development 2.7 branch is available along +with the maintenance branch for 2.6. + +For each branch there is read-only access for the general public and read-write +access for those with commit privileges (called "core developers"). The +location of these branches and the steps to check out the code are listed in +the `dev FAQ`_. + + +Compiling for debugging +======================= + +Python has two features to aid in developing for it. First, there is a +``Py_DEBUG`` compilation flag which turns on some features in the interpreter +which will help with debugging. While this is not the only compilation flag +available (see ``Misc/SpecialBuilds.txt`` in a checkout for all of them), it is +the basic one that you should always use as it tends to catch bugs more often +than running a build of Python without the flag. + +The other feature is support for using code directly from a checkout of Python. +This is handy as it means you do not need to install your build of Python but +can just use the build in-place. It also means that when you edit code in your +checkout you get to see the results without having to install the changed files +as well. + +The steps to compile a debug version of Python are specified in the `dev FAQ`_. + + +Editors and Tools +================== + +Python includes within its source tree some files to help work with various +popular editors and tools. A list of those tools and what is available for them +can be found in the `dev FAQ`_. + + +Directory Structure +=================== + +There are several top-level directories in the Python source tree. Knowing what +which one is meant to hold will help you find where a certain piece of +functionality is implemented. Do realize, though, there are always exceptions to +every rule. + +``Doc`` + ?????? The official documentation. This is what http://docs.python.org/ uses. The + tools for building the documentation is kept in another repository. To + build the docs, see ``Doc/README.txt``. + +``Grammar`` + ?????? Contains the EBNF grammar file for Python. + +``Include`` + ?????? Contains all interpreter-wide header files. + +``Lib`` + ?????? The part of the standard library implemented in pure Python is here. + +``Mac`` + ?????? Mac-specific code for things such as using IDLE as an OS X application. + +``Misc`` + ?????? Things that do not belong elsewhere. Typically this is varying kinds of + documentation. + +``Modules`` + ?????? The part of the standard library (plus some other code) that is implemented + as extension modules. + +``Objects`` + ?????? Code for all built-in types. + +``PC`` + ?????? Windows-specific code along with build files for VC 6, 7, & 8 along with + OS/2. + +``PCbuild`` + ?????? Build files for VC 9 and newer. + +``Parser`` + ?????? Code related to the parser. The definition of the AST nodes is also kept + here. + +``Python`` + ?????? The code that makes Python run. This includes the compiler, eval loop and + various built-in modules. + +``Tools`` + Various tools that are (or have been) used to maintain Python. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 20:55:49 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 20:55:49 +0100 Subject: [Python-checkins] devguide: Simplify the overall title. Message-ID: brett.cannon pushed c020f5db006c to devguide: http://hg.python.org/devguide/rev/c020f5db006c changeset: 7:c020f5db006c user: Brett Cannon date: Tue Jan 04 10:50:21 2011 -0800 summary: Simplify the overall title. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -1,5 +1,5 @@ -Welcome to Python Developer's Guide's documentation! -==================================================== +Python Developer's Guide +======================== Contents: -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 20:55:50 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 20:55:50 +0100 Subject: [Python-checkins] devguide: Ref linking for setup.rst. Message-ID: brett.cannon pushed de3088c14779 to devguide: http://hg.python.org/devguide/rev/de3088c14779 changeset: 9:de3088c14779 user: Brett Cannon date: Tue Jan 04 10:55:17 2011 -0800 summary: Ref linking for setup.rst. files: index.rst setup.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -15,7 +15,7 @@ follow the top-level bullet points in order, while sub-level bullet points can be done in any order. -* `Getting set up `_ +* :ref:`setup` * Coding style guides * `PEP 7`_ * `PEP 8`_ diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -1,3 +1,5 @@ +.. _setup: + Getting Set Up ============== -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 20:55:50 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 20:55:50 +0100 Subject: [Python-checkins] devguide: Rework the source code checkout step. Message-ID: brett.cannon pushed 294297ccc34b to devguide: http://hg.python.org/devguide/rev/294297ccc34b changeset: 10:294297ccc34b user: Brett Cannon date: Tue Jan 04 11:09:56 2011 -0800 summary: Rework the source code checkout step. files: setup.rst diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -7,18 +7,33 @@ Checking out the code -===================== +---------------------- -Python always has the in-development version of the current major versions -along with the last minor release of each major version. For instance, if -Python 2.6 was the latest release (and thus has a major version of *2* and a -minor version of *6*), then the in-development 2.7 branch is available along -with the maintenance branch for 2.6. +One should always work from a checkout of the Python source code. While it may +be tempting to work from the downloaded copy you already have installed on your +machine, it is very likely that you will be working from out-of-date code as +the Python core developers are constantly updating and fixing things in their +:abbr:`VCS (Version Control System)`. It also means you will have better tool +support through the VCS as it will provide a diff tool, etc. -For each branch there is read-only access for the general public and read-write -access for those with commit privileges (called "core developers"). The -location of these branches and the steps to check out the code are listed in -the `dev FAQ`_. +To get a read-only checkout of Python's source, you need to checkout the source +code. Python development is tracked using svn_. To get a read-only checkout of +the in-development branch of Python (core developers should read XXX for a +read-write checkout), run:: + + svn co http://svn.python.org/projects/python/branches/py3k + +If you want a read-only checkout of an already-released version of Python, +i.e., a version in maintenance mode, run something like the following which +gets you a checkout for Python 3.1:: + + svn co http://svn.python.org/projects/python/branches/release31-maint + +To check out a version of Python other than 3.1, simply change the number in +the above URL to the major/minor version (e.g., ``release27-maint`` for Python +2.7). + +.. _svn: http://subversion.tigris.org/ Compiling for debugging @@ -101,3 +116,6 @@ ``Tools`` Various tools that are (or have been) used to maintain Python. + + +.. _dev FAQ: XXX -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 20:55:50 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 20:55:50 +0100 Subject: [Python-checkins] devguide: Add a copy of the dev FAQ to help keep track of what questions have not been Message-ID: brett.cannon pushed a0353d79634d to devguide: http://hg.python.org/devguide/rev/a0353d79634d changeset: 11:a0353d79634d user: Brett Cannon date: Tue Jan 04 11:41:59 2011 -0800 summary: Add a copy of the dev FAQ to help keep track of what questions have not been rolled into the new docs. files: faq.rst diff --git a/faq.rst b/faq.rst new file mode 100644 --- /dev/null +++ b/faq.rst @@ -0,0 +1,892 @@ +Content-type: text/x-rst +Title: Frequently Asked Questions for Python Developers + +:Title: Frequently Asked Questions for Python Developers +:Date: $Date: 2010-09-15 07:35:08 -0700 (Wed, 15 Sep 2010) $ +:Version: $Revision: 10931 $ +:Web site: http://www.python.org/dev/faq/ + +.. contents:: :depth: 3 +.. sectnum:: + +General Information +===================================================================== + +Where do I start? +----------------- + +The `dev page`_ links to various documents to help get you +started. + +.. _dev page: /dev/ + + +How can I become a developer? +--------------------------------------------------------------------------- + +Contribute on a regular basis through patches and ask for commit +privileges once you have demonstrated a track record of being good +at fixing things. + +(Raymond Hettinger commented on the +`School of Hard Knocks `_ required.) + + + +Version Control +================================== + +Where can I learn about the version control system used, Subversion (svn)? +------------------------------------------------------------------------------- + +`Subversion`_'s (also known as ``svn``) official web site is at +http://subversion.apache.org/ . A book on Subversion published by +`O'Reilly Media`_, `Version Control with Subversion`_, is available +for free online. + +With Subversion installed, you can run the help tool that comes with +Subversion to get help:: + + svn help + +The man page for ``svn`` is rather scant and not very helpful. + +.. _Subversion: http://subversion.apache.org/ +.. _O'Reilly Media: http://www.oreilly.com/ +.. _Version Control with Subversion: http://svnbook.red-bean.com/ + + +What do I need to use Subversion? +------------------------------------------------------------------------------- + +.. _download Subversion: http://subversion.apache.org/packages.html + +UNIX +''''''''''''''''''' + +First, you need to `download Subversion`_. Most UNIX-based operating systems +have binary packages available. Also, most packaging systems also +have Subversion available. + +If you have checkin rights, you need OpenSSH_. This is needed to verify +your identity when performing commits. + +.. _OpenSSH: http://www.openssh.org/ + +Windows +''''''''''''''''''' + +You have several options on Windows. One is to `download Subversion`_ itself +which will give you a command-line version. Another option is to `download +TortoiseSVN`_ which integrates with Windows Explorer. + +If you have checkin rights, you will also need an SSH client. +`Download PuTTY and friends`_ (PuTTYgen, Pageant, and Plink) for this. All +other questions in this FAQ will assume you are using these tools. + +Once you have both Subversion and PuTTY installed you must tell Subversion +where to find an SSH client. Do this by editing +``%APPDATA%\Subversion\config`` to have the following +section:: + + [tunnels] + ssh="c:/path/to/putty/plink.exe" -T + +Change the path to be the proper one for your system. The ``-T`` +option prevents a pseudo-terminal from being created. + +You can use Pageant to prevent from having to type in your password for your +SSH 2 key constantly. If you prefer not to have another program running, +you need to create a profile in PuTTY. + +Go to Session:Saved Sessions and create a new profile named +``svn.python.org``. In Session:Host Name, enter ``svn.python.org``. In +SSH/Auth:Private key file select your private key. In Connection:Auto-login +username enter ``pythondev``. + +With this set up, paths are slightly different than most other settings in that +the username is not required. Do take notice of this when choosing to check +out a project! + +.. _download TortoiseSVN: http://tortoisesvn.net/downloads +.. _PuTTY: http://www.chiark.greenend.org.uk/~sgtatham/putty/ +.. _download PuTTY and friends: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html + + +How do I get a checkout of the repository (read-only or read-write)? +------------------------------------------------------------------------------- + +Regardless of whether you are checking out a read-only or read-write version of +the repository, the basic command is the same:: + + svn checkout [PATH] + +```` is the specified location of the project within the repository that +you would like to check out (those paths are discussed later). The optional +``[PATH]`` argument specifies the local directory to put the checkout into. If +left out then the tail part of ```` is used for the directory name. + +For a read-only checkout, the format of ```` is:: + + http://svn.python.org/projects/ + +with `` representing the path to the project. A list of projects can be +viewed at http://svn.python.org/view/ . Any subdirectory may also +be checked out individually. + +For a read-write checkout (with a caveat for Windows users using PuTTY without +Pageant), the format for ```` is:: + + svn+ssh://pythondev at svn.python.org/ + +There are three critical differences between a read-only URL and a read-write +URL. One is the protocol being specified as ``svn+ssh`` and not ``http``. +Next, the username ``pythondev`` is added (*note* that +Windows users using PuTTY without Pageant should leave off ``pythondev@`` if +PuTTY was set up following the instructions in this FAQ). Lastly, note that +``projects`` was removed from the path entirely for a read-write checkout. + +The repositories most people will be interested in are: + +=========== ============================================================== ========================================================================== +Repository read-only read-write +----------- -------------------------------------------------------------- -------------------------------------------------------------------------- +PEPs http://svn.python.org/projects/peps/trunk svn+ssh://pythondev at svn.python.org/peps/trunk +2.7 http://svn.python.org/projects/python/branches/release27-maint svn+ssh://pythondev at svn.python.org/python/branches/release27-maint +3.1 http://svn.python.org/projects/python/branches/release31-maint svn+ssh://pythondev at svn.python.org/python/branches/release31-maint +3.2 http://svn.python.org/projects/python/branches/py3k svn+ssh://pythondev at svn.python.org/python/branches/py3k +=========== ============================================================== ========================================================================== + + +How do I update my working copy to be in sync with the repository? +------------------------------------------------------------------------------- + +Run:: + + svn update + +from the directory you wish to update. The directory and all its +subdirectories will be updated. + + +How do I browse the source code through a web browser? +------------------------------------------------------------------------------- + +Visit http://svn.python.org/view/ to browse the Subversion repository. + + +Where can I find a downloadable snapshot of the source code? +------------------------------------------------------------------------------- + +Visit http://svn.python.org/snapshots/ to download a tarball containing a daily +snapshot of the repository. + + +Who has commit privileges on the Subversion repository? +------------------------------------------------------------------------------- + +See http://www.python.org/dev/committers for a list of committers. + + +How do I verify that my commit privileges are working? +------------------------------------------------------------------------------- + +UNIX +''''''''''''''''''' + +If you are listed as a committer at http://www.python.org/dev/committers , then +you should be able to execute:: + + ssh pythondev at svn.python.org + +and have the following printed to your terminal:: + + ( success ( 2 2 ( ) ( edit-pipeline svndiff1 absent-entries + commit-revprops depth log-revprops partial-replay ) ) ) + +If something else is printed, then there is a problem with your SSH 2 public +key and you should contact pydotorg at python.org . + +Windows +''''''''''''''''''' + +If you are using Pageant, you can verify that your SSH 2 key is set up properly +by running:: + + c:\path\to\putty\plink.exe pythondev at svn.python.org + +Using the proper path to your PuTTY installation, you should get a response +from the server that says:: + + ( success ( 1 2 ( ANONYMOUS EXTERNAL ) ( edit-pipeline ) ) ) + +If there is a failure, run ``plink`` with ``-v`` to analyse the problem. + +If you are using a profile in PuTTY, the best way to test is to try to log in +through Open. + + +What configuration settings should I use? +------------------------------------------------------------------------------- + +Make sure the following settings are in your Subversion config file +(``~/.subversion/config`` under UNIX):: + + [miscellany] + enable-auto-props = yes + + [auto-props] + * = svn:eol-style=native + *.c = svn:keywords=Id + *.h = svn:keywords=Id + *.py = svn:keywords=Id + *.txt = svn:keywords=Author Date Id Revision + +The ``[auto-props]`` line specifies the beginning of the section in the config +file. The ``svn:eol-style`` setting tells Subversion to check out files using +the native line endings on your OS. It will also automatically convert line +endings upon committal so that they are consistent across all platforms. The +``svn:keywords`` settings are to automatically substitute ``$keyword$`` +arguments in files that match the pattern. ``*.txt`` has more options so as to +cover all needed keywords for PEPs_. + +The ``[miscellany]`` section and its one option make Subversion apply the +various rules in the ``[auto-props]`` section automatically to all added or +imported files into the respository. + +.. _PEPs: http://www.python.org/dev/peps/ + + +How do I add a file or directory to the repository? +------------------------------------------------------------------------------- + +Simply specify the path to the file or directory to add and run:: + + svn add PATH + +Subversion will skip any directories it already knows about. But if +you want new files that exist in any directories specified in ``PATH``, specify +``--force`` and Subversion will check *all* directories for new files. + +You will then need to run ``svn commit`` (as discussed in +`How do I commit a change to a file?`_) to commit the file to the repository. + + +How do I commit a change to a file? +------------------------------------------------------------------------------- + +To have any changes to a file (which include adding a new file or deleting an +existing one), you use the command:: + + svn commit [PATH] + +Although ``[PATH]`` is optional, if PATH is omitted all changes +in your local copy will be committed to the repository. +**DO NOT USE THIS!!!** You should specify the specific files +to be committed unless you are *absolutely* positive that +*all outstanding modifications* are meant to go in this commit. + +To abort a commit that you are in the middle of, leave the message +empty (i.e., close the text editor without adding any text for the +message). Subversion will confirm if you want to abort the commit. + +If you do not like the default text editor Subversion uses for +entering commmit messages, you may specify a different editor +in your Subversion config file with the +``editor-cmd`` option in the ``[helpers]`` section. + + +How do I delete a file or directory in the repository? +------------------------------------------------------------------------------- + +Specify the path to be removed with:: + + svn delete PATH + +Any modified files or files that are not checked in will not be deleted +in the working copy on your machine. + + +What files are modified locally in my working copy? +------------------------------------------------------------------------------- + +Running:: + + svn status [PATH] + +will list any differences between your working copy and the repository. Some +key indicators that can appear in the first column of output are: + += =========================== +A Scheduled to be added + +D Scheduled to be deleted + +M Modified locally + +? Not under version control += =========================== + + +How do I find out what Subversion properties are set for a file or directory? +------------------------------------------------------------------------------- + +:: + + svn proplist PATH + + +How do I revert a file I have modified back to the version in the respository? +------------------------------------------------------------------------------- + +Running:: + + svn revert PATH + +will change ``PATH`` to match the version in the repository, throwing away any +changes you made locally. If you run:: + + svn revert -R . + +from the root of your local repository it will recursively restore everything +to match up with the main server. + + +How do I find out who edited or what revision changed a line last? +------------------------------------------------------------------------------- + +You want:: + + svn blame PATH + +This will output to stdout every line of the file along with what revision +number last touched that line and who committed that revision. Since it is +printed to stdout, you probably want to pipe the output to a pager:: + + svn blame PATH | less + + +How can I see a list of log messages for a file or specific revision? +--------------------------------------------------------------------- + +To see the log messages for a specific file, run:: + + svn log PATH + +That will list all messages that pertain to the file specified in ``PATH``. + +If you want to view the log message for a specific revision, run:: + + svn log --verbose -r REV + +With ``REV`` substituted with the revision number. The ``--verbose`` flag +should be used to get a listing of all files modified in that revision. + + +How can I edit the log message of a committed revision? +------------------------------------------------------------------------------- + +Use:: + + svn propedit -r --revprop svn:log + +Replace ```` with the revision number of the commit whose log message +you wish to change. + + +How do I get a diff between the repository and my working copy for a file? +------------------------------------------------------------------------------- + +The diff between your working copy and what is in the repository can be had +with:: + + svn diff PATH + +This will work off the current revision in the repository. To diff your +working copy with a specific revision, do:: + + svn diff -r REV PATH + +Finally, to generate a diff between two specific revisions, use:: + + svn diff -r REV1:REV2 PATH + +Notice the ``:`` between ``REV1`` and ``REV2``. + + +How do I undo the changes made in a recent committal? +------------------------------------------------------------------------------- + +Assuming your bad revision is ``NEW`` and ``OLD`` is the equivalent of ``NEW +- 1``, then run:: + + svn merge -r NEW:OLD PATH + +This will revert *all* files back to their state in revision ``OLD``. +The reason that ``OLD`` is just ``NEW - 1`` is you do not want files to be +accidentally reverted to a state older than your changes, just to the point +prior. + +Note: PATH here refers to the top of the checked out repository, +not the full pathname to a file. PATH can refer to a different +branch when merging from the head, but it must still be the top +and not an individual file or subdirectory. + + +How do I update to a specific release tag? +------------------------------------------------------------------------------- + +Run:: + + svn list svn+ssh://pythondev at svn.python.org/python/tags + +or visit:: + + http://svn.python.org/view/python/tags/ + +to get a list of tags. To switch your current sandbox to a specific tag, +run:: + + svn switch svn+ssh://pythondev at svn.python.org/python/tags/r242 + +To just update to the revision corresponding to that tag without changing +the metadata for the repository, note the revision number corresponding to +the tag of interest and update to it, e.g.:: + + svn update -r 39619 + + +Why should I use ``svn switch``? +------------------------------------------------------------------------------- + +If you picture each file/directory in Subversion as uniquely identified +by a 2-space coordinate system [URL, revision] (given a checkout, you can +use "svn info" to get its coordinates), then we can say that "svn up -r N" +(for some revision number N) keeps the url unchanged and changes the +revision to whatever number you specified. In other words, you get the +state of the working copy URL at the time revision N was created. For +instance, if you execute it with revision 39619 within the trunk working +copy, you will get the trunk at the moment 2.4.2 was released. + +On the other hand, "svn switch" moves the URL: it basically "moves" your +checkout from [old_URL, revision] to [new_URL, HEAD], downloading the +minimal set of diffs to do so. If the new_URL is a tag URL +(e.g. .../tags/r242), it means any revision is good, since nobody is going +to commit into that directory (it will stay unchanged forever). So +[/tags/r242, HEAD] is the same as any other [/tags/r242, revision] (assuming +of course that /tags/r242 was already created at the time the revision was +created). + +If you want to create a sandbox corresponding to a particular release tag, +use svn switch to switch to [/tags/some_tag, HEAD] if you don't plan on +doing modifications. On the other hand if you want to make modifications to +a particular release branch, use svn switch to change to +[/branches/some_branch, HEAD]. + +(Written by Giovanni Bajo on python-dev.) + + +How do I create a branch? +------------------------- + +The best way is to do a server-side copy by specifying the URL for the source +of the branch, and the eventual destination URL for the new branch:: + + svn copy SRC_URL DEST_URL + +You can then checkout your branch as normal. You will want to prepare your +branch for future merging from the source branch so as to keep them in sync. +To find out how to do that, read `How do I merge between branches?`_. + + +What tools do I need to merge between branches? +----------------------------------------------- + +You need `svnmerge.py +`__. + + +How do I prepare a new branch for merging? +------------------------------------------ + +You need to initialize a new branch by having ``svnmerge.py`` discover the +revision number that the branch was created with. Do this with the command:: + + svnmerge.py init + +Then check in the change to the root of the branch. This is a one-time +operation (i.e. only when the branch is originally created, not when each +developer creates a local checkout for the branch). + + +How do I merge between branches? +-------------------------------- + +In the current situation for Python there are four branches under development, +meaning that there are three branches to merge into. Assuming a change is +committed into ``trunk`` as revision 0001, you merge into the 2.x maintenance +by doing:: + + # In the 2.x maintenance branch checkout. + svnmerge.py merge -r 0001 + svn commit -F svnmerge-commit-message.txt # r0002 + +To pull into py3k:: + + # In a py3k checkout. + svnmerge.py merge -r 0001 + svn commit -F svnmerge-commit-message.txt # r0003 + +The 3.x maintenance branch is a special case as you must pull from the py3k +branch revision, *not* trunk:: + + # In a 3.x maintenance checkout. + svnmerge.py merge -r 0003 # Notice the rev is the one from py3k! + svn resolved . + svn commit -F svnmerge-commit-message.txt + + +How do I block a specific revision from being merged into a branch? +------------------------------------------------------------------- + +With the revision number that you want to block handy and ``svnmerge.py``, go +to your checkout of the branch where you want to block the revision and run:: + + svnmerge.py block -r + +This will modify the repository's top directory (which should be your current +directory) and create ``svnmerge-commit-message.txt`` which contains a +generated log message. + +If the command says "no available revisions to block", then it means someone +already merged the revision. + +To check in the new metadata, run:: + + svn ci -F svnmerge-commit-message.txt + + +How do I include an external svn repository (external definition) in the repository? +------------------------------------------------------------------------------------ + +Before attempting to include an external svn repository into Python's +repository, it is important to realize that you can only include directories, +not individual files. + +To include a directory of an external definition (external svn repository) as a +directory you need to edit the ``svn:externals`` property on the root of the +repository you are working with using the format of:: + + local_directory remote_repositories_http_address + +For instance, to include Python's sandbox repository in the 'sandbox' directory +of your repository, run ``svn propedit svn:externals .`` while in the root of +your repository and enter:: + + sandbox http://svn.python.org/projects/sandbox/trunk/ + +in your text editor. The next time you run ``svn update`` it will pull in the +external definition. + + +How can I create a directory in the sandbox? +------------------------------------------------------------------------------ + +Assuming you have commit privileges and you do not already have a complete +checkout of the sandbox itself, the easiest way is to use svn's ``mkdir`` +command:: + + svn mkdir svn+ssh://pythondev at svn.python.org/sandbox/trunk/ + +That command will create the new directory on the server. To gain access to +the new directory you then checkout it out (substitute ``mkdir`` in the command +above with ``checkout``). + +If you already have a complete checkout of the sandbox then you can just use +``svn mkdir`` on a local directory name and check in the new directory itself. + + +SSH +======= + +How do I generate an SSH 2 public key? +------------------------------------------------------------------------------- + +All generated SSH keys should be sent to pydotorg for adding to the list of +keys. + +UNIX +''''''''''''''''''' + +Run:: + + ssh-keygen -t rsa + +This will generate a two files; your public key and your private key. Your +public key is the file ending in ``.pub``. + +Windows +''''''''''''''''''' + +Use PuTTYgen_ to generate your public key. Choose the "SSH2 DSA" radio button, +have it create an OpenSSH formatted key, choose a password, and save the private +key to a file. Copy the section with the public key (using Alt-P) to a file; +that file now has your public key. + + +.. _PuTTYgen: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html + +Is there a way to prevent from having to enter my password for my SSH 2 public key constantly? +------------------------------------------------------------------------------------------------ + +UNIX +''''''''''''''''''' + +Use ``ssh-agent`` and ``ssh-add`` to register your private key with SSH for +your current session. The simplest solution, though, is to use KeyChain_, +which is a shell script that will handle ``ssh-agent`` and ``ssh-add`` for you +once per login instead of per session. + +.. _KeyChain: http://www.gentoo.org/proj/en/keychain/ + +Windows +''''''''''''''''''' + +Running Pageant_ will prevent you from having to type your password constantly. +If you add a shortcut to Pageant to your Autostart group and edit the shortcut +so that the command line includes an argument to your private key then Pageant +will load the key every time you log in. + + +.. _Pageant: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html + +Can I make check-ins from machines other than the one I generated the keys on? +------------------------------------------------------------------------------ + +Yes, all you need is to make sure that the machine you want to check +in code from has both the public and private keys in the standard +place that ssh will look for them (i.e. ~/.ssh on Unix machines). +Please note that although the key file ending in .pub contains your +user name and machine name in it, that information is not used by the +verification process, therefore these key files can be moved to a +different computer and used for verification. Please guard your keys +and never share your private key with anyone. If you lose the media +on which your keys are stored or the machine on which your keys are +stored, be sure to report this to pydotorg at python.org at the same time +that you change your keys. + + +Compilation +===================================================================== + +How do I create a debug build of Python? +----------------------------------------- + +A debug build, sometimes called a "pydebug" build, has extra checks and bits of +information to help with developing Python. + +UNIX +''''''''''''''''''''''' + +The basic steps for building Python for development is to configure it and +then compile it. + +Configuration is typically:: + + ./configure --prefix=/dev/null --with-pydebug + +More flags are available to ``configure``, but this is the minimum you should +do. This will give you a debug version of Python along with a safety measure +to prevent you from accidentally installing your development version over +your system install. If you are developing on OS X for Python 2.x and will not +be working with the OS X-specific modules from the standard library, then +consider using the ``--without-toolbox-glue`` flag to faster compilation time. + +Once ``configure`` is done, you can then compile Python.:: + + make -s + +This will build Python with only warnings and errors being printed to +stderr. If you are using a multi-core machine you can use the ``-j`` flag +along with the number of cores your machine has +(e.g. with two cores, you would want ``make -s -j2``) +to compile multiple files at a time. + +Once Python is done building you will then have a working build of Python +that can be run in-place; ``./python`` on most machines, ``./python.exe`` +on OS X. + +Windows +''''''''''''''''''''''''' + +For VC 9, the ``PCbuild`` directory contains the build +files. For older versions of VC, see the ``PC`` directory. For a free +compiler for Windows, go to http://www.microsoft.com/express/ . + +To build from the GUI, load the project files and press F7. Make sure to +choose the Debug build. If you want to build from the command line, run the +``build_env.bat`` file to get a terminal with proper environment variables. +From that terminal, run:: + + build.bat -c Debug + +Once built you will want to set Python as a startup project. F5 will +launch the interpreter as well as double-clicking the binary. + + +Editors and Tools +===================================================================== + +What support is included in Python's source code for Vim? +--------------------------------------------------------- + +Within the ``Misc/Vim`` directory you will find two files to help you when +editing Python code. One is ``python.vim``, which is a generated syntax +highlight file for Python code. This file is updated much more frequently as it +contains syntax highlighting for keywords as they are added to the source tree. +See the top of the file to find out how to use the file. + +The other file for Vim is a vimrc file that supports PEP 7 and 8 coding +standards. All settings are specific to Python and C code and thus will not +affect other settings. There are also some settings which are helpful but +turned off by default at the end of the file if one cares to use non-essential +settings. Once again, see the top of the file to learn how to take advantage of +the file. + + +What support is included in Python's source code for gdb? +---------------------------------------------------------- + +The ``Misc/gdbinit`` file contains several helpful commands that can be added +to your gdb session. You can either copy the commands into your own +``.gdbinit`` file or, if you don't have your own version of the file, simply +symlink ``~/.gdbinit`` to ``Misc/gdbinit``. + + +Can I run Valgrind against Python? +---------------------------------- + +Because of how Python uses memory, Valgrind requires setting some suppression +rules to cut down on the false positives (which still occur, suggesting one +typically should know how Python uses memory before running Valgrind against +Python). See ``Misc/README.valgrind`` for more details. + + +Patches +===================================================================== + +How to make a patch? +------------------------- + + +If you are using subversion (anonymous or developer) you can use +subversion to make the patches for you. Just edit your local copy and +enter the following command:: + + svn diff | tee ~/name_of_the_patch.diff + +Else you can use the diff util which comes with most operating systems (a +Windows version is available as part of the cygwin tools). + + +How do I apply a patch? +------------------------- + +For the general case, to apply a patch go to the directory that the patch was +created from (usually /dist/src/) and run:: + + patch -p0 < name_of_the_patch.diff + +The ``-p`` option specifies the number of directory separators ("/" in the +case of UNIX) to remove from the paths of the files in the patch. ``-p0`` +leaves the paths alone. + + +How do I undo an applied patch? +------------------------------- + +Undoing a patch differs from applying one by only a command-line option:: + + patch -R -p0 < name_of_the_patch.diff + +Another option is to have 'patch' create backups of all files by using the +``-b`` command-line option. See the man page for 'patch' on the details of +use. + + +How to submit a patch? +--------------------------- + +Please consult the patch submission guidelines at +http://www.python.org/patches/ . + + +How to test a patch? +------------------------------ + +Firstly, you'll need to get a checkout of the source tree you wish to +test the patch against and then build python from this source tree. + +Once you've done that, you can use Python's extensive regression test +suite to check that the patch hasn't broken anything. + +In general, for thorough testing, use:: + + python -m test.regrtest -uall + +For typical testing use:: + + python -m test.regrtest + +For running specific test modules:: + + python -m test.regrtest test_mod1 test_mod2 + +NB: Enabling the relevant test resources via ``-uall`` or something more +specific is especially important when working on things like the +networking code or the audio support - many of the relevant tests are +skipped by default. + +For more thorough documentation, +read the documentation for the ``test`` package at +http://docs.python.org/library/test.html. + +If you suspect the patch may impact other operating systems, test as +many as you have easy access to. You can get help on alternate +platforms by contacting the people listed on +http://www.python.org/moin/PythonTesters, who have +volunteered to support a particular operating system. + + +How to change the status of a patch? +----------------------------------------- + + +To change the status of a patch or assign it to somebody else you have to +have the Developer role in the bug tracker. Contact one of the project +administrators if the following does not work for you. + +Click on the patch itself. In the screen that comes up, there is a drop-box +for "Assigned To:" and a drop-box for "Status:" where you can select a new +responsible developer or a new status respectively. After selecting the +appropriate victim and status, hit the "Submit Changes" button at the bottom +of the page. + +Note: If you are sure that you have the right permissions and a drop-box +does not appear, check that you are actually logged in to Roundup! + + +Bugs +===================================================================== + +Where can I submit/view bugs for Python? +--------------------------------------------- + + +The Python project uses Roundup for bug tracking. Go to +http://bugs.python.org/ for all bug management needs. You will need to +create a Roundup account for yourself before submitting the first bug +report; anonymous reports have been disabled since it was too +difficult to get in contact with submitters. If you previously +had used SourceForge to report Python bugs, you can use Roundup's +"Lost your login?" link to obtain your Roundup password. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 20:55:50 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 20:55:50 +0100 Subject: [Python-checkins] devguide: Add a VCS setup section. Message-ID: brett.cannon pushed f7cbf9228950 to devguide: http://hg.python.org/devguide/rev/f7cbf9228950 changeset: 14:f7cbf9228950 user: Brett Cannon date: Tue Jan 04 11:55:00 2011 -0800 summary: Add a VCS setup section. files: setup.rst diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -12,6 +12,38 @@ .. contents:: +Version Control Setup +--------------------- + +CPython is developed using svn_. Make sure the following settings are in your +svn config file (``~/.subversion/config`` under UNIX):: + + [miscellany] + enable-auto-props = yes + + [auto-props] + * = svn:eol-style=native + *.c = svn:keywords=Id + *.h = svn:keywords=Id + *.py = svn:keywords=Id + *.txt = svn:keywords=Author Date Id Revision + +The ``[auto-props]`` line specifies the beginning of the section in the config +file dealing with svn properties and line endings. The ``svn:eol-style`` +setting tells Subversion to check out files using the native line endings on +your OS. It will also automatically convert line endings upon committal so +that they are consistent across all platforms. The ``svn:keywords`` settings +are to automatically substitute ``$keyword$`` arguments in files that match the +pattern. ``*.txt`` has more options so as to cover all needed keywords for +PEPs_. + +The ``[miscellany]`` section and its one option make svn apply the +various rules in the ``[auto-props]`` section automatically to all added or +imported files into the respository. + +.. _svn: http://subversion.tigris.org/ + + Checking out the code ---------------------- @@ -19,11 +51,11 @@ be tempting to work from the downloaded copy you already have installed on your machine, it is very likely that you will be working from out-of-date code as the Python core developers are constantly updating and fixing things in their -:abbr:`VCS (Version Control System)`. It also means you will have better tool +:abbr:`VCS`. It also means you will have better tool support through the VCS as it will provide a diff tool, etc. To get a read-only checkout of CPython's source, you need to checkout the source -code. Python development is tracked using svn_. To get a read-only checkout of +code. To get a read-only checkout of the in-development branch of Python (core developers should read XXX for a read-write checkout), run:: @@ -43,8 +75,6 @@ This means that it if you edit Python source code in your checkout the changes will be picked up by the interpreter for immediate testing. -.. _svn: http://subversion.tigris.org/ - Compiling (for debugging) ------------------------- -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 20:55:50 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 20:55:50 +0100 Subject: [Python-checkins] devguide: Strip out all generic svn instructions from the FAQ. It's not only Message-ID: brett.cannon pushed 72a286c3452d to devguide: http://hg.python.org/devguide/rev/72a286c3452d changeset: 13:72a286c3452d user: Brett Cannon date: Tue Jan 04 11:48:38 2011 -0800 summary: Strip out all generic svn instructions from the FAQ. It's not only silly to duplicate instructions that can be found all over the internet that are maintained by the creators of the tools under discussion, but it's a maintenance burden that is unneeded. files: faq.rst diff --git a/faq.rst b/faq.rst --- a/faq.rst +++ b/faq.rst @@ -12,14 +12,6 @@ General Information ===================================================================== -Where do I start? ------------------ - -The `dev page`_ links to various documents to help get you -started. - -.. _dev page: /dev/ - How can I become a developer? --------------------------------------------------------------------------- @@ -36,25 +28,6 @@ Version Control ================================== -Where can I learn about the version control system used, Subversion (svn)? -------------------------------------------------------------------------------- - -`Subversion`_'s (also known as ``svn``) official web site is at -http://subversion.apache.org/ . A book on Subversion published by -`O'Reilly Media`_, `Version Control with Subversion`_, is available -for free online. - -With Subversion installed, you can run the help tool that comes with -Subversion to get help:: - - svn help - -The man page for ``svn`` is rather scant and not very helpful. - -.. _Subversion: http://subversion.apache.org/ -.. _O'Reilly Media: http://www.oreilly.com/ -.. _Version Control with Subversion: http://svnbook.red-bean.com/ - What do I need to use Subversion? ------------------------------------------------------------------------------- @@ -64,10 +37,6 @@ UNIX ''''''''''''''''''' -First, you need to `download Subversion`_. Most UNIX-based operating systems -have binary packages available. Also, most packaging systems also -have Subversion available. - If you have checkin rights, you need OpenSSH_. This is needed to verify your identity when performing commits. @@ -76,10 +45,6 @@ Windows ''''''''''''''''''' -You have several options on Windows. One is to `download Subversion`_ itself -which will give you a command-line version. Another option is to `download -TortoiseSVN`_ which integrates with Windows Explorer. - If you have checkin rights, you will also need an SSH client. `Download PuTTY and friends`_ (PuTTYgen, Pageant, and Plink) for this. All other questions in this FAQ will assume you are using these tools. @@ -116,24 +81,6 @@ How do I get a checkout of the repository (read-only or read-write)? ------------------------------------------------------------------------------- -Regardless of whether you are checking out a read-only or read-write version of -the repository, the basic command is the same:: - - svn checkout [PATH] - -```` is the specified location of the project within the repository that -you would like to check out (those paths are discussed later). The optional -``[PATH]`` argument specifies the local directory to put the checkout into. If -left out then the tail part of ```` is used for the directory name. - -For a read-only checkout, the format of ```` is:: - - http://svn.python.org/projects/ - -with `` representing the path to the project. A list of projects can be -viewed at http://svn.python.org/view/ . Any subdirectory may also -be checked out individually. - For a read-write checkout (with a caveat for Windows users using PuTTY without Pageant), the format for ```` is:: @@ -158,16 +105,6 @@ =========== ============================================================== ========================================================================== -How do I update my working copy to be in sync with the repository? -------------------------------------------------------------------------------- - -Run:: - - svn update - -from the directory you wish to update. The directory and all its -subdirectories will be updated. - How do I browse the source code through a web browser? ------------------------------------------------------------------------------- @@ -257,247 +194,6 @@ .. _PEPs: http://www.python.org/dev/peps/ -How do I add a file or directory to the repository? -------------------------------------------------------------------------------- - -Simply specify the path to the file or directory to add and run:: - - svn add PATH - -Subversion will skip any directories it already knows about. But if -you want new files that exist in any directories specified in ``PATH``, specify -``--force`` and Subversion will check *all* directories for new files. - -You will then need to run ``svn commit`` (as discussed in -`How do I commit a change to a file?`_) to commit the file to the repository. - - -How do I commit a change to a file? -------------------------------------------------------------------------------- - -To have any changes to a file (which include adding a new file or deleting an -existing one), you use the command:: - - svn commit [PATH] - -Although ``[PATH]`` is optional, if PATH is omitted all changes -in your local copy will be committed to the repository. -**DO NOT USE THIS!!!** You should specify the specific files -to be committed unless you are *absolutely* positive that -*all outstanding modifications* are meant to go in this commit. - -To abort a commit that you are in the middle of, leave the message -empty (i.e., close the text editor without adding any text for the -message). Subversion will confirm if you want to abort the commit. - -If you do not like the default text editor Subversion uses for -entering commmit messages, you may specify a different editor -in your Subversion config file with the -``editor-cmd`` option in the ``[helpers]`` section. - - -How do I delete a file or directory in the repository? -------------------------------------------------------------------------------- - -Specify the path to be removed with:: - - svn delete PATH - -Any modified files or files that are not checked in will not be deleted -in the working copy on your machine. - - -What files are modified locally in my working copy? -------------------------------------------------------------------------------- - -Running:: - - svn status [PATH] - -will list any differences between your working copy and the repository. Some -key indicators that can appear in the first column of output are: - -= =========================== -A Scheduled to be added - -D Scheduled to be deleted - -M Modified locally - -? Not under version control -= =========================== - - -How do I find out what Subversion properties are set for a file or directory? -------------------------------------------------------------------------------- - -:: - - svn proplist PATH - - -How do I revert a file I have modified back to the version in the respository? -------------------------------------------------------------------------------- - -Running:: - - svn revert PATH - -will change ``PATH`` to match the version in the repository, throwing away any -changes you made locally. If you run:: - - svn revert -R . - -from the root of your local repository it will recursively restore everything -to match up with the main server. - - -How do I find out who edited or what revision changed a line last? -------------------------------------------------------------------------------- - -You want:: - - svn blame PATH - -This will output to stdout every line of the file along with what revision -number last touched that line and who committed that revision. Since it is -printed to stdout, you probably want to pipe the output to a pager:: - - svn blame PATH | less - - -How can I see a list of log messages for a file or specific revision? ---------------------------------------------------------------------- - -To see the log messages for a specific file, run:: - - svn log PATH - -That will list all messages that pertain to the file specified in ``PATH``. - -If you want to view the log message for a specific revision, run:: - - svn log --verbose -r REV - -With ``REV`` substituted with the revision number. The ``--verbose`` flag -should be used to get a listing of all files modified in that revision. - - -How can I edit the log message of a committed revision? -------------------------------------------------------------------------------- - -Use:: - - svn propedit -r --revprop svn:log - -Replace ```` with the revision number of the commit whose log message -you wish to change. - - -How do I get a diff between the repository and my working copy for a file? -------------------------------------------------------------------------------- - -The diff between your working copy and what is in the repository can be had -with:: - - svn diff PATH - -This will work off the current revision in the repository. To diff your -working copy with a specific revision, do:: - - svn diff -r REV PATH - -Finally, to generate a diff between two specific revisions, use:: - - svn diff -r REV1:REV2 PATH - -Notice the ``:`` between ``REV1`` and ``REV2``. - - -How do I undo the changes made in a recent committal? -------------------------------------------------------------------------------- - -Assuming your bad revision is ``NEW`` and ``OLD`` is the equivalent of ``NEW -- 1``, then run:: - - svn merge -r NEW:OLD PATH - -This will revert *all* files back to their state in revision ``OLD``. -The reason that ``OLD`` is just ``NEW - 1`` is you do not want files to be -accidentally reverted to a state older than your changes, just to the point -prior. - -Note: PATH here refers to the top of the checked out repository, -not the full pathname to a file. PATH can refer to a different -branch when merging from the head, but it must still be the top -and not an individual file or subdirectory. - - -How do I update to a specific release tag? -------------------------------------------------------------------------------- - -Run:: - - svn list svn+ssh://pythondev at svn.python.org/python/tags - -or visit:: - - http://svn.python.org/view/python/tags/ - -to get a list of tags. To switch your current sandbox to a specific tag, -run:: - - svn switch svn+ssh://pythondev at svn.python.org/python/tags/r242 - -To just update to the revision corresponding to that tag without changing -the metadata for the repository, note the revision number corresponding to -the tag of interest and update to it, e.g.:: - - svn update -r 39619 - - -Why should I use ``svn switch``? -------------------------------------------------------------------------------- - -If you picture each file/directory in Subversion as uniquely identified -by a 2-space coordinate system [URL, revision] (given a checkout, you can -use "svn info" to get its coordinates), then we can say that "svn up -r N" -(for some revision number N) keeps the url unchanged and changes the -revision to whatever number you specified. In other words, you get the -state of the working copy URL at the time revision N was created. For -instance, if you execute it with revision 39619 within the trunk working -copy, you will get the trunk at the moment 2.4.2 was released. - -On the other hand, "svn switch" moves the URL: it basically "moves" your -checkout from [old_URL, revision] to [new_URL, HEAD], downloading the -minimal set of diffs to do so. If the new_URL is a tag URL -(e.g. .../tags/r242), it means any revision is good, since nobody is going -to commit into that directory (it will stay unchanged forever). So -[/tags/r242, HEAD] is the same as any other [/tags/r242, revision] (assuming -of course that /tags/r242 was already created at the time the revision was -created). - -If you want to create a sandbox corresponding to a particular release tag, -use svn switch to switch to [/tags/some_tag, HEAD] if you don't plan on -doing modifications. On the other hand if you want to make modifications to -a particular release branch, use svn switch to change to -[/branches/some_branch, HEAD]. - -(Written by Giovanni Bajo on python-dev.) - - -How do I create a branch? -------------------------- - -The best way is to do a server-side copy by specifying the URL for the source -of the branch, and the eventual destination URL for the new branch:: - - svn copy SRC_URL DEST_URL - -You can then checkout your branch as normal. You will want to prepare your -branch for future merging from the source branch so as to keep them in sync. -To find out how to do that, read `How do I merge between branches?`_. - What tools do I need to merge between branches? ----------------------------------------------- @@ -566,46 +262,6 @@ svn ci -F svnmerge-commit-message.txt -How do I include an external svn repository (external definition) in the repository? ------------------------------------------------------------------------------------- - -Before attempting to include an external svn repository into Python's -repository, it is important to realize that you can only include directories, -not individual files. - -To include a directory of an external definition (external svn repository) as a -directory you need to edit the ``svn:externals`` property on the root of the -repository you are working with using the format of:: - - local_directory remote_repositories_http_address - -For instance, to include Python's sandbox repository in the 'sandbox' directory -of your repository, run ``svn propedit svn:externals .`` while in the root of -your repository and enter:: - - sandbox http://svn.python.org/projects/sandbox/trunk/ - -in your text editor. The next time you run ``svn update`` it will pull in the -external definition. - - -How can I create a directory in the sandbox? ------------------------------------------------------------------------------- - -Assuming you have commit privileges and you do not already have a complete -checkout of the sandbox itself, the easiest way is to use svn's ``mkdir`` -command:: - - svn mkdir svn+ssh://pythondev at svn.python.org/sandbox/trunk/ - -That command will create the new directory on the server. To gain access to -the new directory you then checkout it out (substitute ``mkdir`` in the command -above with ``checkout``). - -If you already have a complete checkout of the sandbox then you can just use -``svn mkdir`` on a local directory name and check in the new directory itself. - - SSH ======= -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 20:55:50 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 20:55:50 +0100 Subject: [Python-checkins] devguide: Make Python/CPython distinction. Message-ID: brett.cannon pushed 25ed1757b81e to devguide: http://hg.python.org/devguide/rev/25ed1757b81e changeset: 12:25ed1757b81e user: Brett Cannon date: Tue Jan 04 11:47:07 2011 -0800 summary: Make Python/CPython distinction. files: setup.rst diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -3,20 +3,26 @@ Getting Set Up ============== +These instructions cover how to get a source checkout and a compiled version of +the CPython interpreter (CPython is the version of Python available from +http://www.python.org/). It will also tell you how to set up various code +editors. Finally, this document also gives an overview of the directory +structure of a CPython checkout. + .. contents:: Checking out the code ---------------------- -One should always work from a checkout of the Python source code. While it may +One should always work from a checkout of the CPython source code. While it may be tempting to work from the downloaded copy you already have installed on your machine, it is very likely that you will be working from out-of-date code as the Python core developers are constantly updating and fixing things in their :abbr:`VCS (Version Control System)`. It also means you will have better tool support through the VCS as it will provide a diff tool, etc. -To get a read-only checkout of Python's source, you need to checkout the source +To get a read-only checkout of CPython's source, you need to checkout the source code. Python development is tracked using svn_. To get a read-only checkout of the in-development branch of Python (core developers should read XXX for a read-write checkout), run:: @@ -33,11 +39,15 @@ the above URL to the major/minor version (e.g., ``release27-maint`` for Python 2.7). +Do note that CPython will notice that it is being run from a source checkout. +This means that it if you edit Python source code in your checkout the changes +will be picked up by the interpreter for immediate testing. + .. _svn: http://subversion.tigris.org/ -Compiling for debugging -======================= +Compiling (for debugging) +------------------------- Python has two features to aid in developing for it. First, there is a ``Py_DEBUG`` compilation flag which turns on some features in the interpreter -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 20:55:50 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 20:55:50 +0100 Subject: [Python-checkins] devguide: svn config info has moved out of the dev FAQ. Message-ID: brett.cannon pushed 7ee2cb379c30 to devguide: http://hg.python.org/devguide/rev/7ee2cb379c30 changeset: 15:7ee2cb379c30 tag: tip user: Brett Cannon date: Tue Jan 04 11:55:42 2011 -0800 summary: svn config info has moved out of the dev FAQ. files: faq.rst diff --git a/faq.rst b/faq.rst --- a/faq.rst +++ b/faq.rst @@ -163,37 +163,6 @@ through Open. -What configuration settings should I use? -------------------------------------------------------------------------------- - -Make sure the following settings are in your Subversion config file -(``~/.subversion/config`` under UNIX):: - - [miscellany] - enable-auto-props = yes - - [auto-props] - * = svn:eol-style=native - *.c = svn:keywords=Id - *.h = svn:keywords=Id - *.py = svn:keywords=Id - *.txt = svn:keywords=Author Date Id Revision - -The ``[auto-props]`` line specifies the beginning of the section in the config -file. The ``svn:eol-style`` setting tells Subversion to check out files using -the native line endings on your OS. It will also automatically convert line -endings upon committal so that they are consistent across all platforms. The -``svn:keywords`` settings are to automatically substitute ``$keyword$`` -arguments in files that match the pattern. ``*.txt`` has more options so as to -cover all needed keywords for PEPs_. - -The ``[miscellany]`` section and its one option make Subversion apply the -various rules in the ``[auto-props]`` section automatically to all added or -imported files into the respository. - -.. _PEPs: http://www.python.org/dev/peps/ - - What tools do I need to merge between branches? ----------------------------------------------- -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 21:19:48 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 21:19:48 +0100 Subject: [Python-checkins] devguide: Fix up how to make a pydebug build. Message-ID: brett.cannon pushed c61bda44c928 to devguide: http://hg.python.org/devguide/rev/c61bda44c928 changeset: 16:c61bda44c928 user: Brett Cannon date: Tue Jan 04 12:19:07 2011 -0800 summary: Fix up how to make a pydebug build. files: faq.rst setup.rst diff --git a/faq.rst b/faq.rst --- a/faq.rst +++ b/faq.rst @@ -301,63 +301,6 @@ that you change your keys. -Compilation -===================================================================== - -How do I create a debug build of Python? ------------------------------------------ - -A debug build, sometimes called a "pydebug" build, has extra checks and bits of -information to help with developing Python. - -UNIX -''''''''''''''''''''''' - -The basic steps for building Python for development is to configure it and -then compile it. - -Configuration is typically:: - - ./configure --prefix=/dev/null --with-pydebug - -More flags are available to ``configure``, but this is the minimum you should -do. This will give you a debug version of Python along with a safety measure -to prevent you from accidentally installing your development version over -your system install. If you are developing on OS X for Python 2.x and will not -be working with the OS X-specific modules from the standard library, then -consider using the ``--without-toolbox-glue`` flag to faster compilation time. - -Once ``configure`` is done, you can then compile Python.:: - - make -s - -This will build Python with only warnings and errors being printed to -stderr. If you are using a multi-core machine you can use the ``-j`` flag -along with the number of cores your machine has -(e.g. with two cores, you would want ``make -s -j2``) -to compile multiple files at a time. - -Once Python is done building you will then have a working build of Python -that can be run in-place; ``./python`` on most machines, ``./python.exe`` -on OS X. - -Windows -''''''''''''''''''''''''' - -For VC 9, the ``PCbuild`` directory contains the build -files. For older versions of VC, see the ``PC`` directory. For a free -compiler for Windows, go to http://www.microsoft.com/express/ . - -To build from the GUI, load the project files and press F7. Make sure to -choose the Debug build. If you want to build from the command line, run the -``build_env.bat`` file to get a terminal with proper environment variables. -From that terminal, run:: - - build.bat -c Debug - -Once built you will want to set Python as a startup project. F5 will -launch the interpreter as well as double-clicking the binary. - Editors and Tools ===================================================================== diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -79,20 +79,62 @@ Compiling (for debugging) ------------------------- -Python has two features to aid in developing for it. First, there is a -``Py_DEBUG`` compilation flag which turns on some features in the interpreter -which will help with debugging. While this is not the only compilation flag -available (see ``Misc/SpecialBuilds.txt`` in a checkout for all of them), it is -the basic one that you should always use as it tends to catch bugs more often -than running a build of Python without the flag. +CPython provides several compilation flags which help with debugging various +things. While all of the known flags can be in the ``Misc/SpecialBuilds.txt`` +file, the most critical one is the ``Py_DEBUG`` flag. This flag turns on +various extra sanity checks which help catch common issues. You should always +develop under a pydebug build of CPython (only instance of when you shouldn't +is if you are taking performance measurements). -The other feature is support for using code directly from a checkout of Python. -This is handy as it means you do not need to install your build of Python but -can just use the build in-place. It also means that when you edit code in your -checkout you get to see the results without having to install the changed files -as well. -The steps to compile a debug version of Python are specified in the `dev FAQ`_. +UNIX +'''' + +The basic steps for building Python for development is to configure it and +then compile it. + +Configuration is typically:: + + ./configure --prefix=/dev/null --with-pydebug + +More flags are available to ``configure``, but this is the minimum you should +do. This will give you a debug version of Python along with the safety measure +of preventing you from accidentally installing your development version over +your system install. + +Once ``configure`` is done, you can then compile Python.:: + + make -s + +This will build Python with only warnings and errors being printed to +stderr. If you are using a multi-core machine you can use the ``-j`` flag +along with the number of cores your machine has +(e.g., with two cores, you would want ``make -s -j2``) +to speed up. + +Once Python is done building you will then have a working build of Python +that can be run in-place; ``./python`` on most machines, ``./python.exe`` +on OS X. + + +Windows +''''''' + +For :abbr:`VC 9 (Visual C++ 9)`, the ``PCbuild`` directory contains the build +files (for older versions of :abbr:`VC`, see the ``PC`` directory). For a free +compiler for Windows, go to http://www.microsoft.com/express/ . + +To build from the GUI, load the project files and press F7. Make sure to +choose the "Debug" build. + +If you want to build from the command line, run the +``build_env.bat`` file to get a terminal with proper environment variables. +From that terminal, run:: + + build.bat -c Debug + +Once built you will want to set Python as a startup project. F5 will +launch the interpreter as well as double-clicking the binary. Editors and Tools -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 21:19:48 2011 From: python-checkins at python.org (brett.cannon) Date: Tue, 04 Jan 2011 21:19:48 +0100 Subject: [Python-checkins] devguide: Define what pydebug is. Message-ID: brett.cannon pushed c787028dfeab to devguide: http://hg.python.org/devguide/rev/c787028dfeab changeset: 17:c787028dfeab tag: tip user: Brett Cannon date: Tue Jan 04 12:19:41 2011 -0800 summary: Define what pydebug is. files: setup.rst diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -81,7 +81,8 @@ CPython provides several compilation flags which help with debugging various things. While all of the known flags can be in the ``Misc/SpecialBuilds.txt`` -file, the most critical one is the ``Py_DEBUG`` flag. This flag turns on +file, the most critical one is the ``Py_DEBUG`` flag which creates what is +known as a "pydebug" build. This flag turns on various extra sanity checks which help catch common issues. You should always develop under a pydebug build of CPython (only instance of when you shouldn't is if you are taking performance measurements). -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Tue Jan 4 21:57:26 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 4 Jan 2011 21:57:26 +0100 (CET) Subject: [Python-checkins] r87745 - in python/branches/release31-maint/Lib: collections.py test/test_collections.py Message-ID: <20110104205726.3203EEE9CA@mail.python.org> Author: raymond.hettinger Date: Tue Jan 4 21:57:19 2011 New Revision: 87745 Log: Backport r87613 to make OrderedDict subclassing match dict subclassing. Modified: python/branches/release31-maint/Lib/collections.py python/branches/release31-maint/Lib/test/test_collections.py Modified: python/branches/release31-maint/Lib/collections.py ============================================================================== --- python/branches/release31-maint/Lib/collections.py (original) +++ python/branches/release31-maint/Lib/collections.py Tue Jan 4 21:57:19 2011 @@ -21,7 +21,7 @@ class _Link(object): __slots__ = 'prev', 'next', 'key', '__weakref__' -class OrderedDict(dict, MutableMapping): +class OrderedDict(dict): 'Dictionary that remembers insertion order' # An inherited dict maps keys to values. # The inherited dict provides __getitem__, __len__, __contains__, and get. @@ -50,7 +50,7 @@ self.__root = root = _Link() # sentinel node for the doubly linked list root.prev = root.next = root self.__map = {} - self.update(*args, **kwds) + self.__update(*args, **kwds) def clear(self): 'od.clear() -> None. Remove all items from od.' @@ -109,13 +109,29 @@ return (self.__class__, (items,), inst_dict) return self.__class__, (items,) - setdefault = MutableMapping.setdefault - update = MutableMapping.update - pop = MutableMapping.pop + update = __update = MutableMapping.update keys = MutableMapping.keys values = MutableMapping.values items = MutableMapping.items + __marker = object() + + def pop(self, key, default=__marker): + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + def popitem(self, last=True): '''od.popitem() -> (k, v), return and remove a (key, value) pair. Pairs are returned in LIFO order if last is true or FIFO order if false. Modified: python/branches/release31-maint/Lib/test/test_collections.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_collections.py (original) +++ python/branches/release31-maint/Lib/test/test_collections.py Tue Jan 4 21:57:19 2011 @@ -792,6 +792,10 @@ self.assertEqual(list(d.items()), [('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7)]) + def test_abc(self): + self.assertTrue(isinstance(OrderedDict(), MutableMapping)) + self.assertTrue(issubclass(OrderedDict, MutableMapping)) + def test_clear(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) @@ -850,6 +854,17 @@ self.assertEqual(len(od), 0) self.assertEqual(od.pop(k, 12345), 12345) + # make sure pop still works when __missing__ is defined + class Missing(OrderedDict): + def __missing__(self, key): + return 0 + m = Missing(a=1) + self.assertEqual(m.pop('b', 5), 5) + self.assertEqual(m.pop('a', 6), 1) + self.assertEqual(m.pop('a', 6), 6) + with self.assertRaises(KeyError): + m.pop('a') + def test_equality(self): pairs = [('c', 1), ('b', 2), ('a', 3), ('d', 4), ('e', 5), ('f', 6)] shuffle(pairs) @@ -934,6 +949,12 @@ # make sure 'x' is added to the end self.assertEqual(list(od.items())[-1], ('x', 10)) + # make sure setdefault still works when __missing__ is defined + class Missing(OrderedDict): + def __missing__(self, key): + return 0 + self.assertEqual(Missing().setdefault(5, 9), 9) + def test_reinsert(self): # Given insert a, insert b, delete a, re-insert a, # verify that a is now later than b. @@ -945,6 +966,13 @@ self.assertEqual(list(od.items()), [('b', 2), ('a', 1)]) + def test_override_update(self): + # Verify that subclasses can override update() without breaking __init__() + class MyOD(OrderedDict): + def update(self, *args, **kwds): + raise Exception() + items = [('a', 1), ('c', 3), ('b', 2)] + self.assertEqual(list(MyOD(items).items()), items) class GeneralMappingTests(mapping_tests.BasicTestMappingProtocol): type2test = OrderedDict From python-checkins at python.org Tue Jan 4 22:58:10 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 22:58:10 +0100 (CET) Subject: [Python-checkins] r87746 - python/branches/py3k/Modules/pyexpat.c Message-ID: <20110104215810.555A8EE99F@mail.python.org> Author: victor.stinner Date: Tue Jan 4 22:58:10 2011 New Revision: 87746 Log: Issue #9566: explain why (int)len cannot underflow Modified: python/branches/py3k/Modules/pyexpat.c Modified: python/branches/py3k/Modules/pyexpat.c ============================================================================== --- python/branches/py3k/Modules/pyexpat.c (original) +++ python/branches/py3k/Modules/pyexpat.c Tue Jan 4 22:58:10 2011 @@ -839,6 +839,7 @@ finally: Py_XDECREF(arg); Py_XDECREF(str); + /* len <= buf_size <= INT_MAX (see above) */ return (int)len; } From python-checkins at python.org Tue Jan 4 23:00:04 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 4 Jan 2011 23:00:04 +0100 (CET) Subject: [Python-checkins] r87747 - python/branches/py3k/Modules/pyexpat.c Message-ID: <20110104220004.E9E79EE986@mail.python.org> Author: victor.stinner Date: Tue Jan 4 23:00:04 2011 New Revision: 87747 Log: Issue #9566: PyUnicode_FromFormatV() doesn't support %zi, use %zd instead Modified: python/branches/py3k/Modules/pyexpat.c Modified: python/branches/py3k/Modules/pyexpat.c ============================================================================== --- python/branches/py3k/Modules/pyexpat.c (original) +++ python/branches/py3k/Modules/pyexpat.c Tue Jan 4 23:00:04 2011 @@ -831,7 +831,7 @@ if (len > buf_size) { PyErr_Format(PyExc_ValueError, "read() returned too much data: " - "%i bytes requested, %zi returned", + "%i bytes requested, %zd returned", buf_size, len); goto finally; } From python-checkins at python.org Tue Jan 4 23:54:31 2011 From: python-checkins at python.org (antoine.pitrou) Date: Tue, 4 Jan 2011 23:54:31 +0100 (CET) Subject: [Python-checkins] r87748 - python/branches/py3k/Lib/test/test_time.py Message-ID: <20110104225431.14577EE99D@mail.python.org> Author: antoine.pitrou Date: Tue Jan 4 23:54:30 2011 New Revision: 87748 Log: Fix test_time under Windows Modified: python/branches/py3k/Lib/test/test_time.py Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Tue Jan 4 23:54:30 2011 @@ -124,7 +124,7 @@ time.asctime(time.gmtime(self.t)) # Max year is only limited by the size of C int. - sizeof_int = sysconfig.get_config_vars('SIZEOF_INT')[0] + sizeof_int = sysconfig.get_config_var('SIZEOF_INT') or 4 bigyear = (1 << 8 * sizeof_int - 1) - 1 asc = time.asctime((bigyear, 6, 1) + (0,)*6) self.assertEqual(asc[-len(str(bigyear)):], str(bigyear)) From python-checkins at python.org Wed Jan 5 00:05:54 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 00:05:54 +0100 Subject: [Python-checkins] devguide: Add a note about moving over files from Misc. Message-ID: brett.cannon pushed d313f0bc91fd to devguide: http://hg.python.org/devguide/rev/d313f0bc91fd changeset: 19:d313f0bc91fd user: Brett Cannon date: Tue Jan 04 12:57:15 2011 -0800 summary: Add a note about moving over files from Misc. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -53,6 +53,10 @@ tracker for the issue tracker) * `Buildbot builders `_ +.. note:: + XXX move various files out of Misc to here (e.g., README.valgrind, + Porting, SpecialBuilds.txt, maintainers.rst, etc.) + .. _PEP 7: http://www.python.org/dev/peps/pep-0007 .. _PEP 8: http://www.python.org/dev/peps/pep-0008 -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 00:05:54 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 00:05:54 +0100 Subject: [Python-checkins] devguide: Specify -j2 for 'make' by default for those who don't like to read instructions Message-ID: brett.cannon pushed 31ccfd090034 to devguide: http://hg.python.org/devguide/rev/31ccfd090034 changeset: 18:31ccfd090034 user: Brett Cannon date: Tue Jan 04 12:40:48 2011 -0800 summary: Specify -j2 for 'make' by default for those who don't like to read instructions thoroughly. files: setup.rst diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -105,13 +105,12 @@ Once ``configure`` is done, you can then compile Python.:: - make -s + make -s -j2 This will build Python with only warnings and errors being printed to -stderr. If you are using a multi-core machine you can use the ``-j`` flag -along with the number of cores your machine has -(e.g., with two cores, you would want ``make -s -j2``) -to speed up. +stderr and utilize up to 2 CPU cores. If you are using a multi-core machine +with more than 2 cores (or a single-core machine), you can adjust the number +passed into the ``-j`` flag to match the number of cores you have. Once Python is done building you will then have a working build of Python that can be run in-place; ``./python`` on most machines, ``./python.exe`` -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 00:05:54 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 00:05:54 +0100 Subject: [Python-checkins] devguide: Rework editor and tool support discussion. Message-ID: brett.cannon pushed 1bd920ec9a15 to devguide: http://hg.python.org/devguide/rev/1bd920ec9a15 changeset: 20:1bd920ec9a15 user: Brett Cannon date: Tue Jan 04 13:08:06 2011 -0800 summary: Rework editor and tool support discussion. files: faq.rst index.rst setup.rst diff --git a/faq.rst b/faq.rst --- a/faq.rst +++ b/faq.rst @@ -305,22 +305,6 @@ Editors and Tools ===================================================================== -What support is included in Python's source code for Vim? ---------------------------------------------------------- - -Within the ``Misc/Vim`` directory you will find two files to help you when -editing Python code. One is ``python.vim``, which is a generated syntax -highlight file for Python code. This file is updated much more frequently as it -contains syntax highlighting for keywords as they are added to the source tree. -See the top of the file to find out how to use the file. - -The other file for Vim is a vimrc file that supports PEP 7 and 8 coding -standards. All settings are specific to Python and C code and thus will not -affect other settings. There are also some settings which are helpful but -turned off by default at the end of the file if one cares to use non-essential -settings. Once again, see the top of the file to learn how to take advantage of -the file. - What support is included in Python's source code for gdb? ---------------------------------------------------------- @@ -331,14 +315,6 @@ symlink ``~/.gdbinit`` to ``Misc/gdbinit``. -Can I run Valgrind against Python? ----------------------------------- - -Because of how Python uses memory, Valgrind requires setting some suppression -rules to cut down on the false positives (which still occur, suggesting one -typically should know how Python uses memory before running Valgrind against -Python). See ``Misc/README.valgrind`` for more details. - Patches ===================================================================== diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -45,6 +45,8 @@ * `Changing the language `_ +.. _resources: + Resources --------- @@ -53,10 +55,13 @@ tracker for the issue tracker) * `Buildbot builders `_ -.. note:: - XXX move various files out of Misc to here (e.g., README.valgrind, +.. todo:: + move various files out of Misc to here (e.g., README.valgrind, Porting, SpecialBuilds.txt, maintainers.rst, etc.) +.. todo:: + Write a README.gdb for Misc to cover both gdbinit and python-gdb.py + .. _PEP 7: http://www.python.org/dev/peps/pep-0007 .. _PEP 8: http://www.python.org/dev/peps/pep-0008 diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -138,11 +138,16 @@ Editors and Tools -================== +----------------- -Python includes within its source tree some files to help work with various -popular editors and tools. A list of those tools and what is available for them -can be found in the `dev FAQ`_. +Python is used widely enough that practically all code editors have some form +of support for writing Python code. Various coding tools also include Python +support. + +For editors and tools which the core developers have felt some special comment +is needed for coding *in* Python, see the ``Misc`` directory and the +various ``README.*`` files. For tool/editor support geared specifically towards +coding *for* (C)Python itself, see :ref:`resources`. Directory Structure -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 00:05:54 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 00:05:54 +0100 Subject: [Python-checkins] devguide: Fix up the directory explanation. Message-ID: brett.cannon pushed 570608727576 to devguide: http://hg.python.org/devguide/rev/570608727576 changeset: 21:570608727576 user: Brett Cannon date: Tue Jan 04 15:01:52 2011 -0800 summary: Fix up the directory explanation. The 'Getting Set Up' guide is now considered revamped (until I find something it's lacking). files: setup.rst diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -35,7 +35,7 @@ that they are consistent across all platforms. The ``svn:keywords`` settings are to automatically substitute ``$keyword$`` arguments in files that match the pattern. ``*.txt`` has more options so as to cover all needed keywords for -PEPs_. +PEPs. The ``[miscellany]`` section and its one option make svn apply the various rules in the ``[auto-props]`` section automatically to all added or @@ -138,7 +138,7 @@ Editors and Tools ------------------ +================= Python is used widely enough that practically all code editors have some form of support for writing Python code. Various coding tools also include Python @@ -153,35 +153,35 @@ Directory Structure =================== -There are several top-level directories in the Python source tree. Knowing what -which one is meant to hold will help you find where a certain piece of +There are several top-level directories in the CPython source tree. Knowing what +each one is meant to hold will help you find where a certain piece of functionality is implemented. Do realize, though, there are always exceptions to every rule. ``Doc`` - ?????? The official documentation. This is what http://docs.python.org/ uses. The - tools for building the documentation is kept in another repository. To - build the docs, see ``Doc/README.txt``. + ?????? The official documentation. This is what http://docs.python.org/ uses. + To build the docs, see ``Doc/README.txt``. ``Grammar`` - ?????? Contains the EBNF grammar file for Python. + ?????? Contains the :abbr:`EBNF (Extended Backus???Naur Form)` grammar file for + Python. ``Include`` ?????? Contains all interpreter-wide header files. ``Lib`` - ?????? The part of the standard library implemented in pure Python is here. + ?????? The part of the standard library implemented in pure Python. ``Mac`` - ?????? Mac-specific code for things such as using IDLE as an OS X application. + ?????? Mac-specific code (e.g., using IDLE as an OS X application). ``Misc`` ?????? Things that do not belong elsewhere. Typically this is varying kinds of - documentation. + developer-specific documentation. ``Modules`` ?????? The part of the standard library (plus some other code) that is implemented - as extension modules. + in C. ``Objects`` ?????? Code for all built-in types. @@ -198,11 +198,9 @@ here. ``Python`` - ?????? The code that makes Python run. This includes the compiler, eval loop and - various built-in modules. + ?????? The code that makes up the CPython interpreter. This includes the compiler, + eval loop and various built-in modules. ``Tools`` Various tools that are (or have been) used to maintain Python. - -.. _dev FAQ: XXX -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 00:05:54 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 00:05:54 +0100 Subject: [Python-checkins] devguide: Switch on the todo Sphinx extension and list the todo list. Message-ID: brett.cannon pushed 747962c95a84 to devguide: http://hg.python.org/devguide/rev/747962c95a84 changeset: 22:747962c95a84 tag: tip user: Brett Cannon date: Tue Jan 04 15:05:44 2011 -0800 summary: Switch on the todo Sphinx extension and list the todo list. files: conf.py index.rst diff --git a/conf.py b/conf.py --- a/conf.py +++ b/conf.py @@ -25,7 +25,8 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [] +extensions = ['sphinx.ext.todo'] +todo_include_todos = True # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -1,10 +1,13 @@ Python Developer's Guide ======================== -Contents: +.. toctree:: + :hidden: -.. toctree:: - :maxdepth: 2 + setup + + +.. todolist:: Contributing -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 01:19:28 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 5 Jan 2011 01:19:28 +0100 (CET) Subject: [Python-checkins] r87749 - in python/branches/py3k: Lib/test/test_unicode.py Modules/_testcapimodule.c Message-ID: <20110105001928.9D588EE98A@mail.python.org> Author: victor.stinner Date: Wed Jan 5 01:19:28 2011 New Revision: 87749 Log: test_unicode: use ctypes to test PyUnicode_FromFormat() Instead of _testcapi.format_unicode() because it has a limited API: it requires exactly one argument of type unicode. Modified: python/branches/py3k/Lib/test/test_unicode.py python/branches/py3k/Modules/_testcapimodule.c Modified: python/branches/py3k/Lib/test/test_unicode.py ============================================================================== --- python/branches/py3k/Lib/test/test_unicode.py (original) +++ python/branches/py3k/Lib/test/test_unicode.py Wed Jan 5 01:19:28 2011 @@ -1423,22 +1423,36 @@ self.assertEqual("%s" % s, '__str__ overridden') self.assertEqual("{}".format(s), '__str__ overridden') + # Test PyUnicode_FromFormat() def test_from_format(self): - from _testcapi import format_unicode + support.import_module('ctypes') + from ctypes import pythonapi, py_object + if sys.maxunicode == 65535: + name = "PyUnicodeUCS2_FromFormat" + else: + name = "PyUnicodeUCS4_FromFormat" + _PyUnicode_FromFormat = getattr(pythonapi, name) + _PyUnicode_FromFormat.restype = py_object + + def PyUnicode_FromFormat(format, *args): + cargs = tuple( + py_object(arg) if isinstance(arg, str) else arg + for arg in args) + return _PyUnicode_FromFormat(format, *cargs) # ascii format, non-ascii argument - text = format_unicode(b'ascii\x7f=%U', 'unicode\xe9') + text = PyUnicode_FromFormat(b'ascii\x7f=%U', 'unicode\xe9') self.assertEqual(text, 'ascii\x7f=unicode\xe9') - # non-ascii format, ascii argument: ensure that PyUnicode_FromFormat() - # raises an error for a non-ascii format string. + # non-ascii format, ascii argument: ensure that PyUnicode_FromFormatV() + # raises an error self.assertRaisesRegex(ValueError, '^PyUnicode_FromFormatV\(\) expects an ASCII-encoded format ' 'string, got a non-ASCII byte: 0xe9$', - format_unicode, b'unicode\xe9=%s', 'ascii') + PyUnicode_FromFormat, b'unicode\xe9=%s', 'ascii') # other tests - text = format_unicode(b'%%A:%A', 'abc\xe9\uabcd\U0010ffff') + text = PyUnicode_FromFormat(b'%%A:%A', 'abc\xe9\uabcd\U0010ffff') self.assertEqual(text, r"%A:'abc\xe9\uabcd\U0010ffff'") # Test PyUnicode_AsWideChar() Modified: python/branches/py3k/Modules/_testcapimodule.c ============================================================================== --- python/branches/py3k/Modules/_testcapimodule.c (original) +++ python/branches/py3k/Modules/_testcapimodule.c Wed Jan 5 01:19:28 2011 @@ -2246,17 +2246,6 @@ return NULL; } -static PyObject * -format_unicode(PyObject *self, PyObject *args) -{ - const char *format; - PyObject *arg; - if (!PyArg_ParseTuple(args, "yU", &format, &arg)) - return NULL; - return PyUnicode_FromFormat(format, arg); - -} - static PyMethodDef TestMethods[] = { {"raise_exception", raise_exception, METH_VARARGS}, {"raise_memoryerror", (PyCFunction)raise_memoryerror, METH_NOARGS}, @@ -2338,7 +2327,6 @@ {"make_exception_with_doc", (PyCFunction)make_exception_with_doc, METH_VARARGS | METH_KEYWORDS}, {"crash_no_current_thread", (PyCFunction)crash_no_current_thread, METH_NOARGS}, - {"format_unicode", format_unicode, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; From python-checkins at python.org Wed Jan 5 01:27:31 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 01:27:31 +0100 Subject: [Python-checkins] devguide: Move around the buildbot bullet point. Message-ID: brett.cannon pushed 624f80a5aa0f to devguide: http://hg.python.org/devguide/rev/624f80a5aa0f changeset: 23:624f80a5aa0f user: Brett Cannon date: Tue Jan 04 15:21:11 2011 -0800 summary: Move around the buildbot bullet point. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -22,7 +22,6 @@ * Coding style guides * `PEP 7`_ * `PEP 8`_ -* `Using the buildbots `_ * `Submitting a patch `_ * Projects to get familiar with the development process * `Help increase test coverage `_ @@ -31,6 +30,7 @@ * Projects for once you are comfortable * `Helping triage issues `_ * `Fixing issues considered "easy" `_ (and beyond) + * Watching the buildbots_ * `Gaining 'Developer' privileges for the issue tracker `_ * `Triaging issues `_ * `Reviewing patches `_ @@ -56,7 +56,7 @@ * `Issue tracker `_ * `Meta tracker `_ (issue tracker for the issue tracker) -* `Buildbot builders `_ +* Buildbots_ .. todo:: move various files out of Misc to here (e.g., README.valgrind, @@ -66,6 +66,7 @@ Write a README.gdb for Misc to cover both gdbinit and python-gdb.py +.. _buildbots: http://python.org/dev/buildbot/ .. _PEP 7: http://www.python.org/dev/peps/pep-0007 .. _PEP 8: http://www.python.org/dev/peps/pep-0008 -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 01:27:31 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 01:27:31 +0100 Subject: [Python-checkins] devguide: Placeholder for a doc on running the test suite. Message-ID: brett.cannon pushed c7336c6e50b8 to devguide: http://hg.python.org/devguide/rev/c7336c6e50b8 changeset: 25:c7336c6e50b8 user: Brett Cannon date: Tue Jan 04 15:56:59 2011 -0800 summary: Placeholder for a doc on running the test suite. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -24,6 +24,7 @@ * `PEP 7`_ * `PEP 8`_ * :ref:`patch` +* `Running the test suite `_ * Projects to get familiar with the development process * `Help increase test coverage `_ * `Make all unit tests discoverable by unittest `_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 01:27:31 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 01:27:31 +0100 Subject: [Python-checkins] devguide: Prep for a patches doc. Message-ID: brett.cannon pushed acd182640aaf to devguide: http://hg.python.org/devguide/rev/acd182640aaf changeset: 24:acd182640aaf user: Brett Cannon date: Tue Jan 04 15:31:58 2011 -0800 summary: Prep for a patches doc. Also slip in the placeholder for a discussion on communication on Python's development. Also add a todo about moving info PEPs about how to hack on things (e.g., the compiler PEP) into the Resources section. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -5,6 +5,7 @@ :hidden: setup + patch .. todolist:: @@ -22,7 +23,7 @@ * Coding style guides * `PEP 7`_ * `PEP 8`_ -* `Submitting a patch `_ +* :ref:`patch` * Projects to get familiar with the development process * `Help increase test coverage `_ * `Make all unit tests discoverable by unittest `_ @@ -34,6 +35,7 @@ * `Gaining 'Developer' privileges for the issue tracker `_ * `Triaging issues `_ * `Reviewing patches `_ +* `Following Python's development `_ * `Gaining commit privileges `_ * `Committing patches `_ @@ -65,6 +67,10 @@ .. todo:: Write a README.gdb for Misc to cover both gdbinit and python-gdb.py +.. todo:: + Move various informational PEPs out of the PEP index and over here + (.e.g, grammar and compiler guides) + .. _buildbots: http://python.org/dev/buildbot/ .. _PEP 7: http://www.python.org/dev/peps/pep-0007 -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 01:27:31 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 01:27:31 +0100 Subject: [Python-checkins] devguide: Start a patch doc, initially filled in with creation guidelines. Message-ID: brett.cannon pushed e1eb75abf075 to devguide: http://hg.python.org/devguide/rev/e1eb75abf075 changeset: 26:e1eb75abf075 user: Brett Cannon date: Tue Jan 04 16:10:53 2011 -0800 summary: Start a patch doc, initially filled in with creation guidelines. files: patches.rst diff --git a/patches.rst b/patches.rst new file mode 100644 --- /dev/null +++ b/patches.rst @@ -0,0 +1,84 @@ +.. _patch: + +Lifecycle of a Patch +==================== + + +Creating +-------- + +Preparation +''''''''''' + +When creating a patch for submission, there are several things that you should +do to help ensure that your patch is accepted. + +First, make sure to follow Python's style guidelines. For Python code you +should follow `PEP 8`_, and for C code you should follow `PEP 7`_. If you have +one or two discrepencies those can be fixed by the core committer who commits +your patch. But if you have systematic deviations from the style guides your +patch will be put on hold until you fix the formatting issues. + +Second, be aware of backwards-compatibility considerations. While the core +committer who eventually handles your patch will make the final call on whether +something is acceptable, having you think about backwards-compatibility early +will help prevent having your patch rejected on these grounds. Basically just +put yourself in the shoes of someone whose code will be broken by a change to +pre-existing semantics. It is guaranteed that any change made **will** break +someone's code, so you need to have a good reason to make a change as you will +be forcing someone somewhere to update their code (this obviously does not apply +to new semantics). + +Third, make sure you have proper tests to verify your patch works as expected. +Patches will not be accepted without the proper tests! + +Fourth, if you are not already in the ``Misc/ACKS`` file then add your name. If +you have taken the time to diagnose a problem, invent a solution, code it up, +and submit a patch you deserve to be recognized as having contributed to +Python. This also means you need to fill out a `contributor form`_ which +allows the `Python Software Foundation`_ to license your code for use with +Python (you retain the copyright). + + +.. _contributor form: http://www.python.org/psf/contrib/ +.. _PEP 7: http://www.python.org/dev/peps/pep-0007 +.. _PEP 8: http://www.python.org/dev/peps/pep-0008 +.. _Python Software Foundation: http://www.python.org/psf/ + + +Generation +'''''''''' + +Before creating your patch, you should make sure that the entire test suite +runs without failure because of your changes. The only time a patch will be +accepted with failing tests is because the tests fail without the patch applied +and and the patch does not make the pre-existing failures worse. + +To perform a quick sanity check on your patch, you can run:: + + make patchcheck + +This will make sure extraneous whitespace has been removed from your patch, +etc. + +To create your patch, you should generate a unified diff:: + + svn diff > patch.diff + + +Submitting +---------- + +XXX + + +Reviewing +--------- + +XXX + + +Committing/Rejecting +-------------------- + +XXX -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 01:27:31 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 01:27:31 +0100 Subject: [Python-checkins] devguide: Move patches.rst to patch.rst and finish fleshing out. Message-ID: brett.cannon pushed 935450a59738 to devguide: http://hg.python.org/devguide/rev/935450a59738 changeset: 27:935450a59738 tag: tip user: Brett Cannon date: Tue Jan 04 16:27:23 2011 -0800 summary: Move patches.rst to patch.rst and finish fleshing out. files: patch.rst patches.rst diff --git a/patches.rst b/patch.rst rename from patches.rst rename to patch.rst --- a/patches.rst +++ b/patch.rst @@ -15,12 +15,12 @@ First, make sure to follow Python's style guidelines. For Python code you should follow `PEP 8`_, and for C code you should follow `PEP 7`_. If you have -one or two discrepencies those can be fixed by the core committer who commits +one or two discrepencies those can be fixed by the core developer who commits your patch. But if you have systematic deviations from the style guides your patch will be put on hold until you fix the formatting issues. Second, be aware of backwards-compatibility considerations. While the core -committer who eventually handles your patch will make the final call on whether +developer who eventually handles your patch will make the final call on whether something is acceptable, having you think about backwards-compatibility early will help prevent having your patch rejected on these grounds. Basically just put yourself in the shoes of someone whose code will be broken by a change to @@ -69,16 +69,48 @@ Submitting ---------- -XXX +If this is a patch in response to a pre-existing issue on the `issue tracker`_, +attach the patch to the issue. Please provide any details about your patch that +would be relevant to the discussion of the issue or your patch. + +If this is a patch for an unreported issue (assuming you already performed a +search on the issue tracker for a pre-existing issue), create a new issue and +attach your patch. Please fill in as much relevant detail as possible to +prevent patch reviewers from having to delay reviewing your patch because of +lack of information. + + +.. _issue tracker: http://bugs.python.org Reviewing --------- -XXX +To begin with, please be patient! There are many more people submitting patches +than there are people capable of reviewing your patch. To get your patch +reviewed it also requires a reviewer to have the spare time and motivation to +look at your patch (we cannot force anyone to review patches). If your patch has +not received any notice from reviewers (i.e., no comment made) then you may +email python-dev at python.org asking for someone to take a look at your patch. + +When someone does manage to find the time to look at your patch they will most +likely make a comment about how it can be improved (don't worry, even core +developers on Python have their patches sent back to them for changes). The +status of the issue will be made "pending" and will be automatically closed in +two weeks if you do not address the issues raised. This is to prevent your +patch sitting their open forever if you happen to lose interest. Committing/Rejecting -------------------- -XXX +Once your patch has reached an acceptable state (and thus considered +"accepted"), it will either be committed or rejected. If it is rejected, please +do not take it personally! Your work is still appreciated regardless of whether +your patch is committed. Balancing what *does* and *`does not* go into Python +is tricky and we simply cannot accept everyone's contributions. + +But if your patch is committed it will then go into Python's VCS to be released +with the next major release of Python. It may also be backported to older +versions of Python as a bugfix if the core developer doing the commit believes +it is warranted. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 02:39:32 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 5 Jan 2011 02:39:32 +0100 (CET) Subject: [Python-checkins] r87750 - in python/branches/py3k: Doc/library/email.header.rst Lib/email/header.py Lib/email/test/test_email.py Misc/NEWS Message-ID: <20110105013932.87730EE984@mail.python.org> Author: r.david.murray Date: Wed Jan 5 02:39:32 2011 New Revision: 87750 Log: #10790: make append work when output codec is different from input codec There's still a bug here (the encode call shouldn't use the 'errors' paramter), but I'll fix that later. Modified: python/branches/py3k/Doc/library/email.header.rst python/branches/py3k/Lib/email/header.py python/branches/py3k/Lib/email/test/test_email.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Doc/library/email.header.rst ============================================================================== --- python/branches/py3k/Doc/library/email.header.rst (original) +++ python/branches/py3k/Doc/library/email.header.rst Wed Jan 5 02:39:32 2011 @@ -94,14 +94,15 @@ decoded with that character set. If *s* is an instance of :class:`str`, then *charset* is a hint specifying - the character set of the characters in the string. In this case, when - producing an :rfc:`2822`\ -compliant header using :rfc:`2047` rules, the - Unicode string will be encoded using the following charsets in order: - ``us-ascii``, the *charset* hint, ``utf-8``. The first character set to - not provoke a :exc:`UnicodeError` is used. + the character set of the characters in the string. - Optional *errors* is passed through to any :func:`encode` or - :func:`ustr.encode` call, and defaults to "strict". + In either case, when producing an :rfc:`2822`\ -compliant header using + :rfc:`2047` rules, the string will be encoded using the output codec of + the charset. If the string cannot be encoded using the output codec, a + UnicodeError will be raised. + + Optional *errors* is passed as the errors argument to the decode call + if *s* is a byte string. .. method:: encode(splitchars=';, \\t', maxlinelen=None, linesep='\\n') Modified: python/branches/py3k/Lib/email/header.py ============================================================================== --- python/branches/py3k/Lib/email/header.py (original) +++ python/branches/py3k/Lib/email/header.py Wed Jan 5 02:39:32 2011 @@ -245,32 +245,26 @@ that byte string, and a UnicodeError will be raised if the string cannot be decoded with that charset. If s is a Unicode string, then charset is a hint specifying the character set of the characters in - the string. In this case, when producing an RFC 2822 compliant header - using RFC 2047 rules, the Unicode string will be encoded using the - following charsets in order: us-ascii, the charset hint, utf-8. The - first character set not to provoke a UnicodeError is used. + the string. In either case, when producing an RFC 2822 compliant + header using RFC 2047 rules, the string will be encoded using the + output codec of the charset. If the string cannot be encoded to the + output codec, a UnicodeError will be raised. - Optional `errors' is passed as the third argument to any unicode() or - ustr.encode() call. + Optional `errors' is passed as the errors argument to the decode + call if s is a byte string. """ if charset is None: charset = self._charset elif not isinstance(charset, Charset): charset = Charset(charset) - if isinstance(s, str): - # Convert the string from the input character set to the output - # character set and store the resulting bytes and the charset for - # composition later. + if not isinstance(s, str): input_charset = charset.input_codec or 'us-ascii' - input_bytes = s.encode(input_charset, errors) - else: - # We already have the bytes we will store internally. - input_bytes = s + s = s.decode(input_charset, errors) # Ensure that the bytes we're storing can be decoded to the output # character set, otherwise an early error is thrown. output_charset = charset.output_codec or 'us-ascii' - output_string = input_bytes.decode(output_charset, errors) - self._chunks.append((output_string, charset)) + s.encode(output_charset, errors) + self._chunks.append((s, charset)) def encode(self, splitchars=';, \t', maxlinelen=None, linesep='\n'): """Encode a message header into an RFC-compliant format. Modified: python/branches/py3k/Lib/email/test/test_email.py ============================================================================== --- python/branches/py3k/Lib/email/test/test_email.py (original) +++ python/branches/py3k/Lib/email/test/test_email.py Wed Jan 5 02:39:32 2011 @@ -3620,6 +3620,10 @@ s = 'Subject: =?EUC-KR?B?CSixpLDtKSC/7Liuvsax4iC6uLmwMcijIKHaILzSwd/H0SC8+LCjwLsgv7W/+Mj3I ?=' raises(errors.HeaderParseError, decode_header, s) + def test_shift_jis_charset(self): + h = Header('?', charset='shift_jis') + self.assertEqual(h.encode(), '=?iso-2022-jp?b?GyRCSjgbKEI=?=') + # Test RFC 2231 header parameters (en/de)coding Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Wed Jan 5 02:39:32 2011 @@ -30,6 +30,9 @@ Library ------- +- Issue #10790: email.header.Header.append's charset logic now works correctly + for charsets whose output codec is different from its input codec. + - Issue #10819: SocketIO.name property returns -1 when its closed, instead of raising a ValueError, to fix repr(). From python-checkins at python.org Wed Jan 5 02:47:38 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 5 Jan 2011 02:47:38 +0100 (CET) Subject: [Python-checkins] r87751 - in python/branches/release31-maint: Doc/library/email.header.rst Lib/email/header.py Lib/email/test/test_email.py Misc/NEWS Message-ID: <20110105014738.4B05FEE9B7@mail.python.org> Author: r.david.murray Date: Wed Jan 5 02:47:38 2011 New Revision: 87751 Log: Merged revisions 87750 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87750 | r.david.murray | 2011-01-04 20:39:32 -0500 (Tue, 04 Jan 2011) | 5 lines #10790: make append work when output codec is different from input codec There's still a bug here (the encode call shouldn't use the 'errors' paramter), but I'll fix that later. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Doc/library/email.header.rst python/branches/release31-maint/Lib/email/header.py python/branches/release31-maint/Lib/email/test/test_email.py python/branches/release31-maint/Misc/NEWS Modified: python/branches/release31-maint/Doc/library/email.header.rst ============================================================================== --- python/branches/release31-maint/Doc/library/email.header.rst (original) +++ python/branches/release31-maint/Doc/library/email.header.rst Wed Jan 5 02:47:38 2011 @@ -94,15 +94,15 @@ decoded with that character set. If *s* is an instance of :class:`str`, then *charset* is a hint specifying - the character set of the characters in the string. In this case, when - producing an :rfc:`2822`\ -compliant header using :rfc:`2047` rules, the - Unicode string will be encoded using the following charsets in order: - ``us-ascii``, the *charset* hint, ``utf-8``. The first character set to - not provoke a :exc:`UnicodeError` is used. + the character set of the characters in the string. - Optional *errors* is passed through to any :func:`encode` or - :func:`ustr.encode` call, and defaults to "strict". + In either case, when producing an :rfc:`2822`\ -compliant header using + :rfc:`2047` rules, the string will be encoded using the output codec of + the charset. If the string cannot be encoded using the output codec, a + UnicodeError will be raised. + Optional *errors* is passed as the errors argument to the decode call + if *s* is a byte string. .. method:: encode(splitchars=';, \\t', maxlinelen=None) Modified: python/branches/release31-maint/Lib/email/header.py ============================================================================== --- python/branches/release31-maint/Lib/email/header.py (original) +++ python/branches/release31-maint/Lib/email/header.py Wed Jan 5 02:47:38 2011 @@ -245,32 +245,26 @@ that byte string, and a UnicodeError will be raised if the string cannot be decoded with that charset. If s is a Unicode string, then charset is a hint specifying the character set of the characters in - the string. In this case, when producing an RFC 2822 compliant header - using RFC 2047 rules, the Unicode string will be encoded using the - following charsets in order: us-ascii, the charset hint, utf-8. The - first character set not to provoke a UnicodeError is used. + the string. In either case, when producing an RFC 2822 compliant + header using RFC 2047 rules, the string will be encoded using the + output codec of the charset. If the string cannot be encoded to the + output codec, a UnicodeError will be raised. - Optional `errors' is passed as the third argument to any unicode() or - ustr.encode() call. + Optional `errors' is passed as the errors argument to the decode + call if s is a byte string. """ if charset is None: charset = self._charset elif not isinstance(charset, Charset): charset = Charset(charset) - if isinstance(s, str): - # Convert the string from the input character set to the output - # character set and store the resulting bytes and the charset for - # composition later. + if not isinstance(s, str): input_charset = charset.input_codec or 'us-ascii' - input_bytes = s.encode(input_charset, errors) - else: - # We already have the bytes we will store internally. - input_bytes = s + s = s.decode(input_charset, errors) # Ensure that the bytes we're storing can be decoded to the output # character set, otherwise an early error is thrown. output_charset = charset.output_codec or 'us-ascii' - output_string = input_bytes.decode(output_charset, errors) - self._chunks.append((output_string, charset)) + s.encode(output_charset, errors) + self._chunks.append((s, charset)) def encode(self, splitchars=';, \t', maxlinelen=None): """Encode a message header into an RFC-compliant format. Modified: python/branches/release31-maint/Lib/email/test/test_email.py ============================================================================== --- python/branches/release31-maint/Lib/email/test/test_email.py (original) +++ python/branches/release31-maint/Lib/email/test/test_email.py Wed Jan 5 02:47:38 2011 @@ -3255,6 +3255,10 @@ s = 'Subject: =?EUC-KR?B?CSixpLDtKSC/7Liuvsax4iC6uLmwMcijIKHaILzSwd/H0SC8+LCjwLsgv7W/+Mj3I ?=' raises(errors.HeaderParseError, decode_header, s) + def test_shift_jis_charset(self): + h = Header('?', charset='shift_jis') + self.assertEqual(h.encode(), '=?iso-2022-jp?b?GyRCSjgbKEI=?=') + # Test RFC 2231 header parameters (en/de)coding Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Wed Jan 5 02:47:38 2011 @@ -27,6 +27,9 @@ Library ------- +- Issue #10790: email.header.Header.append's charset logic now works correctly + for charsets whose output codec is different from its input codec. + - Issue #6643: Reinitialize locks held within the threading module after fork to avoid a potential rare deadlock or crash on some platforms. From python-checkins at python.org Wed Jan 5 02:50:00 2011 From: python-checkins at python.org (r.david.murray) Date: Wed, 5 Jan 2011 02:50:00 +0100 (CET) Subject: [Python-checkins] r87752 - python/branches/release27-maint Message-ID: <20110105015000.D8B85EE9A6@mail.python.org> Author: r.david.murray Date: Wed Jan 5 02:50:00 2011 New Revision: 87752 Log: Blocked revisions 87750 via svnmerge ........ r87750 | r.david.murray | 2011-01-04 20:39:32 -0500 (Tue, 04 Jan 2011) | 5 lines #10790: make append work when output codec is different from input codec There's still a bug here (the encode call shouldn't use the 'errors' paramter), but I'll fix that later. ........ Modified: python/branches/release27-maint/ (props changed) From ncoghlan at gmail.com Wed Jan 5 03:13:31 2011 From: ncoghlan at gmail.com (Nick Coghlan) Date: Wed, 5 Jan 2011 12:13:31 +1000 Subject: [Python-checkins] devguide: Strip out all generic svn instructions from the FAQ. It's not only In-Reply-To: References: Message-ID: On Wed, Jan 5, 2011 at 5:55 AM, brett.cannon wrote: > brett.cannon pushed 72a286c3452d to devguide: > > http://hg.python.org/devguide/rev/72a286c3452d > changeset: ? 13:72a286c3452d > user: ? ? ? ?Brett Cannon > date: ? ? ? ?Tue Jan 04 11:48:38 2011 -0800 > summary: > ?Strip out all generic svn instructions from the FAQ. It's not only > silly to duplicate instructions that can be found all over the > internet that are maintained by the creators of the tools under > discussion, but it's a maintenance burden that is unneeded. Your call as the author, but please reconsider this one. I've found it *hugely* convenient over the years to have these task oriented answers in the FAQ. The problem with the answers all over the internet is that I (or someone new to our source control tool) may not know enough to ask the right question, and hence those answers may as well not exist. Even if these FAQ answers don't always provide everything needed, they usually provide enough information to let me search for the full answers. Cheers, Nick. -- Nick Coghlan?? |?? ncoghlan at gmail.com?? |?? Brisbane, Australia From python-checkins at python.org Wed Jan 5 04:33:26 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 5 Jan 2011 04:33:26 +0100 (CET) Subject: [Python-checkins] r87753 - in python/branches/py3k: Objects/codeobject.c Parser/tokenizer.c Message-ID: <20110105033326.AAAAFEE987@mail.python.org> Author: victor.stinner Date: Wed Jan 5 04:33:26 2011 New Revision: 87753 Log: Remove arbitrary string length limits PyUnicode_FromFormat() and PyErr_Format() allocates a buffer of the needed size, it is no more a fixed-buffer of 500 bytes. Modified: python/branches/py3k/Objects/codeobject.c python/branches/py3k/Parser/tokenizer.c Modified: python/branches/py3k/Objects/codeobject.c ============================================================================== --- python/branches/py3k/Objects/codeobject.c (original) +++ python/branches/py3k/Objects/codeobject.c Wed Jan 5 04:33:26 2011 @@ -347,11 +347,11 @@ lineno = -1; if (co->co_filename && PyUnicode_Check(co->co_filename)) { return PyUnicode_FromFormat( - "", + "", co->co_name, co, co->co_filename, lineno); } else { return PyUnicode_FromFormat( - "", + "", co->co_name, co, lineno); } } Modified: python/branches/py3k/Parser/tokenizer.c ============================================================================== --- python/branches/py3k/Parser/tokenizer.c (original) +++ python/branches/py3k/Parser/tokenizer.c Wed Jan 5 04:33:26 2011 @@ -590,7 +590,7 @@ if (filename != NULL) { PyErr_Format(PyExc_SyntaxError, "Non-UTF-8 code starting with '\\x%.2x' " - "in file %.200U on line %i, " + "in file %U on line %i, " "but no encoding declared; " "see http://python.org/dev/peps/pep-0263/ for details", badchar, filename, tok->lineno + 1); From python-checkins at python.org Wed Jan 5 04:33:28 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 5 Jan 2011 04:33:28 +0100 (CET) Subject: [Python-checkins] r87754 - python/branches/py3k/Lib/test/test_bytes.py Message-ID: <20110105033328.823C4EE996@mail.python.org> Author: victor.stinner Date: Wed Jan 5 04:33:28 2011 New Revision: 87754 Log: test_bytes: test PyBytes_FromFormat() using ctypes Modified: python/branches/py3k/Lib/test/test_bytes.py Modified: python/branches/py3k/Lib/test/test_bytes.py ============================================================================== --- python/branches/py3k/Lib/test/test_bytes.py (original) +++ python/branches/py3k/Lib/test/test_bytes.py Wed Jan 5 04:33:28 2011 @@ -497,6 +497,27 @@ return None self.assertRaises(TypeError, bytes, A()) + # Test PyBytes_FromFormat() + def test_from_format(self): + test.support.import_module('ctypes') + from ctypes import pythonapi, py_object, c_int, c_char_p + PyBytes_FromFormat = pythonapi.PyBytes_FromFormat + PyBytes_FromFormat.restype = py_object + + self.assertEqual(PyBytes_FromFormat(b'format'), + b'format') + + self.assertEqual(PyBytes_FromFormat(b'%'), b'%') + self.assertEqual(PyBytes_FromFormat(b'%%'), b'%') + self.assertEqual(PyBytes_FromFormat(b'%%s'), b'%s') + self.assertEqual(PyBytes_FromFormat(b'[%%]'), b'[%]') + self.assertEqual(PyBytes_FromFormat(b'%%%c', c_int(ord('_'))), b'%_') + + self.assertEqual(PyBytes_FromFormat(b'c:%c', c_int(255)), + b'c:\xff') + self.assertEqual(PyBytes_FromFormat(b's:%s', c_char_p(b'cstr')), + b's:cstr') + class ByteArrayTest(BaseBytesTest): type2test = bytearray From python-checkins at python.org Wed Jan 5 04:54:25 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 5 Jan 2011 04:54:25 +0100 (CET) Subject: [Python-checkins] r87755 - in python/branches/py3k: Lib/test/test_atexit.py Misc/NEWS Modules/atexitmodule.c Message-ID: <20110105035425.459CDF2F9@mail.python.org> Author: victor.stinner Date: Wed Jan 5 04:54:25 2011 New Revision: 87755 Log: Issue #10756: atexit normalizes the exception before displaying it. Modified: python/branches/py3k/Lib/test/test_atexit.py python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/atexitmodule.c Modified: python/branches/py3k/Lib/test/test_atexit.py ============================================================================== --- python/branches/py3k/Lib/test/test_atexit.py (original) +++ python/branches/py3k/Lib/test/test_atexit.py Wed Jan 5 04:54:25 2011 @@ -65,6 +65,14 @@ self.assertRaises(TypeError, atexit._run_exitfuncs) + def test_raise_unnormalized(self): + # Issue #10756: Make sure that an unnormalized exception is + # handled properly + atexit.register(lambda: 1 / 0) + + self.assertRaises(ZeroDivisionError, atexit._run_exitfuncs) + self.assertIn("ZeroDivisionError", self.stream.getvalue()) + def test_stress(self): a = [0] def inc(): Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Wed Jan 5 04:54:25 2011 @@ -30,6 +30,8 @@ Library ------- +- Issue #10756: atexit normalizes the exception before displaying it. + - Issue #10790: email.header.Header.append's charset logic now works correctly for charsets whose output codec is different from its input codec. Modified: python/branches/py3k/Modules/atexitmodule.c ============================================================================== --- python/branches/py3k/Modules/atexitmodule.c (original) +++ python/branches/py3k/Modules/atexitmodule.c Wed Jan 5 04:54:25 2011 @@ -72,6 +72,7 @@ PyErr_Fetch(&exc_type, &exc_value, &exc_tb); if (!PyErr_ExceptionMatches(PyExc_SystemExit)) { PySys_WriteStderr("Error in atexit._run_exitfuncs:\n"); + PyErr_NormalizeException(&exc_type, &exc_value, &exc_tb); PyErr_Display(exc_type, exc_value, exc_tb); } } From python-checkins at python.org Wed Jan 5 04:54:26 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 5 Jan 2011 04:54:26 +0100 (CET) Subject: [Python-checkins] r87756 - python/branches/py3k/Lib/test/regrtest.py Message-ID: <20110105035426.E0B04EE98F@mail.python.org> Author: victor.stinner Date: Wed Jan 5 04:54:26 2011 New Revision: 87756 Log: regrtest: close the new stdout and restore the original stdout at exit Fix a ResourceWarning(unclosed file). Modified: python/branches/py3k/Lib/test/regrtest.py Modified: python/branches/py3k/Lib/test/regrtest.py ============================================================================== --- python/branches/py3k/Lib/test/regrtest.py (original) +++ python/branches/py3k/Lib/test/regrtest.py Wed Jan 5 04:54:26 2011 @@ -743,10 +743,19 @@ if os.name == "nt": # Replace sys.stdout breaks the stdout newlines on Windows: issue #8533 return + + import atexit + stdout = sys.stdout sys.stdout = open(stdout.fileno(), 'w', encoding=stdout.encoding, - errors="backslashreplace") + errors="backslashreplace", + closefd=False) + + def restore_stdout(): + sys.stdout.close() + sys.stdout = stdout + atexit.register(restore_stdout) def runtest(test, verbose, quiet, huntrleaks=False, debug=False, use_resources=None): From python-checkins at python.org Wed Jan 5 04:54:28 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 5 Jan 2011 04:54:28 +0100 (CET) Subject: [Python-checkins] r87757 - python/branches/py3k/Lib/test/test_threading.py Message-ID: <20110105035428.6586AEE99F@mail.python.org> Author: victor.stinner Date: Wed Jan 5 04:54:28 2011 New Revision: 87757 Log: test_threading: use Popen.communicate() instead of .wait() Popen.communicate() avoids deadlocks and close the pipes when done. This commit fixes a ResourceWarning(unclosed pipe). Modified: python/branches/py3k/Lib/test/test_threading.py Modified: python/branches/py3k/Lib/test/test_threading.py ============================================================================== --- python/branches/py3k/Lib/test/test_threading.py (original) +++ python/branches/py3k/Lib/test/test_threading.py Wed Jan 5 04:54:28 2011 @@ -512,9 +512,9 @@ def assertScriptHasOutput(self, script, expected_output): p = subprocess.Popen([sys.executable, "-c", script], stdout=subprocess.PIPE) - rc = p.wait() - data = p.stdout.read().decode().replace('\r', '') - self.assertEqual(rc, 0, "Unexpected error") + stdout, stderr = p.communicate() + data = stdout.decode().replace('\r', '') + self.assertEqual(p.returncode, 0, "Unexpected error") self.assertEqual(data, expected_output) @unittest.skipUnless(hasattr(os, 'fork'), "needs os.fork()") From python-checkins at python.org Wed Jan 5 04:56:23 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 5 Jan 2011 04:56:23 +0100 (CET) Subject: [Python-checkins] r87758 - in python/branches/py3k/Misc: ACKS NEWS Message-ID: <20110105035623.2B1B1EE994@mail.python.org> Author: victor.stinner Date: Wed Jan 5 04:56:22 2011 New Revision: 87758 Log: Issue #10756: add the author, Andreas St?hrk Modified: python/branches/py3k/Misc/ACKS python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Misc/ACKS ============================================================================== --- python/branches/py3k/Misc/ACKS (original) +++ python/branches/py3k/Misc/ACKS Wed Jan 5 04:56:22 2011 @@ -811,6 +811,7 @@ Ken Stox Dan Stromberg Daniel Stutzbach +Andreas St?hrk Pal Subbiah Nathan Sullivan Mark Summerfield Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Wed Jan 5 04:56:22 2011 @@ -30,7 +30,8 @@ Library ------- -- Issue #10756: atexit normalizes the exception before displaying it. +- Issue #10756: atexit normalizes the exception before displaying it. Patch by + Andreas St?hrk. - Issue #10790: email.header.Header.append's charset logic now works correctly for charsets whose output codec is different from its input codec. From python-checkins at python.org Wed Jan 5 04:58:55 2011 From: python-checkins at python.org (victor.stinner) Date: Wed, 5 Jan 2011 04:58:55 +0100 (CET) Subject: [Python-checkins] r87759 - python/branches/py3k/Lib/test/test_time.py Message-ID: <20110105035855.174A0EE991@mail.python.org> Author: victor.stinner Date: Wed Jan 5 04:58:54 2011 New Revision: 87759 Log: test_time: assertEquals => assertEqual Modified: python/branches/py3k/Lib/test/test_time.py Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Wed Jan 5 04:58:54 2011 @@ -147,7 +147,7 @@ # on some platforms. pass else: - self.assertEquals(time.ctime(bigval)[-5:], '10000') + self.assertEqual(time.ctime(bigval)[-5:], '10000') @unittest.skipIf(not hasattr(time, "tzset"), "time module has no attribute tzset") From solipsis at pitrou.net Wed Jan 5 05:05:45 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Wed, 05 Jan 2011 05:05:45 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r87750): sum=0 Message-ID: py3k results for svn r87750 (hg cset 8ef1f5e86db2) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflogz7WOtE', '-x'] From python-checkins at python.org Wed Jan 5 11:59:48 2011 From: python-checkins at python.org (georg.brandl) Date: Wed, 5 Jan 2011 11:59:48 +0100 (CET) Subject: [Python-checkins] r87760 - python/branches/py3k/Doc/tools/sphinxext/indexcontent.html Message-ID: <20110105105948.AF216EE98F@mail.python.org> Author: georg.brandl Date: Wed Jan 5 11:59:48 2011 New Revision: 87760 Log: Fix duplicate end tag. Modified: python/branches/py3k/Doc/tools/sphinxext/indexcontent.html Modified: python/branches/py3k/Doc/tools/sphinxext/indexcontent.html ============================================================================== --- python/branches/py3k/Doc/tools/sphinxext/indexcontent.html (original) +++ python/branches/py3k/Doc/tools/sphinxext/indexcontent.html Wed Jan 5 11:59:48 2011 @@ -4,7 +4,7 @@ + + + +
+ or all "What's new" documents since 2.0

Download (ca. 2 MB) Download (ca. 1.5 MB)
EPUBDownload (ca. 3.5 MB)Download (ca. 3.5 MB)
From python-checkins at python.org Wed Jan 5 19:37:22 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 5 Jan 2011 19:37:22 +0100 (CET) Subject: [Python-checkins] r87762 - python/branches/py3k/Doc/library/pyexpat.rst Message-ID: <20110105183722.72E3AEE9F9@mail.python.org> Author: antoine.pitrou Date: Wed Jan 5 19:37:22 2011 New Revision: 87762 Log: Issue #5485: Add doc for expat.xmlparser.SetParamEntityParsing. Modified: python/branches/py3k/Doc/library/pyexpat.rst Modified: python/branches/py3k/Doc/library/pyexpat.rst ============================================================================== --- python/branches/py3k/Doc/library/pyexpat.rst (original) +++ python/branches/py3k/Doc/library/pyexpat.rst Wed Jan 5 19:37:22 2011 @@ -153,6 +153,13 @@ :attr:`ordered_attributes` and :attr:`specified_attributes` set to the values of this parser. +.. method:: xmlparser.SetParamEntityParsing(flag) + + Control parsing of parameter entities (including the external DTD subset). + Possible *flag* values are :const:`XML_PARAM_ENTITY_PARSING_NEVER`, + :const:`XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE` and + :const:`XML_PARAM_ENTITY_PARSING_ALWAYS`. Return true if setting the flag + was successful. .. method:: xmlparser.UseForeignDTD([flag]) From python-checkins at python.org Wed Jan 5 19:41:10 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 5 Jan 2011 19:41:10 +0100 (CET) Subject: [Python-checkins] r87763 - in python/branches/release31-maint: Doc/library/pyexpat.rst Message-ID: <20110105184110.29887EE9AF@mail.python.org> Author: antoine.pitrou Date: Wed Jan 5 19:41:10 2011 New Revision: 87763 Log: Merged revisions 87762 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87762 | antoine.pitrou | 2011-01-05 19:37:22 +0100 (mer., 05 janv. 2011) | 3 lines Issue #5485: Add doc for expat.xmlparser.SetParamEntityParsing. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Doc/library/pyexpat.rst Modified: python/branches/release31-maint/Doc/library/pyexpat.rst ============================================================================== --- python/branches/release31-maint/Doc/library/pyexpat.rst (original) +++ python/branches/release31-maint/Doc/library/pyexpat.rst Wed Jan 5 19:41:10 2011 @@ -154,6 +154,13 @@ :attr:`ordered_attributes` and :attr:`specified_attributes` set to the values of this parser. +.. method:: xmlparser.SetParamEntityParsing(flag) + + Control parsing of parameter entities (including the external DTD subset). + Possible *flag* values are :const:`XML_PARAM_ENTITY_PARSING_NEVER`, + :const:`XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE` and + :const:`XML_PARAM_ENTITY_PARSING_ALWAYS`. Return true if setting the flag + was successful. .. method:: xmlparser.UseForeignDTD([flag]) From python-checkins at python.org Wed Jan 5 19:41:13 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 5 Jan 2011 19:41:13 +0100 (CET) Subject: [Python-checkins] r87764 - in python/branches/release27-maint: Doc/library/pyexpat.rst Message-ID: <20110105184113.5F48AEE9CD@mail.python.org> Author: antoine.pitrou Date: Wed Jan 5 19:41:13 2011 New Revision: 87764 Log: Merged revisions 87762 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87762 | antoine.pitrou | 2011-01-05 19:37:22 +0100 (mer., 05 janv. 2011) | 3 lines Issue #5485: Add doc for expat.xmlparser.SetParamEntityParsing. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Doc/library/pyexpat.rst Modified: python/branches/release27-maint/Doc/library/pyexpat.rst ============================================================================== --- python/branches/release27-maint/Doc/library/pyexpat.rst (original) +++ python/branches/release27-maint/Doc/library/pyexpat.rst Wed Jan 5 19:41:13 2011 @@ -157,6 +157,13 @@ :attr:`ordered_attributes`, :attr:`returns_unicode` and :attr:`specified_attributes` set to the values of this parser. +.. method:: xmlparser.SetParamEntityParsing(flag) + + Control parsing of parameter entities (including the external DTD subset). + Possible *flag* values are :const:`XML_PARAM_ENTITY_PARSING_NEVER`, + :const:`XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE` and + :const:`XML_PARAM_ENTITY_PARSING_ALWAYS`. Return true if setting the flag + was successful. .. method:: xmlparser.UseForeignDTD([flag]) From python-checkins at python.org Wed Jan 5 19:44:14 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 5 Jan 2011 19:44:14 +0100 (CET) Subject: [Python-checkins] r87765 - in python/branches/py3k: Lib/test/test_pyexpat.py Misc/NEWS Message-ID: <20110105184414.75E05EE9EF@mail.python.org> Author: antoine.pitrou Date: Wed Jan 5 19:44:14 2011 New Revision: 87765 Log: Issue #5485: Add tests for the UseForeignDTD method of expat parser objects. Patch by Jean-Paul Calderone and Sandro Tosi. Modified: python/branches/py3k/Lib/test/test_pyexpat.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/test/test_pyexpat.py ============================================================================== --- python/branches/py3k/Lib/test/test_pyexpat.py (original) +++ python/branches/py3k/Lib/test/test_pyexpat.py Wed Jan 5 19:44:14 2011 @@ -155,6 +155,14 @@ 'ElementDeclHandler', 'AttlistDeclHandler', 'SkippedEntityHandler', ] + def _hookup_callbacks(self, parser, handler): + """ + Set each of the callbacks defined on handler and named in + self.handler_names on the given parser. + """ + for name in self.handler_names: + setattr(parser, name, getattr(handler, name)) + def _verify_parse_output(self, operations): expected_operations = [ ('XML declaration', ('1.0', 'iso-8859-1', 0)), @@ -196,8 +204,7 @@ # Try the parse again, this time producing Unicode output out = self.Outputter() parser = expat.ParserCreate(namespace_separator='!') - for name in self.handler_names: - setattr(parser, name, getattr(out, name)) + self._hookup_callbacks(parser, out) parser.Parse(data, 1) @@ -210,8 +217,7 @@ # Try parsing a file out = self.Outputter() parser = expat.ParserCreate(namespace_separator='!') - for name in self.handler_names: - setattr(parser, name, getattr(out, name)) + self._hookup_callbacks(parser, out) file = BytesIO(data) parser.ParseFile(file) @@ -613,6 +619,48 @@ errors.codes[errors.XML_ERROR_UNCLOSED_TOKEN]) +class ForeignDTDTests(unittest.TestCase): + """ + Tests for the UseForeignDTD method of expat parser objects. + """ + def test_use_foreign_dtd(self): + """ + If UseForeignDTD is passed True and a document without an external + entity reference is parsed, ExternalEntityRefHandler is first called + with None for the public and system ids. + """ + handler_call_args = [] + def resolve_entity(context, base, system_id, public_id): + handler_call_args.append((public_id, system_id)) + return 1 + + parser = expat.ParserCreate() + parser.UseForeignDTD(True) + parser.SetParamEntityParsing(expat.XML_PARAM_ENTITY_PARSING_ALWAYS) + parser.ExternalEntityRefHandler = resolve_entity + parser.Parse("") + self.assertEqual(handler_call_args, [(None, None)]) + + def test_ignore_use_foreign_dtd(self): + """ + If UseForeignDTD is passed True and a document with an external + entity reference is parsed, ExternalEntityRefHandler is called with + the public and system ids from the document. + """ + handler_call_args = [] + def resolve_entity(context, base, system_id, public_id): + handler_call_args.append((public_id, system_id)) + return 1 + + parser = expat.ParserCreate() + parser.UseForeignDTD(True) + parser.SetParamEntityParsing(expat.XML_PARAM_ENTITY_PARSING_ALWAYS) + parser.ExternalEntityRefHandler = resolve_entity + parser.Parse( + "") + self.assertEqual(handler_call_args, [("bar", "baz")]) + + def test_main(): run_unittest(SetAttributeTest, ParseTest, @@ -624,7 +672,8 @@ sf1296433Test, ChardataBufferTest, MalformedInputTest, - ErrorMessageTest) + ErrorMessageTest, + ForeignDTDTests) if __name__ == "__main__": test_main() Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Wed Jan 5 19:44:14 2011 @@ -153,6 +153,9 @@ Tests ----- +- Issue #5485: Add tests for the UseForeignDTD method of expat parser objects. + Patch by Jean-Paul Calderone and Sandro Tosi. + - Issue #6293: Have regrtest.py echo back sys.flags. This is done by default in whole runs and enabled selectively using ``--header`` when running an explicit list of tests. Original patch by Collin Winter. From python-checkins at python.org Wed Jan 5 21:08:25 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 5 Jan 2011 21:08:25 +0100 (CET) Subject: [Python-checkins] r87766 - python/branches/py3k/Python/sysmodule.c Message-ID: <20110105200825.6CE50EE9CC@mail.python.org> Author: raymond.hettinger Date: Wed Jan 5 21:08:25 2011 New Revision: 87766 Log: Fix count of flag fields. Being one short caused the 'quiet' option not to print. Modified: python/branches/py3k/Python/sysmodule.c Modified: python/branches/py3k/Python/sysmodule.c ============================================================================== --- python/branches/py3k/Python/sysmodule.c (original) +++ python/branches/py3k/Python/sysmodule.c Wed Jan 5 21:08:25 2011 @@ -1427,9 +1427,9 @@ flags__doc__, /* doc */ flags_fields, /* fields */ #ifdef RISCOS - 12 + 13 #else - 11 + 12 #endif }; From python-checkins at python.org Wed Jan 5 21:24:08 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 5 Jan 2011 21:24:08 +0100 (CET) Subject: [Python-checkins] r87767 - in python/branches/py3k: Doc/whatsnew/3.2.rst Lib/test/test_sys.py Message-ID: <20110105202408.81144EE9DE@mail.python.org> Author: raymond.hettinger Date: Wed Jan 5 21:24:08 2011 New Revision: 87767 Log: Update tests and whatsnew for the 'quiet' flag Modified: python/branches/py3k/Doc/whatsnew/3.2.rst python/branches/py3k/Lib/test/test_sys.py Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Wed Jan 5 21:24:08 2011 @@ -383,7 +383,14 @@ (Suggested by Mark Dickinson and implemented by Eric Smith in :issue:`7094`.) * The interpreter can now be started with a quiet option, ``-q``, to suppress - the copyright and version information in an interactive mode. + the copyright and version information in an interactive mode. The option can + be introspected using the :attr:`sys.flags` attribute:: + + $ python -q + >>> sys.flags + sys.flags(debug=0, division_warning=0, inspect=0, interactive=0, + optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0, + ignore_environment=0, verbose=0, bytes_warning=0, quiet=1) (Contributed by Marcin Wojdyr in issue:`1772833`). Modified: python/branches/py3k/Lib/test/test_sys.py ============================================================================== --- python/branches/py3k/Lib/test/test_sys.py (original) +++ python/branches/py3k/Lib/test/test_sys.py Wed Jan 5 21:24:08 2011 @@ -501,7 +501,7 @@ attrs = ("debug", "division_warning", "inspect", "interactive", "optimize", "dont_write_bytecode", "no_user_site", "no_site", "ignore_environment", "verbose", - "bytes_warning") + "bytes_warning", "quiet") for attr in attrs: self.assertTrue(hasattr(sys.flags, attr), attr) self.assertEqual(type(getattr(sys.flags, attr)), int, attr) From python-checkins at python.org Wed Jan 5 22:03:48 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 5 Jan 2011 22:03:48 +0100 (CET) Subject: [Python-checkins] r87768 - in python/branches/py3k: Lib/socket.py Lib/test/test_socket.py Misc/NEWS Message-ID: <20110105210348.5015AEE98A@mail.python.org> Author: antoine.pitrou Date: Wed Jan 5 22:03:42 2011 New Revision: 87768 Log: Issue #7995: When calling accept() on a socket with a timeout, the returned socket is now always non-blocking, regardless of the operating system. Modified: python/branches/py3k/Lib/socket.py python/branches/py3k/Lib/test/test_socket.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/socket.py ============================================================================== --- python/branches/py3k/Lib/socket.py (original) +++ python/branches/py3k/Lib/socket.py Wed Jan 5 22:03:42 2011 @@ -130,7 +130,13 @@ For IP sockets, the address info is a pair (hostaddr, port). """ fd, addr = self._accept() - return socket(self.family, self.type, self.proto, fileno=fd), addr + sock = socket(self.family, self.type, self.proto, fileno=fd) + # Issue #7995: if no default timeout is set and the listening + # socket had a (non-zero) timeout, force the new socket in blocking + # mode to override platform-specific socket flags inheritance. + if getdefaulttimeout() is None and self.gettimeout(): + sock.setblocking(True) + return sock, addr def makefile(self, mode="r", buffering=None, *, encoding=None, errors=None, newline=None): Modified: python/branches/py3k/Lib/test/test_socket.py ============================================================================== --- python/branches/py3k/Lib/test/test_socket.py (original) +++ python/branches/py3k/Lib/test/test_socket.py Wed Jan 5 22:03:42 2011 @@ -982,6 +982,23 @@ def _testInitNonBlocking(self): pass + def testInheritFlags(self): + # Issue #7995: when calling accept() on a listening socket with a + # timeout, the resulting socket should not be non-blocking. + self.serv.settimeout(10) + try: + conn, addr = self.serv.accept() + message = conn.recv(len(MSG)) + finally: + conn.close() + self.serv.settimeout(None) + + def _testInheritFlags(self): + time.sleep(0.1) + self.cli.connect((HOST, self.port)) + time.sleep(0.5) + self.cli.send(MSG) + def testAccept(self): # Testing non-blocking accept self.serv.setblocking(0) Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Wed Jan 5 22:03:42 2011 @@ -30,6 +30,9 @@ Library ------- +- Issue #7995: When calling accept() on a socket with a timeout, the returned + socket is now always non-blocking, regardless of the operating system. + - Issue #10756: atexit normalizes the exception before displaying it. Patch by Andreas St?hrk. From python-checkins at python.org Wed Jan 5 22:17:37 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 5 Jan 2011 22:17:37 +0100 (CET) Subject: [Python-checkins] r87769 - python/branches/py3k/Doc/library/socket.rst Message-ID: <20110105211737.03274EE984@mail.python.org> Author: antoine.pitrou Date: Wed Jan 5 22:17:36 2011 New Revision: 87769 Log: Overhaul the documentation about socket timeouts. Modified: python/branches/py3k/Doc/library/socket.rst Modified: python/branches/py3k/Doc/library/socket.rst ============================================================================== --- python/branches/py3k/Doc/library/socket.rst (original) +++ python/branches/py3k/Doc/library/socket.rst Wed Jan 5 22:17:36 2011 @@ -148,8 +148,8 @@ .. exception:: timeout This exception is raised when a timeout occurs on a socket which has had - timeouts enabled via a prior call to :meth:`settimeout`. The accompanying value - is a string whose value is currently always "timed out". + timeouts enabled via a prior call to :meth:`~socket.settimeout`. The + accompanying value is a string whose value is currently always "timed out". .. data:: AF_UNIX @@ -515,9 +515,10 @@ .. function:: setdefaulttimeout(timeout) - Set the default timeout in floating seconds for new socket objects. A value of - ``None`` indicates that new socket objects have no timeout. When the socket - module is first imported, the default is ``None``. + Set the default timeout in floating seconds for new socket objects. When + the socket module is first imported, the default is ``None``. See + :meth:`~socket.settimeout` for possible values and their respective + meanings. .. data:: SocketType @@ -624,6 +625,13 @@ to decode C structures encoded as byte strings). +.. method:: socket.gettimeout() + + Return the timeout in floating seconds associated with socket operations, + or ``None`` if no timeout is set. This reflects the last call to + :meth:`setblocking` or :meth:`settimeout`. + + .. method:: socket.ioctl(control, option) :platform: Windows @@ -653,8 +661,9 @@ interpreted the same way as by the built-in :func:`open` function. Closing the file object won't close the socket unless there are no remaining - references to the socket. The socket must be in blocking mode (it can not - have a timeout). + references to the socket. The socket must be in blocking mode; it can have + a timeout, but the file object's internal buffer may end up in a inconsistent + state if a timeout occurs. .. note:: @@ -734,55 +743,26 @@ .. method:: socket.setblocking(flag) - Set blocking or non-blocking mode of the socket: if *flag* is 0, the socket is - set to non-blocking, else to blocking mode. Initially all sockets are in - blocking mode. In non-blocking mode, if a :meth:`recv` call doesn't find any - data, or if a :meth:`send` call can't immediately dispose of the data, a - :exc:`error` exception is raised; in blocking mode, the calls block until they - can proceed. ``s.setblocking(0)`` is equivalent to ``s.settimeout(0.0)``; - ``s.setblocking(1)`` is equivalent to ``s.settimeout(None)``. + Set blocking or non-blocking mode of the socket: if *flag* is false, the + socket is set to non-blocking, else to blocking mode. + This method is a shorthand for certain :meth:`~socket.settimeout` calls: -.. method:: socket.settimeout(value) + * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` - Set a timeout on blocking socket operations. The *value* argument can be a - nonnegative float expressing seconds, or ``None``. If a float is given, - subsequent socket operations will raise a :exc:`timeout` exception if the - timeout period *value* has elapsed before the operation has completed. Setting - a timeout of ``None`` disables timeouts on socket operations. - ``s.settimeout(0.0)`` is equivalent to ``s.setblocking(0)``; - ``s.settimeout(None)`` is equivalent to ``s.setblocking(1)``. - - -.. method:: socket.gettimeout() + * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0.0)`` - Return the timeout in floating seconds associated with socket operations, or - ``None`` if no timeout is set. This reflects the last call to - :meth:`setblocking` or :meth:`settimeout`. +.. method:: socket.settimeout(value) -Some notes on socket blocking and timeouts: A socket object can be in one of -three modes: blocking, non-blocking, or timeout. Sockets are always created in -blocking mode. In blocking mode, operations block until complete or -the system returns an error (such as connection timed out). In -non-blocking mode, operations fail (with an error that is unfortunately -system-dependent) if they cannot be completed immediately. In timeout mode, -operations fail if they cannot be completed within the timeout specified for the -socket or if the system returns an error. The :meth:`~socket.setblocking` -method is simply a shorthand for certain :meth:`~socket.settimeout` calls. - -Timeout mode internally sets the socket in non-blocking mode. The blocking and -timeout modes are shared between file descriptors and socket objects that refer -to the same network endpoint. A consequence of this is that file objects -returned by the :meth:`~socket.makefile` method must only be used when the -socket is in blocking mode; in timeout or non-blocking mode file operations -that cannot be completed immediately will fail. + Set a timeout on blocking socket operations. The *value* argument can be a + nonnegative floating point number expressing seconds, or ``None``. + If a non-zero value is given, subsequent socket operations will raise a + :exc:`timeout` exception if the timeout period *value* has elapsed before + the operation has completed. If zero is given, the socket is put in + non-blocking mode. If ``None`` is given, the socket is put in blocking mode. -Note that the :meth:`~socket.connect` operation is subject to the timeout -setting, and in general it is recommended to call :meth:`~socket.settimeout` -before calling :meth:`~socket.connect` or pass a timeout parameter to -:meth:`create_connection`. The system network stack may return a connection -timeout error of its own regardless of any Python socket timeout setting. + For further information, please consult the :ref:`notes on socket timeouts `. .. method:: socket.setsockopt(level, optname, value) @@ -828,6 +808,61 @@ The socket protocol. + +.. _socket-timeouts: + +Notes on socket timeouts +------------------------ + +A socket object can be in one of three modes: blocking, non-blocking, or +timeout. Sockets are by default always created in blocking mode, but this +can be changed by calling :func:`setdefaulttimeout`. + +* In *blocking mode*, operations block until complete or the system returns + an error (such as connection timed out). + +* In *non-blocking mode*, operations fail (with an error that is unfortunately + system-dependent) if they cannot be completed immediately: functions from the + :mod:`select` can be used to know when and whether a socket is available for + reading or writing. + +* In *timeout mode*, operations fail if they cannot be completed within the + timeout specified for the socket (they raise a :exc:`timeout` exception) + or if the system returns an error. + +.. note:: + At the operating system level, sockets in *timeout mode* are internally set + in non-blocking mode. Also, the blocking and timeout modes are shared between + file descriptors and socket objects that refer to the same network endpoint. + This implementation detail can have visible consequences if e.g. you decide + to use the :meth:`~socket.fileno()` of a socket. + +Timeouts and the ``connect`` method +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :meth:`~socket.connect` operation is also subject to the timeout +setting, and in general it is recommended to call :meth:`~socket.settimeout` +before calling :meth:`~socket.connect` or pass a timeout parameter to +:meth:`create_connection`. However, the system network stack may also +return a connection timeout error of its own regardless of any Python socket +timeout setting. + +Timeouts and the ``accept`` method +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If :func:`getdefaulttimeout` is not :const:`None`, sockets returned by +the :meth:`~socket.accept` method inherit that timeout. Otherwise, the +behaviour depends on settings of the listening socket: + +* if the listening socket is in *blocking mode* or in *timeout mode*, + the socket returned by :meth:`~socket.accept` is in *blocking mode*; + +* if the listening socket is in *non-blocking mode*, whether the socket + returned by :meth:`~socket.accept` is in blocking or non-blocking mode + is operating system-dependent. If you want to ensure cross-platform + behaviour, it is recommended you manually override this setting. + + .. _socket-example: Example From python-checkins at python.org Wed Jan 5 22:20:28 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 5 Jan 2011 22:20:28 +0100 (CET) Subject: [Python-checkins] r87770 - in python/branches/release31-maint: Doc/library/socket.rst Message-ID: <20110105212028.2FA1FEE984@mail.python.org> Author: antoine.pitrou Date: Wed Jan 5 22:20:28 2011 New Revision: 87770 Log: Merged revisions 87769 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87769 | antoine.pitrou | 2011-01-05 22:17:36 +0100 (mer., 05 janv. 2011) | 3 lines Overhaul the documentation about socket timeouts. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Doc/library/socket.rst Modified: python/branches/release31-maint/Doc/library/socket.rst ============================================================================== --- python/branches/release31-maint/Doc/library/socket.rst (original) +++ python/branches/release31-maint/Doc/library/socket.rst Wed Jan 5 22:20:28 2011 @@ -149,8 +149,8 @@ .. exception:: timeout This exception is raised when a timeout occurs on a socket which has had - timeouts enabled via a prior call to :meth:`settimeout`. The accompanying value - is a string whose value is currently always "timed out". + timeouts enabled via a prior call to :meth:`~socket.settimeout`. The + accompanying value is a string whose value is currently always "timed out". .. data:: AF_UNIX @@ -485,9 +485,10 @@ .. function:: setdefaulttimeout(timeout) - Set the default timeout in floating seconds for new socket objects. A value of - ``None`` indicates that new socket objects have no timeout. When the socket - module is first imported, the default is ``None``. + Set the default timeout in floating seconds for new socket objects. When + the socket module is first imported, the default is ``None``. See + :meth:`~socket.settimeout` for possible values and their respective + meanings. .. data:: SocketType @@ -585,6 +586,13 @@ to decode C structures encoded as byte strings). +.. method:: socket.gettimeout() + + Return the timeout in floating seconds associated with socket operations, + or ``None`` if no timeout is set. This reflects the last call to + :meth:`setblocking` or :meth:`settimeout`. + + .. method:: socket.ioctl(control, option) :platform: Windows @@ -613,9 +621,10 @@ arguments are interpreted the same way as by the built-in :func:`open` function. - Closing the file object won't close the socket unless there are no - remaining references to the socket. The socket must be in blocking mode - (it can not have a timeout). + Closing the file object won't close the socket unless there are no remaining + references to the socket. The socket must be in blocking mode; it can have + a timeout, but the file object's internal buffer may end up in a inconsistent + state if a timeout occurs. .. method:: socket.recv(bufsize[, flags]) @@ -689,55 +698,26 @@ .. method:: socket.setblocking(flag) - Set blocking or non-blocking mode of the socket: if *flag* is 0, the socket is - set to non-blocking, else to blocking mode. Initially all sockets are in - blocking mode. In non-blocking mode, if a :meth:`recv` call doesn't find any - data, or if a :meth:`send` call can't immediately dispose of the data, a - :exc:`error` exception is raised; in blocking mode, the calls block until they - can proceed. ``s.setblocking(0)`` is equivalent to ``s.settimeout(0.0)``; - ``s.setblocking(1)`` is equivalent to ``s.settimeout(None)``. + Set blocking or non-blocking mode of the socket: if *flag* is false, the + socket is set to non-blocking, else to blocking mode. + This method is a shorthand for certain :meth:`~socket.settimeout` calls: -.. method:: socket.settimeout(value) + * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` - Set a timeout on blocking socket operations. The *value* argument can be a - nonnegative float expressing seconds, or ``None``. If a float is given, - subsequent socket operations will raise a :exc:`timeout` exception if the - timeout period *value* has elapsed before the operation has completed. Setting - a timeout of ``None`` disables timeouts on socket operations. - ``s.settimeout(0.0)`` is equivalent to ``s.setblocking(0)``; - ``s.settimeout(None)`` is equivalent to ``s.setblocking(1)``. - - -.. method:: socket.gettimeout() + * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0.0)`` - Return the timeout in floating seconds associated with socket operations, or - ``None`` if no timeout is set. This reflects the last call to - :meth:`setblocking` or :meth:`settimeout`. +.. method:: socket.settimeout(value) -Some notes on socket blocking and timeouts: A socket object can be in one of -three modes: blocking, non-blocking, or timeout. Sockets are always created in -blocking mode. In blocking mode, operations block until complete or -the system returns an error (such as connection timed out). In -non-blocking mode, operations fail (with an error that is unfortunately -system-dependent) if they cannot be completed immediately. In timeout mode, -operations fail if they cannot be completed within the timeout specified for the -socket or if the system returns an error. The :meth:`~socket.setblocking` -method is simply a shorthand for certain :meth:`~socket.settimeout` calls. - -Timeout mode internally sets the socket in non-blocking mode. The blocking and -timeout modes are shared between file descriptors and socket objects that refer -to the same network endpoint. A consequence of this is that file objects -returned by the :meth:`~socket.makefile` method must only be used when the -socket is in blocking mode; in timeout or non-blocking mode file operations -that cannot be completed immediately will fail. + Set a timeout on blocking socket operations. The *value* argument can be a + nonnegative floating point number expressing seconds, or ``None``. + If a non-zero value is given, subsequent socket operations will raise a + :exc:`timeout` exception if the timeout period *value* has elapsed before + the operation has completed. If zero is given, the socket is put in + non-blocking mode. If ``None`` is given, the socket is put in blocking mode. -Note that the :meth:`~socket.connect` operation is subject to the timeout -setting, and in general it is recommended to call :meth:`~socket.settimeout` -before calling :meth:`~socket.connect` or pass a timeout parameter to -:meth:`create_connection`. The system network stack may return a connection -timeout error of its own regardless of any Python socket timeout setting. + For further information, please consult the :ref:`notes on socket timeouts `. .. method:: socket.setsockopt(level, optname, value) @@ -783,6 +763,46 @@ The socket protocol. + +.. _socket-timeouts: + +Notes on socket timeouts +------------------------ + +A socket object can be in one of three modes: blocking, non-blocking, or +timeout. Sockets are by default always created in blocking mode, but this +can be changed by calling :func:`setdefaulttimeout`. + +* In *blocking mode*, operations block until complete or the system returns + an error (such as connection timed out). + +* In *non-blocking mode*, operations fail (with an error that is unfortunately + system-dependent) if they cannot be completed immediately: functions from the + :mod:`select` can be used to know when and whether a socket is available for + reading or writing. + +* In *timeout mode*, operations fail if they cannot be completed within the + timeout specified for the socket (they raise a :exc:`timeout` exception) + or if the system returns an error. + +.. note:: + At the operating system level, sockets in *timeout mode* are internally set + in non-blocking mode. Also, the blocking and timeout modes are shared between + file descriptors and socket objects that refer to the same network endpoint. + This implementation detail can have visible consequences if e.g. you decide + to use the :meth:`~socket.fileno()` of a socket. + +Timeouts and the ``connect`` method +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :meth:`~socket.connect` operation is also subject to the timeout +setting, and in general it is recommended to call :meth:`~socket.settimeout` +before calling :meth:`~socket.connect` or pass a timeout parameter to +:meth:`create_connection`. However, the system network stack may also +return a connection timeout error of its own regardless of any Python socket +timeout setting. + + .. _socket-example: Example From python-checkins at python.org Wed Jan 5 22:47:47 2011 From: python-checkins at python.org (georg.brandl) Date: Wed, 5 Jan 2011 22:47:47 +0100 (CET) Subject: [Python-checkins] r87771 - python/branches/py3k/Lib/test/regrtest.py Message-ID: <20110105214747.E0042EE9CC@mail.python.org> Author: georg.brandl Date: Wed Jan 5 22:47:47 2011 New Revision: 87771 Log: On Py3k, -tt and -3 are no-op and unsupported respectively. Modified: python/branches/py3k/Lib/test/regrtest.py Modified: python/branches/py3k/Lib/test/regrtest.py ============================================================================== --- python/branches/py3k/Lib/test/regrtest.py (original) +++ python/branches/py3k/Lib/test/regrtest.py Wed Jan 5 22:47:47 2011 @@ -3,7 +3,7 @@ """ Usage: -python -m test.regrtest [options] [test_name1 [test_name2 ...]] +python -m test [options] [test_name1 [test_name2 ...]] python path/to/Lib/test/regrtest.py [options] [test_name1 [test_name2 ...]] @@ -14,7 +14,7 @@ For more rigorous testing, it is useful to use the following command line: -python -E -tt -Wd -3 -m test.regrtest [options] [test_name1 ...] +python -E -Wd -m test [options] [test_name1 ...] Options: From python-checkins at python.org Wed Jan 5 23:11:21 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 23:11:21 +0100 Subject: [Python-checkins] devguide: Add placeholder for having people get involved by fixing warnings (e.g., Message-ID: brett.cannon pushed 91293487e427 to devguide: http://hg.python.org/devguide/rev/91293487e427 changeset: 28:91293487e427 user: Brett Cannon date: Wed Jan 05 13:33:31 2011 -0800 summary: Add placeholder for having people get involved by fixing warnings (e.g., ResourceWarnings). files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -24,10 +24,11 @@ * `PEP 7`_ * `PEP 8`_ * :ref:`patch` -* `Running the test suite `_ +* :ref:`runtests` * Projects to get familiar with the development process * `Help increase test coverage `_ * `Make all unit tests discoverable by unittest `_ + * `Fix all warnings raised when running the test suite w/ -uall `_ * `Fixing documentation bugs `_ * Projects for once you are comfortable * `Helping triage issues `_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 23:11:21 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 23:11:21 +0100 Subject: [Python-checkins] devguide: Start a doc on running and writing unit tests. Message-ID: brett.cannon pushed 2c77eaf7f589 to devguide: http://hg.python.org/devguide/rev/2c77eaf7f589 changeset: 29:2c77eaf7f589 user: Brett Cannon date: Wed Jan 05 13:44:39 2011 -0800 summary: Start a doc on running and writing unit tests. files: index.rst runtests.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -6,6 +6,7 @@ setup patch + runtests .. todolist:: diff --git a/runtests.rst b/runtests.rst new file mode 100644 --- /dev/null +++ b/runtests.rst @@ -0,0 +1,49 @@ +.. _runtests: + +Running & Writing Tests +======================= + +.. note:: + This document assumes you are working with the in-development version of + Python. If you are not then some things presented here may not work as they + may depend on new features not available in released versions of Python. + +Running +------- + +The shortest, simplest way of running the test suite is:: + + ./python -m test + +That will run the entire standard test suite (i.e., all tests that do not +consume a lot of resources) using the ``test.regrtest`` module (Python's test +runner which you can execute directly if you prefer). +To run **all** tests, you need to specify what +resources you are willing to have consumed. For those flags (and others which +can help debug various issues such as reference leaks), read the help text:: + + ./python -m test -h + +If you want to run a single test, simply specify the test name as an argument:: + + ./python -m test test_abc + +Finally, if you want to run tests under a more strenuous set of settings, you +can run test as:: + + ./python -bb -E -Wd -m test -j2 -r -w + +The various extra flags passed to Python cause it to be much stricter about +various things (the ``-Wd`` flag should be ``-We`` at some point, but the test +suite has not reached a point where all warnings have been dealt with and so we +cannot guarantee that a bug-free Python will properly complete a test run with +``-We``). The flags to the test runner cause it to run faster but also +more randomly which is also a stricter way to run tests thanks to possible +assumptions in test order or state that may have been made. It also causes +failures to run again to see if it a transient failure or a consistent one. + + +Writing +------- + +XXX -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 23:11:21 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 23:11:21 +0100 Subject: [Python-checkins] devguide: Add a note about a possible starter project. Message-ID: brett.cannon pushed fb2acaf637a5 to devguide: http://hg.python.org/devguide/rev/fb2acaf637a5 changeset: 30:fb2acaf637a5 user: Brett Cannon date: Wed Jan 05 14:08:53 2011 -0800 summary: Add a note about a possible starter project. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -74,6 +74,10 @@ Move various informational PEPs out of the PEP index and over here (.e.g, grammar and compiler guides) +.. todo:: + See if tempfile or test.support has a context manager that creates and + deletes a temp file so as to move off of test.support.TESTFN. + .. _buildbots: http://python.org/dev/buildbot/ .. _PEP 7: http://www.python.org/dev/peps/pep-0007 -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 23:11:21 2011 From: python-checkins at python.org (brett.cannon) Date: Wed, 05 Jan 2011 23:11:21 +0100 Subject: [Python-checkins] devguide: Discuss the writing of tests. Message-ID: brett.cannon pushed 0b915adc0c34 to devguide: http://hg.python.org/devguide/rev/0b915adc0c34 changeset: 31:0b915adc0c34 tag: tip user: Brett Cannon date: Wed Jan 05 14:10:29 2011 -0800 summary: Discuss the writing of tests. files: runtests.rst diff --git a/runtests.rst b/runtests.rst --- a/runtests.rst +++ b/runtests.rst @@ -46,4 +46,16 @@ Writing ------- -XXX +Writing tests for Python is much like writing tests for your own code. Tests +need to be thorough, fast, isolated, consistently repeatable, and as simple as +possible. Tests live in the ``Lib/test`` directory, where every file that +includes tests has a ``test_`` prefix. + +One difference, though, is that you are allowed to use the ``test.support`` +module. It contains various helpers that are tailored to Python's test suite. +Because of this it has no API or backwards-compatibility guarantees, which is +why the general public is not supposed to use the module. But when you are +writing tests for Python's test suite its use is encouraged. + +If your test must write various temporary files to a specific directory, you +can use the ``Lib/test/data`` directory for that purpose. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Wed Jan 5 23:27:49 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 5 Jan 2011 23:27:49 +0100 (CET) Subject: [Python-checkins] r87772 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110105222749.60B09EE9DE@mail.python.org> Author: raymond.hettinger Date: Wed Jan 5 23:27:49 2011 New Revision: 87772 Log: RC1 updates to whatsnew Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Wed Jan 5 23:27:49 2011 @@ -394,13 +394,13 @@ (Contributed by Marcin Wojdyr in issue:`1772833`). -* The :func:`hasattr` function used to catch and suppress any Exception. Now, - it only catches :exc:`AttributeError`. Under the hood, :func:`hasattr` works - by calling :func:`getattr` and throwing away the results. This is necessary - because dynamic attribute creation is possible using :meth:`__getattribute__` - or :meth:`__getattr__`. If :func:`hasattr` were to just scan instance and class - dictionaries it would miss the dynamic methods and make it difficult to - implement proxy objects. +* The :func:`hasattr` function works by calling :func:`getattr` and detecting + whether an exception is raised. This technique allows it to detect methods + created dynamically by :meth:`__getattr__` or :meth:`__getattribute__` which + would be absent from the class dictionary. Formerly, *hasattr* would catch + any exception, possibly masking genuine errors in those methods. Now, + *hasattr* has been tightened to only catch :exc:`AttributeError` and let + other exceptions pass through. (Discovered by Yury Selivanov and fixed by Benjamin Peterson; :issue:`9666`.) @@ -682,9 +682,10 @@ return ((self.lastname.lower(), self.firstname.lower()) < (other.lastname.lower(), other.firstname.lower())) - (Contributed by Raymond Hettinger.) + With the *total_ordering* decorator, the remaining comparison methods + are filled-in automatically. -.. XXX clarify what the example does + (Contributed by Raymond Hettinger.) * To aid in porting programs from Python 2, the :func:`~functools.cmp_to_key` function converts an old-style comparison function to @@ -787,12 +788,10 @@ * Also, :class:`~datetime.timedelta` objects can now be multiplied by :class:`float` and divided by :class:`float` and :class:`int` objects. + And :class:`~datetime.timedelta` objects can now divide one another. -.. XXX Describe added support for dividing a timedelta by another timedelta. - See revision 80290 and issue #2706. - - (Contributed by Alexander Belopolsky in :issue:`1289118`, :issue:`5094` and - :issue:`6641`.) + (Contributed by Alexander Belopolsky in :issue:`1289118`, :issue:`5094`, + :issue:`6641`, and :issue:`2706`.) abc --- @@ -861,7 +860,7 @@ (Contributed by Michael Foord in :issue:`9110`.) decimal and fractions ---------------------- +---------------------- Mark Dickinson crafted an elegant and efficient scheme for assuring that different numeric datatypes will have the same hash value whenever their actual @@ -902,6 +901,16 @@ (Contributed by Mark Dickinson and Raymond Hettinger.) +codecs +------ + +In an effort to keep codec aliases solely focused on bytes-to-text encodings, +the *base64*, *bz2*, *hex*, *quopri*, *rot13*, *uu* and *zlib* codecs have been +removed from the codec aliases. These bytes-to-bytes conversion are still +accessible via codecs.lookup(). + +(see :issue:`10807`.) + ftp --- @@ -930,7 +939,11 @@ (Contributed by Tarek Ziad? and Giampaolo Rodol? in :issue:`4972`, and by Georg Brandl in :issue:`8046` and :issue:`1286`.) -.. XXX mention os.popen and subprocess.Popen auto-closing of fds +popen +----- + +The :func:`os.popen` and :func:`subprocess.Popen` functions now support +the :keyword:`with`-statement` for auto-closing of the file descriptors. gzip and zipfile ---------------- @@ -1077,6 +1090,11 @@ unittest -------- +The unittest module has a number of improvements supporting test discovery for +packages, easier experimentation at the interactive prompt, new testcase +methods, improved diagnostic messages for test failures, and better method +names. + * The command-line call, ``python -m unittest`` can now accept file paths instead of module names for running specific tests (:issue:`10620`). The new test discovery can find tests within packages, locating any test importable @@ -1088,14 +1106,24 @@ (Contributed by Michael Foord.) +* Experimentation at the interactive prompt is now easier because the + :class:`unittest.case.TestCase` class can now be instantiated without + arguments: + + >>> TestCase().assertEqual(pow(2, 3), 8) + + (Contributed by Michael Foord.) + * The :mod:`unittest` module has two new methods, :meth:`~unittest.TestCase.assertWarns` and - :meth:`~unittest.TestCase.assertWarnsRegex` to check that a given warning type + :meth:`~unittest.TestCase.assertWarnsRegex` to verify that a given warning type is triggered by the code under test: >>> with self.assertWarns(DeprecationWarning): ... legacy_function('XYZ') + (Contributed by Michael Foord and Ezio Melotti.) + Another new method, :meth:`~unittest.TestCase.assertCountEqual` is used to compare two iterables to determine if their element counts are equal (whether the same elements are present with the same number of occurrences regardless @@ -1104,23 +1132,28 @@ def test_anagram(self): self.assertCountEqual('algorithm', 'logarithm') - A principal feature of the unittest module is an effort to produce meaningful + (Contributed by Raymond Hettinger.) + +* A principal feature of the unittest module is an effort to produce meaningful diagnostics when a test fails. When possible the failure is recorded along with a diff of the output. This is especially helpful for analyzing log files of failed test runs. However, since diffs can sometime be voluminous, there is a new :attr:`~unittest.TestCase.maxDiff` attribute which sets maximum length of diffs. - In addition the naming in the module has undergone a number of clean-ups. For - example, :meth:`~unittest.TestCase.assertRegex` is the new name for +* In addition, the method names in the module have undergone a number of clean-ups. + + For example, :meth:`~unittest.TestCase.assertRegex` is the new name for :meth:`~unittest.TestCase.assertRegexpMatches` which was misnamed because the test uses :func:`re.search`, not :func:`re.match`. Other methods using - regular expressions are now named using short form "Regex" in preference - to "Regexp" -- this matches the names used in other unittest implementations, + regular expressions are now named using short form "Regex" in preference to + "Regexp" -- this matches the names used in other unittest implementations, matches Python's old name for the :mod:`re` module, and it has unambiguous camel-casing. - To improve consistency, some of long-standing method aliases are being + (Contributed by Raymond Hettinger and implemented by Ezio Melotti.) + +* To improve consistency, some of long-standing method aliases are being deprecated in favor of the preferred names: - replace :meth:`assert_` with :meth:`.assertTrue` @@ -1135,6 +1168,13 @@ (Contributed by Ezio Melotti; :issue:`9424`.) +* The :meth:`~unittest.TestCase.assertDictContainsSubset` method was deprecated + because it was mis-implemented with the arguments in the wrong order. This + created hard-to-debug optical illusions where tests like + ``TestCase().assertDictContainsSubset({'a':1, 'b':2}, {'a':1})`` would fail. + + (Contributed by Raymond Hettinger.) + random ------ @@ -1548,12 +1588,22 @@ No functionality was changed. This just provides an easier-to-read alternate implementation. (Contributed by Alexander Belopolsky.) +The unmaintained *Demo* directory has been removed. Some demos were integrated +into the documentation, some were moved to the *Tools/demo* directory, and +others were removed altogether. (Contributed by Georg Brandl.) + IDLE ==== * The format menu now has an option to clean-up source files by stripping - trailing whitespace (:issue:`5150`). + trailing whitespace. + + (Contributed by Raymond Hettinger; :issue:`5150`.) + +* IDLE on Mac OS X now works with both Carbon AquaTk and Cocoa AquaTk. + + (Contributed by Kevin Walzer, Ned Deily, and Ronald Oussoren; :issue:`6075`.) Build and C API Changes @@ -1561,6 +1611,9 @@ Changes to Python's build process and to the C API include: +* The *idle*, *pydoc* and *2to3* scripts are now installed with a + version-specific suffix on ``make altinstall`` (:issue:`10679`). + * The C functions that access the Unicode Database now accept and return characters from the full Unicode range, even on narrow unicode builds (Py_UNICODE_TOLOWER, Py_UNICODE_ISDECIMAL, and others). A visible difference @@ -1713,6 +1766,13 @@ (Contributed by Georg Brandl and Mattias Br?ndstr?m; `appspot issue 53094 `_.) -* :func:`struct.pack` no longer implicitly encodes unicode to UTF-8: use - explicit conversion instead and replace unicode literals by bytes literals. +* :func:`struct.pack` now only allows bytes for the ``s`` string pack code. + Formerly, it would accept text arguments and implicitly encode them to bytes + using UTF-8. This was problematic because it made assumptions about the + correct encoding and because a variable length encoding can fail when writing + to fixed length segment of a structure. + + Code such as ``struct.pack('<6sHHBBB', 'GIF87a', x, y)`` should be rewritten + with to use bytes instead of text, ``struct.pack('<6sHHBBB', b'GIF87a', x, y)``. + (Discovered by David Beazley and fixed by Victor Stinner; :issue:`10783`. From python-checkins at python.org Wed Jan 5 23:41:23 2011 From: python-checkins at python.org (raymond.hettinger) Date: Wed, 5 Jan 2011 23:41:23 +0100 (CET) Subject: [Python-checkins] r87773 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110105224123.7AFCEEE991@mail.python.org> Author: raymond.hettinger Date: Wed Jan 5 23:41:23 2011 New Revision: 87773 Log: Remove mention of codes pending further discussion on transform()/untransform(). Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Wed Jan 5 23:41:23 2011 @@ -901,16 +901,6 @@ (Contributed by Mark Dickinson and Raymond Hettinger.) -codecs ------- - -In an effort to keep codec aliases solely focused on bytes-to-text encodings, -the *base64*, *bz2*, *hex*, *quopri*, *rot13*, *uu* and *zlib* codecs have been -removed from the codec aliases. These bytes-to-bytes conversion are still -accessible via codecs.lookup(). - -(see :issue:`10807`.) - ftp --- From python-checkins at python.org Wed Jan 5 23:43:26 2011 From: python-checkins at python.org (antoine.pitrou) Date: Wed, 5 Jan 2011 23:43:26 +0100 (CET) Subject: [Python-checkins] r87774 - python/branches/py3k/Misc/NEWS Message-ID: <20110105224326.58436EE991@mail.python.org> Author: antoine.pitrou Date: Wed Jan 5 23:43:26 2011 New Revision: 87774 Log: Fix mistake in NEWS Modified: python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Wed Jan 5 23:43:26 2011 @@ -31,7 +31,7 @@ ------- - Issue #7995: When calling accept() on a socket with a timeout, the returned - socket is now always non-blocking, regardless of the operating system. + socket is now always blocking, regardless of the operating system. - Issue #10756: atexit normalizes the exception before displaying it. Patch by Andreas St?hrk. From python-checkins at python.org Thu Jan 6 00:00:00 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 6 Jan 2011 00:00:00 +0100 (CET) Subject: [Python-checkins] r87775 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110105230000.8C5A6F2C0@mail.python.org> Author: raymond.hettinger Date: Thu Jan 6 00:00:00 2011 New Revision: 87775 Log: Add more porting notes. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Thu Jan 6 00:00:00 2011 @@ -1766,3 +1766,10 @@ with to use bytes instead of text, ``struct.pack('<6sHHBBB', b'GIF87a', x, y)``. (Discovered by David Beazley and fixed by Victor Stinner; :issue:`10783`. + +* The :class:`xml.etree.ElementTree` class now raises an + :exc:`xml.etree.ElementTree.ParseError` when a parse fails. Previously it + raised a :exc:`xml.parsers.expat.ExpatError`. + +* The new, longer :func:`str` value on floats may break doctests which rely on + the old output format. From python-checkins at python.org Thu Jan 6 00:00:47 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Thu, 6 Jan 2011 00:00:47 +0100 (CET) Subject: [Python-checkins] r87776 - in python/branches/py3k: Lib/test/test_time.py Modules/timemodule.c Message-ID: <20110105230047.48C9BEE99C@mail.python.org> Author: alexander.belopolsky Date: Thu Jan 6 00:00:47 2011 New Revision: 87776 Log: - time.accept2dyear = True is now equivalent to time.accept2dyear = 1 - removed unnecessary struct_time to tuple conversion - added more unit tests (See issue #10827 for discussion.) Modified: python/branches/py3k/Lib/test/test_time.py python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Thu Jan 6 00:00:47 2011 @@ -263,8 +263,48 @@ # This should not cause an exception time.strftime("%B", (2009,2,1,0,0,0,0,0,0)) +class TestAccept2Year(unittest.TestCase): + accept2dyear = 1 + def setUp(self): + self.saved_accept2dyear = time.accept2dyear + time.accept2dyear = self.accept2dyear + + def tearDown(self): + time.accept2dyear = self.saved_accept2dyear + + def yearstr(self, y): + return time.strftime('%Y', (y,) + (0,) * 8) + + def test_2dyear(self): + self.assertEqual(self.yearstr(0), '2000') + self.assertEqual(self.yearstr(69), '1969') + self.assertEqual(self.yearstr(68), '2068') + self.assertEqual(self.yearstr(99), '1999') + + def test_invalid(self): + self.assertRaises(ValueError, self.yearstr, 1899) + self.assertRaises(ValueError, self.yearstr, 100) + self.assertRaises(ValueError, self.yearstr, -1) + +class TestAccept2YearBool(TestAccept2Year): + accept2dyear = True + +class TestDontAccept2Year(TestAccept2Year): + accept2dyear = 0 + def test_2dyear(self): + self.assertRaises(ValueError, self.yearstr, 0) + self.assertRaises(ValueError, self.yearstr, 69) + self.assertRaises(ValueError, self.yearstr, 68) + self.assertRaises(ValueError, self.yearstr, 99) + +class TestDontAccept2YearBool(TestDontAccept2Year): + accept2dyear = False + + def test_main(): - support.run_unittest(TimeTestCase, TestLocale) + support.run_unittest(TimeTestCase, TestLocale, + TestAccept2Year, TestAccept2YearBool, + TestDontAccept2Year, TestDontAccept2YearBool) if __name__ == "__main__": test_main() Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Thu Jan 6 00:00:47 2011 @@ -217,29 +217,6 @@ } static PyObject * -structtime_totuple(PyObject *t) -{ - PyObject *x = NULL; - unsigned int i; - PyObject *v = PyTuple_New(9); - if (v == NULL) - return NULL; - - for (i=0; i<9; i++) { - x = PyStructSequence_GET_ITEM(t, i); - Py_INCREF(x); - PyTuple_SET_ITEM(v, i, x); - } - - if (PyErr_Occurred()) { - Py_XDECREF(v); - return NULL; - } - - return v; -} - -static PyObject * time_convert(double when, struct tm * (*function)(const time_t *)) { struct tm *p; @@ -328,9 +305,6 @@ t = args; Py_INCREF(t); } - else if (Py_TYPE(args) == &StructTimeType) { - t = structtime_totuple(args); - } else { PyErr_SetString(PyExc_TypeError, "Tuple or struct_time argument required"); @@ -352,19 +326,30 @@ } Py_DECREF(t); + /* XXX: Why 1900? If the goal is to interpret 2-digit years as those in + * 20th / 21st century according to the POSIX standard, we can just treat + * 0 <= y < 100 as special. Year 100 is probably too ambiguous and should + * be rejected, but years 101 through 1899 can be passed through. + */ if (y < 1900) { PyObject *accept = PyDict_GetItemString(moddict, "accept2dyear"); - if (accept == NULL || !PyLong_CheckExact(accept) || - !PyObject_IsTrue(accept)) { - PyErr_SetString(PyExc_ValueError, - "year >= 1900 required"); + int acceptval = accept != NULL && PyObject_IsTrue(accept); + if (acceptval == -1) return 0; + if (acceptval) { + if (69 <= y && y <= 99) + y += 1900; + else if (0 <= y && y <= 68) + y += 2000; + else { + PyErr_SetString(PyExc_ValueError, + "year out of range"); + return 0; + } } - if (69 <= y && y <= 99) - y += 1900; - else if (0 <= y && y <= 68) - y += 2000; + /* XXX: When accept2dyear is false, we don't have to reject y < 1900. + * Consider removing the following else-clause. */ else { PyErr_SetString(PyExc_ValueError, "year out of range"); From python-checkins at python.org Thu Jan 6 00:01:37 2011 From: python-checkins at python.org (victor.stinner) Date: Thu, 6 Jan 2011 00:01:37 +0100 (CET) Subject: [Python-checkins] r87777 - python/branches/py3k/Lib/imaplib.py Message-ID: <20110105230137.5FAF4EE9E6@mail.python.org> Author: victor.stinner Date: Thu Jan 6 00:01:37 2011 New Revision: 87777 Log: imaplib: IMAP4 constructor closes the socket on error Fix a ResourceWarning(unclosed socket) if an exception is raised in the constructor after the creation of the socket. Patch written by Nadeem Vawda. Modified: python/branches/py3k/Lib/imaplib.py Modified: python/branches/py3k/Lib/imaplib.py ============================================================================== --- python/branches/py3k/Lib/imaplib.py (original) +++ python/branches/py3k/Lib/imaplib.py Thu Jan 6 00:01:37 2011 @@ -169,6 +169,17 @@ self.open(host, port) + try: + self._connect() + except Exception: + try: + self.shutdown() + except socket.error: + pass + raise + + + def _connect(self): # Create unique tag for this session, # and compile tagged response matcher. From python-checkins at python.org Thu Jan 6 00:01:39 2011 From: python-checkins at python.org (victor.stinner) Date: Thu, 6 Jan 2011 00:01:39 +0100 (CET) Subject: [Python-checkins] r87778 - python/branches/py3k/Lib/test/test_imaplib.py Message-ID: <20110105230139.135EDEE9E3@mail.python.org> Author: victor.stinner Date: Thu Jan 6 00:01:38 2011 New Revision: 87778 Log: test_imaplib: reap_server() closes the server when done Fix a ResourceWarning(unclosed socket). Patch written by Nadeem Vawda. Modified: python/branches/py3k/Lib/test/test_imaplib.py Modified: python/branches/py3k/Lib/test/test_imaplib.py ============================================================================== --- python/branches/py3k/Lib/test/test_imaplib.py (original) +++ python/branches/py3k/Lib/test/test_imaplib.py Thu Jan 6 00:01:38 2011 @@ -135,6 +135,7 @@ def reap_server(self, server, thread): if verbose: print("waiting for server") server.shutdown() + server.server_close() thread.join() if verbose: print("done") From python-checkins at python.org Thu Jan 6 00:47:01 2011 From: python-checkins at python.org (victor.stinner) Date: Thu, 6 Jan 2011 00:47:01 +0100 (CET) Subject: [Python-checkins] r87779 - python/branches/py3k/Lib/test/test_atexit.py Message-ID: <20110105234701.2991AEE984@mail.python.org> Author: victor.stinner Date: Thu Jan 6 00:47:00 2011 New Revision: 87779 Log: test_atexit: fix code saving/restoring stdout and stderr That's why I prefer a single instruction per line :-) Modified: python/branches/py3k/Lib/test/test_atexit.py Modified: python/branches/py3k/Lib/test/test_atexit.py ============================================================================== --- python/branches/py3k/Lib/test/test_atexit.py (original) +++ python/branches/py3k/Lib/test/test_atexit.py Thu Jan 6 00:47:00 2011 @@ -25,8 +25,9 @@ class TestCase(unittest.TestCase): def setUp(self): + self.save_stdout = sys.stdout + self.save_stderr = sys.stderr self.stream = io.StringIO() - self.save_stdout, self.save_stderr = sys.stderr, sys.stdout sys.stdout = sys.stderr = self.stream atexit._clear() From python-checkins at python.org Thu Jan 6 01:49:39 2011 From: python-checkins at python.org (victor.stinner) Date: Thu, 6 Jan 2011 01:49:39 +0100 (CET) Subject: [Python-checkins] r87780 - in python/branches/py3k: Lib/bdb.py Misc/NEWS Message-ID: <20110106004939.376D2EE983@mail.python.org> Author: victor.stinner Date: Thu Jan 6 01:49:38 2011 New Revision: 87780 Log: Issue #10492: bdb.Bdb.run() only traces the execution of the code And not the compilation (if the input is a string). Modified: python/branches/py3k/Lib/bdb.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/bdb.py ============================================================================== --- python/branches/py3k/Lib/bdb.py (original) +++ python/branches/py3k/Lib/bdb.py Thu Jan 6 01:49:38 2011 @@ -385,6 +385,8 @@ if locals is None: locals = globals self.reset() + if isinstance(cmd, str): + cmd = compile(cmd, "", "exec") sys.settrace(self.trace_dispatch) try: exec(cmd, globals, locals) Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Thu Jan 6 01:49:38 2011 @@ -30,6 +30,9 @@ Library ------- +- Issue #10492: bdb.Bdb.run() only traces the execution of the code, not the + compilation (if the input is a string). + - Issue #7995: When calling accept() on a socket with a timeout, the returned socket is now always blocking, regardless of the operating system. From python-checkins at python.org Thu Jan 6 03:01:27 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 6 Jan 2011 03:01:27 +0100 (CET) Subject: [Python-checkins] r87781 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110106020127.1FC05EE99B@mail.python.org> Author: raymond.hettinger Date: Thu Jan 6 03:01:26 2011 New Revision: 87781 Log: Add PEP 3333 to whatsnew. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Thu Jan 6 03:01:26 2011 @@ -362,6 +362,37 @@ :pep:`3149` - ABI Version Tagged .so Files PEP written by Barry Warsaw. +PEP 3333: Python Web Server Gateway Interface v1.0.1 +===================================================== + +This informational PEP clarifies how bytes/text issues are to be handled by the +WGSI protocol. The challenge is that string handling in Python 3 is most +conveniently handled with the :class:`str` type eventhough the HTTP protocol +is itself bytes oriented. + +The PEP differentiates so-called *native strings* that are used for +request/response headers and metadata versus *byte strings* which are used for +the bodies of requests and responses. + +The *native strings* are always of type :class:`str` but are restricted to code +points between *u0000* through *u00FF* which are translatable to bytes using +*Latin-1* encoding. These strings are used with :func:`start_response` as +response headers or statuses and must follow :rfc:`2616` with respect to +encoding. That is, they must either be *ISO-8859-1* characters or use +:rfc:`2047` MIME encoding. + +To make the environment accessible using native strings, the :mod:`wsgiref` +module has a new function, :func:`wsgiref.handlers.read_environ` which +transcodes CGI variables from :attr:`os.environ` into native strings and returns +a new dictionary. This function provides a WSGI native string friendly +abstraction which is especially helpful given that the environment variables are +handled differently on various operating systems (native unicode on Windows or +UTF-8 encoded bytes on some Unix installations). + +.. seealso:: + + :pep:`3333` - Python Web Server Gateway Interface v1.0.1 + PEP written by Phillip Eby. Other Language Changes ====================== @@ -1399,7 +1430,7 @@ - bytes input support - non-UTF8 percent encoding of non-ASCII characters Issue 2987 for IPv6 (RFC2732) support in urlparse -.. XXX: Any updates to the WSGI bytes versus text problem? + Multi-threading =============== From python-checkins at python.org Thu Jan 6 03:08:30 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 6 Jan 2011 03:08:30 +0100 (CET) Subject: [Python-checkins] r87782 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110106020830.F18D7EE983@mail.python.org> Author: raymond.hettinger Date: Thu Jan 6 03:08:30 2011 New Revision: 87782 Log: Nits Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Thu Jan 6 03:08:30 2011 @@ -428,10 +428,10 @@ * The :func:`hasattr` function works by calling :func:`getattr` and detecting whether an exception is raised. This technique allows it to detect methods created dynamically by :meth:`__getattr__` or :meth:`__getattribute__` which - would be absent from the class dictionary. Formerly, *hasattr* would catch - any exception, possibly masking genuine errors in those methods. Now, - *hasattr* has been tightened to only catch :exc:`AttributeError` and let - other exceptions pass through. + would otherwise be absent from the class dictionary. Formerly, *hasattr* + would catch any exception, possibly masking genuine errors. Now, *hasattr* + has been tightened to only catch :exc:`AttributeError` and let other + exceptions pass through. (Discovered by Yury Selivanov and fixed by Benjamin Peterson; :issue:`9666`.) @@ -459,7 +459,6 @@ (Added by Antoine Pitrou; :issue:`9757`.) - * Previously it was illegal to delete a name from the local namespace if it occurs as a free variable in a nested block:: From ncoghlan at gmail.com Thu Jan 6 03:45:13 2011 From: ncoghlan at gmail.com (Nick Coghlan) Date: Thu, 6 Jan 2011 12:45:13 +1000 Subject: [Python-checkins] devguide: Add a note about a possible starter project. In-Reply-To: References: Message-ID: On Thu, Jan 6, 2011 at 8:11 AM, brett.cannon wrote: > +.. todo:: > + ? ?See if tempfile or test.support has a context manager that creates and > + ? ?deletes a temp file so as to move off of test.support.TESTFN. Yeah, tempfile.TemporaryFile and friends all support the CM protocol. There's also the tempfile.TemporaryDirectory CM (as of 3.2). Cheers, Nick. -- Nick Coghlan?? |?? ncoghlan at gmail.com?? |?? Brisbane, Australia From solipsis at pitrou.net Thu Jan 6 05:06:57 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Thu, 06 Jan 2011 05:06:57 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r87782): sum=0 Message-ID: py3k results for svn r87782 (hg cset 5798ce539937) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflog15JUVz', '-x'] From python-checkins at python.org Thu Jan 6 06:34:18 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 6 Jan 2011 06:34:18 +0100 (CET) Subject: [Python-checkins] r87783 - in python/branches/py3k/Lib/test: datetimetester.py test_httplib.py test_threading.py test_winreg.py Message-ID: <20110106053418.039DEEE9F7@mail.python.org> Author: raymond.hettinger Date: Thu Jan 6 06:34:17 2011 New Revision: 87783 Log: Issue 10825: Minor updates to the test suite. Modified: python/branches/py3k/Lib/test/datetimetester.py python/branches/py3k/Lib/test/test_httplib.py python/branches/py3k/Lib/test/test_threading.py python/branches/py3k/Lib/test/test_winreg.py Modified: python/branches/py3k/Lib/test/datetimetester.py ============================================================================== --- python/branches/py3k/Lib/test/datetimetester.py (original) +++ python/branches/py3k/Lib/test/datetimetester.py Thu Jan 6 06:34:17 2011 @@ -202,7 +202,7 @@ def test_dst(self): - self.assertEqual(None, timezone.utc.dst(self.DT)) + self.assertIsNone(timezone.utc.dst(self.DT)) with self.assertRaises(TypeError): self.EST.dst('') with self.assertRaises(TypeError): self.EST.dst(5) Modified: python/branches/py3k/Lib/test/test_httplib.py ============================================================================== --- python/branches/py3k/Lib/test/test_httplib.py (original) +++ python/branches/py3k/Lib/test/test_httplib.py Thu Jan 6 06:34:17 2011 @@ -560,7 +560,7 @@ self.conn.request("PUT", "/url", "body") message, f = self.get_headers_and_fp() self.assertEqual("text/plain", message.get_content_type()) - self.assertEqual(None, message.get_charset()) + self.assertIsNone(message.get_charset()) self.assertEqual("4", message.get("content-length")) self.assertEqual(b'body', f.read()) @@ -568,7 +568,7 @@ self.conn.request("PUT", "/url", "body\xc1") message, f = self.get_headers_and_fp() self.assertEqual("text/plain", message.get_content_type()) - self.assertEqual(None, message.get_charset()) + self.assertIsNone(message.get_charset()) self.assertEqual("5", message.get("content-length")) self.assertEqual(b'body\xc1', f.read()) @@ -576,7 +576,7 @@ self.conn.request("PUT", "/url", b"body\xc1") message, f = self.get_headers_and_fp() self.assertEqual("text/plain", message.get_content_type()) - self.assertEqual(None, message.get_charset()) + self.assertIsNone(message.get_charset()) self.assertEqual("5", message.get("content-length")) self.assertEqual(b'body\xc1', f.read()) @@ -587,7 +587,7 @@ self.conn.request("PUT", "/url", f) message, f = self.get_headers_and_fp() self.assertEqual("text/plain", message.get_content_type()) - self.assertEqual(None, message.get_charset()) + self.assertIsNone(message.get_charset()) self.assertEqual("4", message.get("content-length")) self.assertEqual(b'body', f.read()) @@ -598,7 +598,7 @@ self.conn.request("PUT", "/url", f) message, f = self.get_headers_and_fp() self.assertEqual("text/plain", message.get_content_type()) - self.assertEqual(None, message.get_charset()) + self.assertIsNone(message.get_charset()) self.assertEqual("5", message.get("content-length")) self.assertEqual(b'body\xc1', f.read()) Modified: python/branches/py3k/Lib/test/test_threading.py ============================================================================== --- python/branches/py3k/Lib/test/test_threading.py (original) +++ python/branches/py3k/Lib/test/test_threading.py Thu Jan 6 06:34:17 2011 @@ -396,7 +396,7 @@ weak_cyclic_object = weakref.ref(cyclic_object) cyclic_object.thread.join() del cyclic_object - self.assertEqual(None, weak_cyclic_object(), + self.assertIsNone(weak_cyclic_object(), msg=('%d references still around' % sys.getrefcount(weak_cyclic_object()))) @@ -404,7 +404,7 @@ weak_raising_cyclic_object = weakref.ref(raising_cyclic_object) raising_cyclic_object.thread.join() del raising_cyclic_object - self.assertEqual(None, weak_raising_cyclic_object(), + self.assertIsNone(weak_raising_cyclic_object(), msg=('%d references still around' % sys.getrefcount(weak_raising_cyclic_object()))) Modified: python/branches/py3k/Lib/test/test_winreg.py ============================================================================== --- python/branches/py3k/Lib/test/test_winreg.py (original) +++ python/branches/py3k/Lib/test/test_winreg.py Thu Jan 6 06:34:17 2011 @@ -341,8 +341,8 @@ with OpenKey(HKEY_LOCAL_MACHINE, "Software") as key: # HKLM\Software is redirected but not reflected in all OSes self.assertTrue(QueryReflectionKey(key)) - self.assertEqual(None, EnableReflectionKey(key)) - self.assertEqual(None, DisableReflectionKey(key)) + self.assertIsNone(EnableReflectionKey(key)) + self.assertIsNone(DisableReflectionKey(key)) self.assertTrue(QueryReflectionKey(key)) @unittest.skipUnless(HAS_REFLECTION, "OS doesn't support reflection") From python-checkins at python.org Thu Jan 6 08:16:32 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 08:16:32 +0100 (CET) Subject: [Python-checkins] r87784 - python/branches/py3k/Doc/c-api/arg.rst Message-ID: <20110106071632.235C4EE99E@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 08:16:31 2011 New Revision: 87784 Log: Issue #10840: make it explicit that "s*" and friends provide contiguous memory. Modified: python/branches/py3k/Doc/c-api/arg.rst Modified: python/branches/py3k/Doc/c-api/arg.rst ============================================================================== --- python/branches/py3k/Doc/c-api/arg.rst (original) +++ python/branches/py3k/Doc/c-api/arg.rst Thu Jan 6 08:16:31 2011 @@ -30,9 +30,10 @@ Strings and buffers ------------------- -These formats do not expect you to provide raw storage for the returned string -or bytes. Also, you won't have to release any memory yourself, except with -the ``es``, ``es#``, ``et`` and ``et#`` formats. +These formats allow to access an object as a contiguous chunk of memory. +You don't have to provide raw storage for the returned unicode or bytes +area. Also, you won't have to release any memory yourself, except with the +``es``, ``es#``, ``et`` and ``et#`` formats. However, when a :c:type:`Py_buffer` structure gets filled, the underlying buffer is locked so that the caller can subsequently use the buffer even From python-checkins at python.org Thu Jan 6 08:17:30 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 08:17:30 +0100 (CET) Subject: [Python-checkins] r87785 - in python/branches/release31-maint: Doc/c-api/arg.rst Message-ID: <20110106071730.5C642EE99E@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 08:17:30 2011 New Revision: 87785 Log: Merged revisions 87784 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87784 | antoine.pitrou | 2011-01-06 08:16:31 +0100 (jeu., 06 janv. 2011) | 3 lines Issue #10840: make it explicit that "s*" and friends provide contiguous memory. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Doc/c-api/arg.rst Modified: python/branches/release31-maint/Doc/c-api/arg.rst ============================================================================== --- python/branches/release31-maint/Doc/c-api/arg.rst (original) +++ python/branches/release31-maint/Doc/c-api/arg.rst Thu Jan 6 08:17:30 2011 @@ -30,9 +30,10 @@ Strings and buffers ------------------- -These formats do not expect you to provide raw storage for the returned string -or bytes. Also, you won't have to release any memory yourself, except with -the ``es``, ``es#``, ``et`` and ``et#`` formats. +These formats allow to access an object as a contiguous chunk of memory. +You don't have to provide raw storage for the returned unicode or bytes +area. Also, you won't have to release any memory yourself, except with the +``es``, ``es#``, ``et`` and ``et#`` formats. However, when a :ctype:`Py_buffer` structure gets filled, the underlying buffer is locked so that the caller can subsequently use the buffer even From python-checkins at python.org Thu Jan 6 10:05:22 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 10:05:22 +0100 (CET) Subject: [Python-checkins] r87786 - in python/branches/py3k: Lib/test/test_timeout.py Misc/NEWS Message-ID: <20110106090522.83D6DEE995@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 10:05:22 2011 New Revision: 87786 Log: Issue #1677694: Refactor and improve test_timeout. Original patch by Bj?rn Lindqvist. Modified: python/branches/py3k/Lib/test/test_timeout.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/test/test_timeout.py ============================================================================== --- python/branches/py3k/Lib/test/test_timeout.py (original) +++ python/branches/py3k/Lib/test/test_timeout.py Thu Jan 6 10:05:22 2011 @@ -7,6 +7,7 @@ skip_expected = not support.is_resource_enabled('network') import time +import errno import socket @@ -101,8 +102,29 @@ def setUp(self): raise NotImplementedError() - def tearDown(self): - self.sock.close() + tearDown = setUp + + def _sock_operation(self, count, timeout, method, *args): + """ + Test the specified socket method. + + The method is run at most `count` times and must raise a socket.timeout + within `timeout` + self.fuzz seconds. + """ + self.sock.settimeout(timeout) + method = getattr(self.sock, method) + for i in range(count): + t1 = time.time() + try: + method(*args) + except socket.timeout as e: + delta = time.time() - t1 + break + else: + self.fail('socket.timeout was not raised') + # These checks should account for timing unprecision + self.assertLess(delta, timeout + self.fuzz) + self.assertGreater(delta, timeout - 1.0) class TCPTimeoutTestCase(TimeoutTestCase): @@ -112,6 +134,9 @@ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.addr_remote = ('www.python.org.', 80) + def tearDown(self): + self.sock.close() + def testConnectTimeout(self): # Choose a private address that is unlikely to exist to prevent # failures due to the connect succeeding before the timeout. @@ -119,68 +144,48 @@ # with the connect time. This avoids failing the assertion that # the timeout occurred fast enough. addr = ('10.0.0.0', 12345) - - # Test connect() timeout - _timeout = 0.001 - self.sock.settimeout(_timeout) - - _t1 = time.time() - self.assertRaises(socket.error, self.sock.connect, addr) - _t2 = time.time() - - _delta = abs(_t1 - _t2) - self.assertTrue(_delta < _timeout + self.fuzz, - "timeout (%g) is more than %g seconds more than expected (%g)" - %(_delta, self.fuzz, _timeout)) + with support.transient_internet(addr[0]): + self._sock_operation(1, 0.001, 'connect', addr) def testRecvTimeout(self): # Test recv() timeout - _timeout = 0.02 - with support.transient_internet(self.addr_remote[0]): self.sock.connect(self.addr_remote) - self.sock.settimeout(_timeout) - - _t1 = time.time() - self.assertRaises(socket.timeout, self.sock.recv, 1024) - _t2 = time.time() - - _delta = abs(_t1 - _t2) - self.assertTrue(_delta < _timeout + self.fuzz, - "timeout (%g) is %g seconds more than expected (%g)" - %(_delta, self.fuzz, _timeout)) + self._sock_operation(1, 1.5, 'recv', 1024) def testAcceptTimeout(self): # Test accept() timeout - _timeout = 2 - self.sock.settimeout(_timeout) - # Prevent "Address already in use" socket exceptions support.bind_port(self.sock, self.localhost) self.sock.listen(5) - - _t1 = time.time() - self.assertRaises(socket.error, self.sock.accept) - _t2 = time.time() - - _delta = abs(_t1 - _t2) - self.assertTrue(_delta < _timeout + self.fuzz, - "timeout (%g) is %g seconds more than expected (%g)" - %(_delta, self.fuzz, _timeout)) + self._sock_operation(1, 1.5, 'accept') def testSend(self): # Test send() timeout - # couldn't figure out how to test it - pass + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as serv: + support.bind_port(serv, self.localhost) + serv.listen(5) + self.sock.connect(serv.getsockname()) + # Send a lot of data in order to bypass buffering in the TCP stack. + self._sock_operation(100, 1.5, 'send', b"X" * 200000) def testSendto(self): # Test sendto() timeout - # couldn't figure out how to test it - pass + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as serv: + support.bind_port(serv, self.localhost) + serv.listen(5) + self.sock.connect(serv.getsockname()) + # The address argument is ignored since we already connected. + self._sock_operation(100, 1.5, 'sendto', b"X" * 200000, + serv.getsockname()) def testSendall(self): # Test sendall() timeout - # couldn't figure out how to test it - pass + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as serv: + support.bind_port(serv, self.localhost) + serv.listen(5) + self.sock.connect(serv.getsockname()) + # Send a lot of data in order to bypass buffering in the TCP stack. + self._sock_operation(100, 1.5, 'sendall', b"X" * 200000) class UDPTimeoutTestCase(TimeoutTestCase): @@ -189,21 +194,14 @@ def setUp(self): self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + def tearDown(self): + self.sock.close() + def testRecvfromTimeout(self): # Test recvfrom() timeout - _timeout = 2 - self.sock.settimeout(_timeout) # Prevent "Address already in use" socket exceptions support.bind_port(self.sock, self.localhost) - - _t1 = time.time() - self.assertRaises(socket.error, self.sock.recvfrom, 8192) - _t2 = time.time() - - _delta = abs(_t1 - _t2) - self.assertTrue(_delta < _timeout + self.fuzz, - "timeout (%g) is %g seconds more than expected (%g)" - %(_delta, self.fuzz, _timeout)) + self._sock_operation(1, 1.5, 'recvfrom', 1024) def test_main(): Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Thu Jan 6 10:05:22 2011 @@ -159,6 +159,9 @@ Tests ----- +- Issue #1677694: Refactor and improve test_timeout. Original patch by + Bj?rn Lindqvist. + - Issue #5485: Add tests for the UseForeignDTD method of expat parser objects. Patch by Jean-Paul Calderone and Sandro Tosi. From python-checkins at python.org Thu Jan 6 10:15:45 2011 From: python-checkins at python.org (georg.brandl) Date: Thu, 6 Jan 2011 10:15:45 +0100 (CET) Subject: [Python-checkins] r87787 - python/branches/py3k/Lib/email/charset.py Message-ID: <20110106091545.60F56EE9A9@mail.python.org> Author: georg.brandl Date: Thu Jan 6 10:15:45 2011 New Revision: 87787 Log: Remove doc for nonexisting parameter. Modified: python/branches/py3k/Lib/email/charset.py Modified: python/branches/py3k/Lib/email/charset.py ============================================================================== --- python/branches/py3k/Lib/email/charset.py (original) +++ python/branches/py3k/Lib/email/charset.py Thu Jan 6 10:15:45 2011 @@ -294,7 +294,7 @@ """Header-encode a string by converting it first to bytes. This is similar to `header_encode()` except that the string is fit - into maximum line lengths as given by the arguments. + into maximum line lengths as given by the argument. :param string: A unicode string for the header. It must be possible to encode this string to bytes using the character set's @@ -305,8 +305,6 @@ and should never be exhausted. The maximum line lengths should not count the RFC 2047 chrome. These line lengths are only a hint; the splitter does the best it can. - :param firstmaxlen: The maximum line length of the first line. If - None (the default), then `maxlen` is used for the first line. :return: Lines of encoded strings, each with RFC 2047 chrome. """ # See which encoding we should use. From python-checkins at python.org Thu Jan 6 10:23:19 2011 From: python-checkins at python.org (georg.brandl) Date: Thu, 6 Jan 2011 10:23:19 +0100 (CET) Subject: [Python-checkins] r87788 - in python/branches/py3k/Doc/library: functional.rst index.rst numeric.rst Message-ID: <20110106092319.98F71EE9A9@mail.python.org> Author: georg.brandl Date: Thu Jan 6 10:23:19 2011 New Revision: 87788 Log: itertools, operator and functools are not really "numeric" modules; move them into their own "functional" chapter. Added: python/branches/py3k/Doc/library/functional.rst Modified: python/branches/py3k/Doc/library/index.rst python/branches/py3k/Doc/library/numeric.rst Added: python/branches/py3k/Doc/library/functional.rst ============================================================================== --- (empty file) +++ python/branches/py3k/Doc/library/functional.rst Thu Jan 6 10:23:19 2011 @@ -0,0 +1,15 @@ +****************************** +Functional Programming Modules +****************************** + +The modules described in this chapter provide functions and classes that support +a functional programming style, and general operations on callables. + +The following modules are documented in this chapter: + + +.. toctree:: + + itertools.rst + functools.rst + operator.rst Modified: python/branches/py3k/Doc/library/index.rst ============================================================================== --- python/branches/py3k/Doc/library/index.rst (original) +++ python/branches/py3k/Doc/library/index.rst Thu Jan 6 10:23:19 2011 @@ -49,6 +49,7 @@ strings.rst datatypes.rst numeric.rst + functional.rst filesys.rst persistence.rst archiving.rst Modified: python/branches/py3k/Doc/library/numeric.rst ============================================================================== --- python/branches/py3k/Doc/library/numeric.rst (original) +++ python/branches/py3k/Doc/library/numeric.rst Thu Jan 6 10:23:19 2011 @@ -23,6 +23,3 @@ decimal.rst fractions.rst random.rst - itertools.rst - functools.rst - operator.rst From python-checkins at python.org Thu Jan 6 10:23:57 2011 From: python-checkins at python.org (georg.brandl) Date: Thu, 6 Jan 2011 10:23:57 +0100 (CET) Subject: [Python-checkins] r87789 - in python/branches/py3k/Doc: glossary.rst library/csv.rst library/email.charset.rst library/email.header.rst library/inspect.rst library/operator.rst library/string.rst reference/compound_stmts.rst reference/executionmodel.rst Message-ID: <20110106092357.31C9CEE9A9@mail.python.org> Author: georg.brandl Date: Thu Jan 6 10:23:56 2011 New Revision: 87789 Log: Fix various issues (mostly Python 2 relics) found by Jacques Ducasse. Modified: python/branches/py3k/Doc/glossary.rst python/branches/py3k/Doc/library/csv.rst python/branches/py3k/Doc/library/email.charset.rst python/branches/py3k/Doc/library/email.header.rst python/branches/py3k/Doc/library/inspect.rst python/branches/py3k/Doc/library/operator.rst python/branches/py3k/Doc/library/string.rst python/branches/py3k/Doc/reference/compound_stmts.rst python/branches/py3k/Doc/reference/executionmodel.rst Modified: python/branches/py3k/Doc/glossary.rst ============================================================================== --- python/branches/py3k/Doc/glossary.rst (original) +++ python/branches/py3k/Doc/glossary.rst Thu Jan 6 10:23:56 2011 @@ -339,12 +339,12 @@ iterator An object representing a stream of data. Repeated calls to the iterator's - :meth:`__next__` (or passing it to the built-in function :func:`next`) - method return successive items in the stream. When no more data are - available a :exc:`StopIteration` exception is raised instead. At this + :meth:`__next__` method (or passing it to the built-in function + :func:`next`) return successive items in the stream. When no more data + are available a :exc:`StopIteration` exception is raised instead. At this point, the iterator object is exhausted and any further calls to its - :meth:`next` method just raise :exc:`StopIteration` again. Iterators are - required to have an :meth:`__iter__` method that returns the iterator + :meth:`__next__` method just raise :exc:`StopIteration` again. Iterators + are required to have an :meth:`__iter__` method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a Modified: python/branches/py3k/Doc/library/csv.rst ============================================================================== --- python/branches/py3k/Doc/library/csv.rst (original) +++ python/branches/py3k/Doc/library/csv.rst Thu Jan 6 10:23:56 2011 @@ -50,7 +50,7 @@ Return a reader object which will iterate over lines in the given *csvfile*. *csvfile* can be any object which supports the :term:`iterator` protocol and returns a - string each time its :meth:`!next` method is called --- :term:`file objects + string each time its :meth:`!__next__` method is called --- :term:`file objects ` and list objects are both suitable. If *csvfile* is a file object, it should be opened with ``newline=''``. [#]_ An optional *dialect* parameter can be given which is used to define a set of parameters Modified: python/branches/py3k/Doc/library/email.charset.rst ============================================================================== --- python/branches/py3k/Doc/library/email.charset.rst (original) +++ python/branches/py3k/Doc/library/email.charset.rst Thu Jan 6 10:23:56 2011 @@ -142,12 +142,6 @@ it is *input_charset*. - .. method:: encoded_header_len() - - Return the length of the encoded header string, properly calculating for - quoted-printable or base64 encoding. - - .. method:: header_encode(string) Header-encode the string *string*. @@ -156,6 +150,16 @@ *header_encoding* attribute. + .. method:: header_encode_lines(string, maxlengths) + + Header-encode a *string* by converting it first to bytes. + + This is similar to :meth:`header_encode` except that the string is fit + into maximum line lengths as given by the argument *maxlengths*, which + must be an iterator: each element returned from this iterator will provide + the next maximum line length. + + .. method:: body_encode(string) Body-encode the string *string*. Modified: python/branches/py3k/Doc/library/email.header.rst ============================================================================== --- python/branches/py3k/Doc/library/email.header.rst (original) +++ python/branches/py3k/Doc/library/email.header.rst Thu Jan 6 10:23:56 2011 @@ -130,14 +130,10 @@ .. method:: __str__() - A synonym for :meth:`Header.encode`. Useful for ``str(aHeader)``. - - - .. method:: __unicode__() - A helper for :class:`str`'s :func:`encode` method. Returns the header as a Unicode string. + .. method:: __eq__(other) This method allows you to compare two :class:`Header` instances for Modified: python/branches/py3k/Doc/library/inspect.rst ============================================================================== --- python/branches/py3k/Doc/library/inspect.rst (original) +++ python/branches/py3k/Doc/library/inspect.rst Thu Jan 6 10:23:56 2011 @@ -176,17 +176,16 @@ .. function:: getmoduleinfo(path) - Returns a :term:`named tuple` ``ModuleInfo(name, suffix, mode, - module_type)`` of values that describe how Python will interpret the file - identified by *path* if it is a module, or ``None`` if it would not be - identified as a module. The return tuple is ``(name, suffix, mode, mtype)``, - where *name* is the name of the module without the name of any enclosing - package, *suffix* is the trailing part of the file name (which may not be a - dot-delimited extension), *mode* is the :func:`open` mode that would be used - (``'r'`` or ``'rb'``), and *mtype* is an integer giving the type of the - module. *mtype* will have a value which can be compared to the constants - defined in the :mod:`imp` module; see the documentation for that module for - more information on module types. + Returns a :term:`named tuple` ``ModuleInfo(name, suffix, mode, module_type)`` + of values that describe how Python will interpret the file identified by + *path* if it is a module, or ``None`` if it would not be identified as a + module. In that tuple, *name* is the name of the module without the name of + any enclosing package, *suffix* is the trailing part of the file name (which + may not be a dot-delimited extension), *mode* is the :func:`open` mode that + would be used (``'r'`` or ``'rb'``), and *module_type* is an integer giving + the type of the module. *module_type* will have a value which can be + compared to the constants defined in the :mod:`imp` module; see the + documentation for that module for more information on module types. .. function:: getmodulename(path) @@ -391,12 +390,12 @@ .. function:: getargspec(func) Get the names and default values of a Python function's arguments. A - :term:`named tuple` ``ArgSpec(args, varargs, keywords, - defaults)`` is returned. *args* is a list of - the argument names. *varargs* and *varkw* are the names of the ``*`` and - ``**`` arguments or ``None``. *defaults* is a tuple of default argument - values or None if there are no default arguments; if this tuple has *n* - elements, they correspond to the last *n* elements listed in *args*. + :term:`named tuple` ``ArgSpec(args, varargs, keywords, defaults)`` is + returned. *args* is a list of the argument names. *varargs* and *keywords* + are the names of the ``*`` and ``**`` arguments or ``None``. *defaults* is a + tuple of default argument values or None if there are no default arguments; + if this tuple has *n* elements, they correspond to the last *n* elements + listed in *args*. .. deprecated:: 3.0 Use :func:`getfullargspec` instead, which provides information about @@ -425,8 +424,8 @@ Get information about arguments passed into a particular frame. A :term:`named tuple` ``ArgInfo(args, varargs, keywords, locals)`` is - returned. *args* is a list of the argument names. *varargs* and *varkw* are - the names of the ``*`` and ``**`` arguments or ``None``. *locals* is the + returned. *args* is a list of the argument names. *varargs* and *keywords* + are the names of the ``*`` and ``**`` arguments or ``None``. *locals* is the locals dictionary of the given frame. Modified: python/branches/py3k/Doc/library/operator.rst ============================================================================== --- python/branches/py3k/Doc/library/operator.rst (original) +++ python/branches/py3k/Doc/library/operator.rst Thu Jan 6 10:23:56 2011 @@ -19,8 +19,7 @@ trailing ``__`` are also provided for convenience. The functions fall into categories that perform object comparisons, logical -operations, mathematical operations, sequence operations, and abstract type -tests. +operations, mathematical operations and sequence operations. The object comparison functions are useful for all objects, and are named after the rich comparison operators they support: Modified: python/branches/py3k/Doc/library/string.rst ============================================================================== --- python/branches/py3k/Doc/library/string.rst (original) +++ python/branches/py3k/Doc/library/string.rst Thu Jan 6 10:23:56 2011 @@ -5,17 +5,11 @@ :synopsis: Common string operations. -.. index:: module: re +.. seealso:: -The :mod:`string` module contains a number of useful constants and classes -for string formatting. In addition, Python's built-in string classes -support the sequence type methods described in the :ref:`typesseq` -section, and also the string-specific methods described in the -:ref:`string-methods` section. To output formatted strings, see the -:ref:`string-formatting` section. Also, see the :mod:`re` module for -string functions based on regular expressions. + :ref:`typesseq` -.. seealso:: + :ref:`string-methods` Latest version of the :source:`string module Python source code ` Modified: python/branches/py3k/Doc/reference/compound_stmts.rst ============================================================================== --- python/branches/py3k/Doc/reference/compound_stmts.rst (original) +++ python/branches/py3k/Doc/reference/compound_stmts.rst Thu Jan 6 10:23:56 2011 @@ -285,12 +285,11 @@ Before an except clause's suite is executed, details about the exception are stored in the :mod:`sys` module and can be access via :func:`sys.exc_info`. -:func:`sys.exc_info` returns a 3-tuple consisting of: ``exc_type``, the -exception class; ``exc_value``, the exception instance; ``exc_traceback``, a -traceback object (see section :ref:`types`) identifying the point in the program -where the exception occurred. :func:`sys.exc_info` values are restored to their -previous values (before the call) when returning from a function that handled an -exception. +:func:`sys.exc_info` returns a 3-tuple consisting of the exception class, the +exception instance and a traceback object (see section :ref:`types`) identifying +the point in the program where the exception occurred. :func:`sys.exc_info` +values are restored to their previous values (before the call) when returning +from a function that handled an exception. .. index:: keyword: else Modified: python/branches/py3k/Doc/reference/executionmodel.rst ============================================================================== --- python/branches/py3k/Doc/reference/executionmodel.rst (original) +++ python/branches/py3k/Doc/reference/executionmodel.rst Thu Jan 6 10:23:56 2011 @@ -141,9 +141,9 @@ The namespace for a module is automatically created the first time a module is imported. The main module for a script is always called :mod:`__main__`. -The global statement has the same scope as a name binding operation in the same -block. If the nearest enclosing scope for a free variable contains a global -statement, the free variable is treated as a global. +The :keyword:`global` statement has the same scope as a name binding operation +in the same block. If the nearest enclosing scope for a free variable contains +a global statement, the free variable is treated as a global. A class definition is an executable statement that may use and define names. These references follow the normal rules for name resolution. The namespace of From python-checkins at python.org Thu Jan 6 10:25:27 2011 From: python-checkins at python.org (georg.brandl) Date: Thu, 6 Jan 2011 10:25:27 +0100 (CET) Subject: [Python-checkins] r87790 - python/branches/py3k/Doc/ACKS.txt Message-ID: <20110106092527.D3DEAEE984@mail.python.org> Author: georg.brandl Date: Thu Jan 6 10:25:27 2011 New Revision: 87790 Log: Add acks where acks are due. Modified: python/branches/py3k/Doc/ACKS.txt Modified: python/branches/py3k/Doc/ACKS.txt ============================================================================== --- python/branches/py3k/Doc/ACKS.txt (original) +++ python/branches/py3k/Doc/ACKS.txt Thu Jan 6 10:25:27 2011 @@ -47,6 +47,7 @@ * L. Peter Deutsch * Robert Donohue * Fred L. Drake, Jr. + * Jacques Ducasse * Josip Dzolonga * Jeff Epler * Michael Ernst From python-checkins at python.org Thu Jan 6 11:05:26 2011 From: python-checkins at python.org (georg.brandl) Date: Thu, 6 Jan 2011 11:05:26 +0100 (CET) Subject: [Python-checkins] r87791 - in python/branches/py3k/Mac: IDLE/IDLE.app/Contents/Info.plist PythonLauncher/Info.plist.in Resources/app/Info.plist.in Resources/framework/Info.plist.in Message-ID: <20110106100526.AAEA8EE9A9@mail.python.org> Author: georg.brandl Date: Thu Jan 6 11:05:26 2011 New Revision: 87791 Log: #10844: update copyright years in Mac plists. Modified: python/branches/py3k/Mac/IDLE/IDLE.app/Contents/Info.plist python/branches/py3k/Mac/PythonLauncher/Info.plist.in python/branches/py3k/Mac/Resources/app/Info.plist.in python/branches/py3k/Mac/Resources/framework/Info.plist.in Modified: python/branches/py3k/Mac/IDLE/IDLE.app/Contents/Info.plist ============================================================================== --- python/branches/py3k/Mac/IDLE/IDLE.app/Contents/Info.plist (original) +++ python/branches/py3k/Mac/IDLE/IDLE.app/Contents/Info.plist Thu Jan 6 11:05:26 2011 @@ -36,7 +36,7 @@ CFBundleExecutable IDLE CFBundleGetInfoString - %version%, ? 2001-2008 Python Software Foundation + %version%, ? 2001-2011 Python Software Foundation CFBundleIconFile IDLE.icns CFBundleIdentifier Modified: python/branches/py3k/Mac/PythonLauncher/Info.plist.in ============================================================================== --- python/branches/py3k/Mac/PythonLauncher/Info.plist.in (original) +++ python/branches/py3k/Mac/PythonLauncher/Info.plist.in Thu Jan 6 11:05:26 2011 @@ -40,7 +40,7 @@ CFBundleExecutable PythonLauncher CFBundleGetInfoString - %VERSION%, ? 2001-2008 Python Software Foundation + %VERSION%, ? 2001-2011 Python Software Foundation CFBundleIconFile PythonLauncher.icns CFBundleIdentifier Modified: python/branches/py3k/Mac/Resources/app/Info.plist.in ============================================================================== --- python/branches/py3k/Mac/Resources/app/Info.plist.in (original) +++ python/branches/py3k/Mac/Resources/app/Info.plist.in Thu Jan 6 11:05:26 2011 @@ -20,7 +20,7 @@ CFBundleExecutable Python CFBundleGetInfoString - %version%, (c) 2004-2010 Python Software Foundation. + %version%, (c) 2004-2011 Python Software Foundation. CFBundleHelpBookFolder Documentation @@ -37,7 +37,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - %version%, (c) 2004-2010 Python Software Foundation. + %version%, (c) 2004-2011 Python Software Foundation. CFBundleName Python CFBundlePackageType @@ -55,6 +55,6 @@ NSAppleScriptEnabled NSHumanReadableCopyright - (c) 2004 Python Software Foundation. + (c) 2011 Python Software Foundation. Modified: python/branches/py3k/Mac/Resources/framework/Info.plist.in ============================================================================== --- python/branches/py3k/Mac/Resources/framework/Info.plist.in (original) +++ python/branches/py3k/Mac/Resources/framework/Info.plist.in Thu Jan 6 11:05:26 2011 @@ -17,9 +17,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - %VERSION%, (c) 2004-2008 Python Software Foundation. + %VERSION%, (c) 2004-2011 Python Software Foundation. CFBundleLongVersionString - %VERSION%, (c) 2004-2008 Python Software Foundation. + %VERSION%, (c) 2004-2011 Python Software Foundation. CFBundleSignature ???? CFBundleVersion From python-checkins at python.org Thu Jan 6 17:31:28 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 17:31:28 +0100 (CET) Subject: [Python-checkins] r87792 - in python/branches/py3k/Doc: glossary.rst library/threading.rst Message-ID: <20110106163128.EA374EE995@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 17:31:28 2011 New Revision: 87792 Log: Elaborate about the GIL. Modified: python/branches/py3k/Doc/glossary.rst python/branches/py3k/Doc/library/threading.rst Modified: python/branches/py3k/Doc/glossary.rst ============================================================================== --- python/branches/py3k/Doc/glossary.rst (original) +++ python/branches/py3k/Doc/glossary.rst Thu Jan 6 17:31:28 2011 @@ -102,9 +102,10 @@ See :pep:`343`. CPython - The canonical implementation of the Python programming language. The - term "CPython" is used in contexts when necessary to distinguish this - implementation from others such as Jython or IronPython. + The canonical implementation of the Python programming language, as + distributed on `python.org `_. The term "CPython" + is used when necessary to distinguish this implementation from others + such as Jython or IronPython. decorator A function returning another function, usually applied as a function @@ -263,16 +264,25 @@ See :term:`global interpreter lock`. global interpreter lock - The lock used by Python threads to assure that only one thread - executes in the :term:`CPython` :term:`virtual machine` at a time. - This simplifies the CPython implementation by assuring that no two - processes can access the same memory at the same time. Locking the - entire interpreter makes it easier for the interpreter to be - multi-threaded, at the expense of much of the parallelism afforded by - multi-processor machines. Efforts have been made in the past to - create a "free-threaded" interpreter (one which locks shared data at a - much finer granularity), but so far none have been successful because - performance suffered in the common single-processor case. + The mechanism used by the :term:`CPython` interpreter to assure that + only one thread executes Python :term:`bytecode` at a time. + This simplifies the CPython implementation by making the object model + (including critical built-in types such as :class:`dict`) implicitly + safe against concurrent access. Locking the entire interpreter + makes it easier for the interpreter to be multi-threaded, at the + expense of much of the parallelism afforded by multi-processor + machines. + + However, some extension modules, either standard or third-party, + are designed so as to release the GIL when doing computationally-intensive + tasks such as compression or hashing. Also, the GIL is always released + when doing I/O. + + Past efforts to create a "free-threaded" interpreter (one which locks + shared data at a much finer granularity) have not been successful + because performance suffered in the common single-processor case. It + is believed that overcoming this performance issue would make the + implementation much more complicated and therefore costlier to maintain. hashable An object is *hashable* if it has a hash value which never changes during Modified: python/branches/py3k/Doc/library/threading.rst ============================================================================== --- python/branches/py3k/Doc/library/threading.rst (original) +++ python/branches/py3k/Doc/library/threading.rst Thu Jan 6 17:31:28 2011 @@ -17,11 +17,23 @@ methods and functions in this module in the Python 2.x series are still supported by this module. +.. impl-detail:: + + Due to the :term:`Global Interpreter Lock`, in CPython only one thread + can execute Python code at once (even though certain performance-oriented + libraries might overcome this limitation). + If you want your application to make better of use of the computational + resources of multi-core machines, you are advised to use + :mod:`multiprocessing` or :class:`concurrent.futures.ProcessPoolExecutor`. + However, threading is still an appropriate model if you want to run + multiple I/O-bound tasks simultaneously. + .. seealso:: Latest version of the :source:`threading module Python source code ` + This module defines the following functions and objects: From python-checkins at python.org Thu Jan 6 17:34:50 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 17:34:50 +0100 (CET) Subject: [Python-checkins] r87793 - in python/branches/release31-maint: Doc/glossary.rst Doc/library/threading.rst Message-ID: <20110106163450.AD016EE99C@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 17:34:50 2011 New Revision: 87793 Log: Merged revisions 87792 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87792 | antoine.pitrou | 2011-01-06 17:31:28 +0100 (jeu., 06 janv. 2011) | 3 lines Elaborate about the GIL. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Doc/glossary.rst python/branches/release31-maint/Doc/library/threading.rst Modified: python/branches/release31-maint/Doc/glossary.rst ============================================================================== --- python/branches/release31-maint/Doc/glossary.rst (original) +++ python/branches/release31-maint/Doc/glossary.rst Thu Jan 6 17:34:50 2011 @@ -99,9 +99,10 @@ See :pep:`343`. CPython - The canonical implementation of the Python programming language. The - term "CPython" is used in contexts when necessary to distinguish this - implementation from others such as Jython or IronPython. + The canonical implementation of the Python programming language, as + distributed on `python.org `_. The term "CPython" + is used when necessary to distinguish this implementation from others + such as Jython or IronPython. decorator A function returning another function, usually applied as a function @@ -258,16 +259,25 @@ See :term:`global interpreter lock`. global interpreter lock - The lock used by Python threads to assure that only one thread - executes in the :term:`CPython` :term:`virtual machine` at a time. - This simplifies the CPython implementation by assuring that no two - processes can access the same memory at the same time. Locking the - entire interpreter makes it easier for the interpreter to be - multi-threaded, at the expense of much of the parallelism afforded by - multi-processor machines. Efforts have been made in the past to - create a "free-threaded" interpreter (one which locks shared data at a - much finer granularity), but so far none have been successful because - performance suffered in the common single-processor case. + The mechanism used by the :term:`CPython` interpreter to assure that + only one thread executes Python :term:`bytecode` at a time. + This simplifies the CPython implementation by making the object model + (including critical built-in types such as :class:`dict`) implicitly + safe against concurrent access. Locking the entire interpreter + makes it easier for the interpreter to be multi-threaded, at the + expense of much of the parallelism afforded by multi-processor + machines. + + However, some extension modules, either standard or third-party, + are designed so as to release the GIL when doing computationally-intensive + tasks such as compression or hashing. Also, the GIL is always released + when doing I/O. + + Past efforts to create a "free-threaded" interpreter (one which locks + shared data at a much finer granularity) have not been successful + because performance suffered in the common single-processor case. It + is believed that overcoming this performance issue would make the + implementation much more complicated and therefore costlier to maintain. hashable An object is *hashable* if it has a hash value which never changes during Modified: python/branches/release31-maint/Doc/library/threading.rst ============================================================================== --- python/branches/release31-maint/Doc/library/threading.rst (original) +++ python/branches/release31-maint/Doc/library/threading.rst Thu Jan 6 17:34:50 2011 @@ -17,6 +17,17 @@ methods and functions in this module in the Python 2.x series are still supported by this module. +.. impl-detail:: + + Due to the :term:`Global Interpreter Lock`, in CPython only one thread + can execute Python code at once (even though certain performance-oriented + libraries might overcome this limitation). + If you want your application to make better of use of the computational + resources of multi-core machines, you are advised to use + :mod:`multiprocessing`. However, threading is still an appropriate model + if you want to run multiple I/O-bound tasks simultaneously. + + This module defines the following functions and objects: From python-checkins at python.org Thu Jan 6 17:35:15 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 17:35:15 +0100 (CET) Subject: [Python-checkins] r87794 - in python/branches/release27-maint: Doc/glossary.rst Doc/library/threading.rst Message-ID: <20110106163515.1AA8BEE9E1@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 17:35:14 2011 New Revision: 87794 Log: Merged revisions 87792 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87792 | antoine.pitrou | 2011-01-06 17:31:28 +0100 (jeu., 06 janv. 2011) | 3 lines Elaborate about the GIL. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Doc/glossary.rst python/branches/release27-maint/Doc/library/threading.rst Modified: python/branches/release27-maint/Doc/glossary.rst ============================================================================== --- python/branches/release27-maint/Doc/glossary.rst (original) +++ python/branches/release27-maint/Doc/glossary.rst Thu Jan 6 17:35:14 2011 @@ -106,9 +106,10 @@ See :pep:`343`. CPython - The canonical implementation of the Python programming language. The - term "CPython" is used in contexts when necessary to distinguish this - implementation from others such as Jython or IronPython. + The canonical implementation of the Python programming language, as + distributed on `python.org `_. The term "CPython" + is used when necessary to distinguish this implementation from others + such as Jython or IronPython. decorator A function returning another function, usually applied as a function @@ -253,16 +254,25 @@ See :term:`global interpreter lock`. global interpreter lock - The lock used by Python threads to assure that only one thread - executes in the :term:`CPython` :term:`virtual machine` at a time. - This simplifies the CPython implementation by assuring that no two - processes can access the same memory at the same time. Locking the - entire interpreter makes it easier for the interpreter to be - multi-threaded, at the expense of much of the parallelism afforded by - multi-processor machines. Efforts have been made in the past to - create a "free-threaded" interpreter (one which locks shared data at a - much finer granularity), but so far none have been successful because - performance suffered in the common single-processor case. + The mechanism used by the :term:`CPython` interpreter to assure that + only one thread executes Python :term:`bytecode` at a time. + This simplifies the CPython implementation by making the object model + (including critical built-in types such as :class:`dict`) implicitly + safe against concurrent access. Locking the entire interpreter + makes it easier for the interpreter to be multi-threaded, at the + expense of much of the parallelism afforded by multi-processor + machines. + + However, some extension modules, either standard or third-party, + are designed so as to release the GIL when doing computationally-intensive + tasks such as compression or hashing. Also, the GIL is always released + when doing I/O. + + Past efforts to create a "free-threaded" interpreter (one which locks + shared data at a much finer granularity) have not been successful + because performance suffered in the common single-processor case. It + is believed that overcoming this performance issue would make the + implementation much more complicated and therefore costlier to maintain. hashable An object is *hashable* if it has a hash value which never changes during Modified: python/branches/release27-maint/Doc/library/threading.rst ============================================================================== --- python/branches/release27-maint/Doc/library/threading.rst (original) +++ python/branches/release27-maint/Doc/library/threading.rst Thu Jan 6 17:35:14 2011 @@ -26,11 +26,22 @@ Starting with Python 2.5, several Thread methods raise :exc:`RuntimeError` instead of :exc:`AssertionError` if called erroneously. +.. impl-detail:: + + Due to the :term:`Global Interpreter Lock`, in CPython only one thread + can execute Python code at once (even though certain performance-oriented + libraries might overcome this limitation). + If you want your application to make better of use of the computational + resources of multi-core machines, you are advised to use + :mod:`multiprocessing`. However, threading is still an appropriate model + if you want to run multiple I/O-bound tasks simultaneously. + .. seealso:: Latest version of the `threading module Python source code `_ + This module defines the following functions and objects: .. function:: active_count() From python-checkins at python.org Thu Jan 6 17:45:25 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Thu, 6 Jan 2011 17:45:25 +0100 (CET) Subject: [Python-checkins] r87795 - python/branches/py3k/Modules/timemodule.c Message-ID: <20110106164525.CCC87EE9BA@mail.python.org> Author: alexander.belopolsky Date: Thu Jan 6 17:45:25 2011 New Revision: 87795 Log: Use PyOS_snprintf for better portability. Modified: python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Thu Jan 6 17:45:25 2011 @@ -605,11 +605,11 @@ char buf[20]; /* 'Sun Sep 16 01:03:52\0' */ int n; - n = snprintf(buf, sizeof(buf), "%.3s %.3s%3d %.2d:%.2d:%.2d", - wday_name[timeptr->tm_wday], - mon_name[timeptr->tm_mon], - timeptr->tm_mday, timeptr->tm_hour, - timeptr->tm_min, timeptr->tm_sec); + n = PyOS_snprintf(buf, sizeof(buf), "%.3s %.3s%3d %.2d:%.2d:%.2d", + wday_name[timeptr->tm_wday], + mon_name[timeptr->tm_mon], + timeptr->tm_mday, timeptr->tm_hour, + timeptr->tm_min, timeptr->tm_sec); /* XXX: since the fields used by snprintf above are validated in checktm, * the following condition should never trigger. We keep the check because * historically fixed size buffer used in asctime was the source of From python-checkins at python.org Thu Jan 6 18:01:36 2011 From: python-checkins at python.org (david.malcolm) Date: Thu, 6 Jan 2011 18:01:36 +0100 (CET) Subject: [Python-checkins] r87796 - in python/branches/py3k: Misc/NEWS Python/ceval.c Message-ID: <20110106170136.9CB43EE99C@mail.python.org> Author: david.malcolm Date: Thu Jan 6 18:01:36 2011 New Revision: 87796 Log: Issue #10655: Fix the build on PowerPC on Linux with GCC when building with timestamp profiling (--with-tsc): the preprocessor test for the PowerPC support now looks for "__powerpc__" as well as "__ppc__": the latter seems to only be present on OS X; the former is the correct one for Linux with GCC. Modified: python/branches/py3k/Misc/NEWS python/branches/py3k/Python/ceval.c Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Thu Jan 6 18:01:36 2011 @@ -145,6 +145,11 @@ - Issue #10679: The "idle", "pydoc" and "2to3" scripts are now installed with a version-specific suffix on "make altinstall". +- Issue #10655: Fix the build on PowerPC on Linux with GCC when building with + timestamp profiling (--with-tsc): the preprocessor test for the PowerPC + support now looks for "__powerpc__" as well as "__ppc__": the latter seems to + only be present on OS X; the former is the correct one for Linux with GCC. + Tools/Demos ----------- Modified: python/branches/py3k/Python/ceval.c ============================================================================== --- python/branches/py3k/Python/ceval.c (original) +++ python/branches/py3k/Python/ceval.c Thu Jan 6 18:01:36 2011 @@ -26,10 +26,11 @@ typedef unsigned long long uint64; -#if defined(__ppc__) /* <- Don't know if this is the correct symbol; this - section should work for GCC on any PowerPC - platform, irrespective of OS. - POWER? Who knows :-) */ +/* PowerPC suppport. + "__ppc__" appears to be the preprocessor definition to detect on OS X, whereas + "__powerpc__" appears to be the correct one for Linux with GCC +*/ +#if defined(__ppc__) || defined (__powerpc__) #define READ_TIMESTAMP(var) ppc_getcounter(&var) From python-checkins at python.org Thu Jan 6 18:17:04 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 18:17:04 +0100 (CET) Subject: [Python-checkins] r87797 - in python/branches/py3k: Lib/test/test_wsgiref.py Lib/wsgiref/handlers.py Misc/ACKS Misc/NEWS Message-ID: <20110106171704.E047DEE9E0@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 18:17:04 2011 New Revision: 87797 Log: Issue #3839: wsgiref should not override a Content-Length header set by the application. Initial patch by Clovis Fabricio. Modified: python/branches/py3k/Lib/test/test_wsgiref.py python/branches/py3k/Lib/wsgiref/handlers.py python/branches/py3k/Misc/ACKS python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/test/test_wsgiref.py ============================================================================== --- python/branches/py3k/Lib/test/test_wsgiref.py (original) +++ python/branches/py3k/Lib/test/test_wsgiref.py Thu Jan 6 18:17:04 2011 @@ -520,6 +520,11 @@ s('200 OK',[]) return ['\u0442\u0435\u0441\u0442'.encode("utf-8")] + def trivial_app4(e,s): + # Simulate a response to a HEAD request + s('200 OK',[('Content-Length', '12345')]) + return [] + h = TestHandler() h.run(trivial_app1) self.assertEqual(h.stdout.getvalue(), @@ -543,10 +548,12 @@ b'\r\n' b'\xd1\x82\xd0\xb5\xd1\x81\xd1\x82') - - - - + h = TestHandler() + h.run(trivial_app4) + self.assertEqual(h.stdout.getvalue(), + b'Status: 200 OK\r\n' + b'Content-Length: 12345\r\n' + b'\r\n') def testBasicErrorOutput(self): Modified: python/branches/py3k/Lib/wsgiref/handlers.py ============================================================================== --- python/branches/py3k/Lib/wsgiref/handlers.py (original) +++ python/branches/py3k/Lib/wsgiref/handlers.py Thu Jan 6 18:17:04 2011 @@ -302,7 +302,9 @@ def finish_content(self): """Ensure headers and content have both been sent""" if not self.headers_sent: - self.headers['Content-Length'] = "0" + # Only zero Content-Length if not set by the application (so + # that HEAD requests can be satisfied properly, see #3839) + self.headers.setdefault('Content-Length', "0") self.send_headers() else: pass # XXX check if content-length was too short? Modified: python/branches/py3k/Misc/ACKS ============================================================================== --- python/branches/py3k/Misc/ACKS (original) +++ python/branches/py3k/Misc/ACKS Thu Jan 6 18:17:04 2011 @@ -261,6 +261,7 @@ David Everly Greg Ewing Martijn Faassen +Clovis Fabricio Andreas Faerber Bill Fancher Troy J. Farrell Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Thu Jan 6 18:17:04 2011 @@ -30,6 +30,9 @@ Library ------- +- Issue #3839: wsgiref should not override a Content-Length header set by + the application. Initial patch by Clovis Fabricio. + - Issue #10492: bdb.Bdb.run() only traces the execution of the code, not the compilation (if the input is a string). From python-checkins at python.org Thu Jan 6 18:18:32 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 18:18:32 +0100 (CET) Subject: [Python-checkins] r87798 - in python/branches/release31-maint: Lib/test/test_wsgiref.py Lib/wsgiref/handlers.py Misc/ACKS Misc/NEWS Message-ID: <20110106171832.37A51EE9CE@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 18:18:32 2011 New Revision: 87798 Log: Merged revisions 87797 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87797 | antoine.pitrou | 2011-01-06 18:17:04 +0100 (jeu., 06 janv. 2011) | 4 lines Issue #3839: wsgiref should not override a Content-Length header set by the application. Initial patch by Clovis Fabricio. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/test/test_wsgiref.py python/branches/release31-maint/Lib/wsgiref/handlers.py python/branches/release31-maint/Misc/ACKS python/branches/release31-maint/Misc/NEWS Modified: python/branches/release31-maint/Lib/test/test_wsgiref.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_wsgiref.py (original) +++ python/branches/release31-maint/Lib/test/test_wsgiref.py Thu Jan 6 18:18:32 2011 @@ -543,6 +543,11 @@ s('200 OK',[]) return ['\u0442\u0435\u0441\u0442'.encode("utf-8")] + def trivial_app4(e,s): + # Simulate a response to a HEAD request + s('200 OK',[('Content-Length', '12345')]) + return [] + h = TestHandler() h.run(trivial_app1) self.assertEqual(h.stdout.getvalue(), @@ -566,10 +571,12 @@ b'\r\n' b'\xd1\x82\xd0\xb5\xd1\x81\xd1\x82') - - - - + h = TestHandler() + h.run(trivial_app4) + self.assertEqual(h.stdout.getvalue(), + b'Status: 200 OK\r\n' + b'Content-Length: 12345\r\n' + b'\r\n') def testBasicErrorOutput(self): Modified: python/branches/release31-maint/Lib/wsgiref/handlers.py ============================================================================== --- python/branches/release31-maint/Lib/wsgiref/handlers.py (original) +++ python/branches/release31-maint/Lib/wsgiref/handlers.py Thu Jan 6 18:18:32 2011 @@ -240,7 +240,9 @@ def finish_content(self): """Ensure headers and content have both been sent""" if not self.headers_sent: - self.headers['Content-Length'] = "0" + # Only zero Content-Length if not set by the application (so + # that HEAD requests can be satisfied properly, see #3839) + self.headers.setdefault('Content-Length', "0") self.send_headers() else: pass # XXX check if content-length was too short? Modified: python/branches/release31-maint/Misc/ACKS ============================================================================== --- python/branches/release31-maint/Misc/ACKS (original) +++ python/branches/release31-maint/Misc/ACKS Thu Jan 6 18:18:32 2011 @@ -237,6 +237,7 @@ David Everly Greg Ewing Martijn Faassen +Clovis Fabricio Andreas Faerber Bill Fancher Troy J. Farrell Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Thu Jan 6 18:18:32 2011 @@ -27,6 +27,9 @@ Library ------- +- Issue #3839: wsgiref should not override a Content-Length header set by + the application. Initial patch by Clovis Fabricio. + - Issue #10790: email.header.Header.append's charset logic now works correctly for charsets whose output codec is different from its input codec. From python-checkins at python.org Thu Jan 6 18:19:05 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 18:19:05 +0100 (CET) Subject: [Python-checkins] r87799 - in python/branches/release27-maint: Lib/test/test_wsgiref.py Lib/wsgiref/handlers.py Misc/ACKS Misc/NEWS Message-ID: <20110106171905.54F75EE9E9@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 18:19:05 2011 New Revision: 87799 Log: Merged revisions 87797 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87797 | antoine.pitrou | 2011-01-06 18:17:04 +0100 (jeu., 06 janv. 2011) | 4 lines Issue #3839: wsgiref should not override a Content-Length header set by the application. Initial patch by Clovis Fabricio. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/test/test_wsgiref.py python/branches/release27-maint/Lib/wsgiref/handlers.py python/branches/release27-maint/Misc/ACKS python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Lib/test/test_wsgiref.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_wsgiref.py (original) +++ python/branches/release27-maint/Lib/test/test_wsgiref.py Thu Jan 6 18:19:05 2011 @@ -481,6 +481,11 @@ s('200 OK',[])(e['wsgi.url_scheme']) return [] + def trivial_app4(e,s): + # Simulate a response to a HEAD request + s('200 OK',[('Content-Length', '12345')]) + return [] + h = TestHandler() h.run(trivial_app1) self.assertEqual(h.stdout.getvalue(), @@ -497,10 +502,12 @@ "http") - - - - + h = TestHandler() + h.run(trivial_app4) + self.assertEqual(h.stdout.getvalue(), + b'Status: 200 OK\r\n' + b'Content-Length: 12345\r\n' + b'\r\n') def testBasicErrorOutput(self): Modified: python/branches/release27-maint/Lib/wsgiref/handlers.py ============================================================================== --- python/branches/release27-maint/Lib/wsgiref/handlers.py (original) +++ python/branches/release27-maint/Lib/wsgiref/handlers.py Thu Jan 6 18:19:05 2011 @@ -240,7 +240,9 @@ def finish_content(self): """Ensure headers and content have both been sent""" if not self.headers_sent: - self.headers['Content-Length'] = "0" + # Only zero Content-Length if not set by the application (so + # that HEAD requests can be satisfied properly, see #3839) + self.headers.setdefault('Content-Length', "0") self.send_headers() else: pass # XXX check if content-length was too short? Modified: python/branches/release27-maint/Misc/ACKS ============================================================================== --- python/branches/release27-maint/Misc/ACKS (original) +++ python/branches/release27-maint/Misc/ACKS Thu Jan 6 18:19:05 2011 @@ -242,6 +242,7 @@ David Everly Greg Ewing Martijn Faassen +Clovis Fabricio Andreas Faerber Bill Fancher Troy J. Farrell Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Thu Jan 6 18:19:05 2011 @@ -25,6 +25,9 @@ Library ------- +- Issue #3839: wsgiref should not override a Content-Length header set by + the application. Initial patch by Clovis Fabricio. + - Issue #10806, issue #9905: Fix subprocess pipes when some of the standard file descriptors (0, 1, 2) are closed in the parent process. Initial patch by Ross Lagerwall. From python-checkins at python.org Thu Jan 6 18:36:32 2011 From: python-checkins at python.org (david.malcolm) Date: Thu, 6 Jan 2011 18:36:32 +0100 (CET) Subject: [Python-checkins] r87800 - in python/branches/release31-maint: Misc/NEWS Python/ceval.c Message-ID: <20110106173632.482CCEE9D5@mail.python.org> Author: david.malcolm Date: Thu Jan 6 18:36:32 2011 New Revision: 87800 Log: Merged revisions 87796 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87796 | david.malcolm | 2011-01-06 12:01:36 -0500 (Thu, 06 Jan 2011) | 6 lines Issue #10655: Fix the build on PowerPC on Linux with GCC when building with timestamp profiling (--with-tsc): the preprocessor test for the PowerPC support now looks for "__powerpc__" as well as "__ppc__": the latter seems to only be present on OS X; the former is the correct one for Linux with GCC. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Misc/NEWS python/branches/release31-maint/Python/ceval.c Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Thu Jan 6 18:36:32 2011 @@ -111,6 +111,11 @@ - Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD and DragonFly BSD. Patch by Nicolas Joly. +- Issue #10655: Fix the build on PowerPC on Linux with GCC when building with + timestamp profiling (--with-tsc): the preprocessor test for the PowerPC + support now looks for "__powerpc__" as well as "__ppc__": the latter seems to + only be present on OS X; the former is the correct one for Linux with GCC. + Tests ----- Modified: python/branches/release31-maint/Python/ceval.c ============================================================================== --- python/branches/release31-maint/Python/ceval.c (original) +++ python/branches/release31-maint/Python/ceval.c Thu Jan 6 18:36:32 2011 @@ -27,10 +27,11 @@ typedef unsigned long long uint64; -#if defined(__ppc__) /* <- Don't know if this is the correct symbol; this - section should work for GCC on any PowerPC - platform, irrespective of OS. - POWER? Who knows :-) */ +/* PowerPC suppport. + "__ppc__" appears to be the preprocessor definition to detect on OS X, whereas + "__powerpc__" appears to be the correct one for Linux with GCC +*/ +#if defined(__ppc__) || defined (__powerpc__) #define READ_TIMESTAMP(var) ppc_getcounter(&var) From python-checkins at python.org Thu Jan 6 18:39:24 2011 From: python-checkins at python.org (david.malcolm) Date: Thu, 6 Jan 2011 18:39:24 +0100 (CET) Subject: [Python-checkins] r87801 - in python/branches/release27-maint: Misc/NEWS Python/ceval.c Message-ID: <20110106173924.6FC89EF9E@mail.python.org> Author: david.malcolm Date: Thu Jan 6 18:39:24 2011 New Revision: 87801 Log: Merged revisions 87796 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87796 | david.malcolm | 2011-01-06 12:01:36 -0500 (Thu, 06 Jan 2011) | 6 lines Issue #10655: Fix the build on PowerPC on Linux with GCC when building with timestamp profiling (--with-tsc): the preprocessor test for the PowerPC support now looks for "__powerpc__" as well as "__ppc__": the latter seems to only be present on OS X; the former is the correct one for Linux with GCC. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Misc/NEWS python/branches/release27-maint/Python/ceval.c Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Thu Jan 6 18:39:24 2011 @@ -116,6 +116,11 @@ - Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD and DragonFly BSD. Patch by Nicolas Joly. +- Issue #10655: Fix the build on PowerPC on Linux with GCC when building with + timestamp profiling (--with-tsc): the preprocessor test for the PowerPC + support now looks for "__powerpc__" as well as "__ppc__": the latter seems to + only be present on OS X; the former is the correct one for Linux with GCC. + Tests ----- Modified: python/branches/release27-maint/Python/ceval.c ============================================================================== --- python/branches/release27-maint/Python/ceval.c (original) +++ python/branches/release27-maint/Python/ceval.c Thu Jan 6 18:39:24 2011 @@ -27,10 +27,11 @@ typedef unsigned long long uint64; -#if defined(__ppc__) /* <- Don't know if this is the correct symbol; this - section should work for GCC on any PowerPC - platform, irrespective of OS. - POWER? Who knows :-) */ +/* PowerPC suppport. + "__ppc__" appears to be the preprocessor definition to detect on OS X, whereas + "__powerpc__" appears to be the correct one for Linux with GCC +*/ +#if defined(__ppc__) || defined (__powerpc__) #define READ_TIMESTAMP(var) ppc_getcounter(&var) From python-checkins at python.org Thu Jan 6 19:25:55 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 19:25:55 +0100 (CET) Subject: [Python-checkins] r87802 - in python/branches/py3k: Misc/NEWS Modules/posixmodule.c Message-ID: <20110106182555.58E92EE9F3@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 19:25:55 2011 New Revision: 87802 Log: Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. (this does not seem to be easily testable) Modified: python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/posixmodule.c Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Thu Jan 6 19:25:55 2011 @@ -30,6 +30,9 @@ Library ------- +- Issue #7858: Raise an error properly when os.utime() fails under Windows + on an existing file. + - Issue #3839: wsgiref should not override a Content-Length header set by the application. Initial patch by Clovis Fabricio. Modified: python/branches/py3k/Modules/posixmodule.c ============================================================================== --- python/branches/py3k/Modules/posixmodule.c (original) +++ python/branches/py3k/Modules/posixmodule.c Thu Jan 6 19:25:55 2011 @@ -3256,6 +3256,7 @@ something is wrong with the file, when it also could be the time stamp that gives a problem. */ win32_error("utime", NULL); + goto done; } Py_INCREF(Py_None); result = Py_None; From python-checkins at python.org Thu Jan 6 19:29:05 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 19:29:05 +0100 (CET) Subject: [Python-checkins] r87803 - in python/branches/release31-maint: Misc/NEWS Modules/posixmodule.c Message-ID: <20110106182905.88232EE985@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 19:29:05 2011 New Revision: 87803 Log: Merged revisions 87802 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87802 | antoine.pitrou | 2011-01-06 19:25:55 +0100 (jeu., 06 janv. 2011) | 6 lines Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. (this does not seem to be easily testable) ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Misc/NEWS python/branches/release31-maint/Modules/posixmodule.c Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Thu Jan 6 19:29:05 2011 @@ -27,6 +27,9 @@ Library ------- +- Issue #7858: Raise an error properly when os.utime() fails under Windows + on an existing file. + - Issue #3839: wsgiref should not override a Content-Length header set by the application. Initial patch by Clovis Fabricio. Modified: python/branches/release31-maint/Modules/posixmodule.c ============================================================================== --- python/branches/release31-maint/Modules/posixmodule.c (original) +++ python/branches/release31-maint/Modules/posixmodule.c Thu Jan 6 19:29:05 2011 @@ -3031,6 +3031,7 @@ something is wrong with the file, when it also could be the time stamp that gives a problem. */ win32_error("utime", NULL); + goto done; } Py_INCREF(Py_None); result = Py_None; From python-checkins at python.org Thu Jan 6 19:30:26 2011 From: python-checkins at python.org (antoine.pitrou) Date: Thu, 6 Jan 2011 19:30:26 +0100 (CET) Subject: [Python-checkins] r87804 - in python/branches/release27-maint: Misc/NEWS Modules/posixmodule.c Message-ID: <20110106183026.E5C73EE985@mail.python.org> Author: antoine.pitrou Date: Thu Jan 6 19:30:26 2011 New Revision: 87804 Log: Merged revisions 87802 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87802 | antoine.pitrou | 2011-01-06 19:25:55 +0100 (jeu., 06 janv. 2011) | 6 lines Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. (this does not seem to be easily testable) ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Misc/NEWS python/branches/release27-maint/Modules/posixmodule.c Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Thu Jan 6 19:30:26 2011 @@ -25,6 +25,9 @@ Library ------- +- Issue #7858: Raise an error properly when os.utime() fails under Windows + on an existing file. + - Issue #3839: wsgiref should not override a Content-Length header set by the application. Initial patch by Clovis Fabricio. Modified: python/branches/release27-maint/Modules/posixmodule.c ============================================================================== --- python/branches/release27-maint/Modules/posixmodule.c (original) +++ python/branches/release27-maint/Modules/posixmodule.c Thu Jan 6 19:30:26 2011 @@ -2843,6 +2843,7 @@ something is wrong with the file, when it also could be the time stamp that gives a problem. */ win32_error("utime", NULL); + goto done; } Py_INCREF(Py_None); result = Py_None; From python-checkins at python.org Thu Jan 6 20:15:47 2011 From: python-checkins at python.org (martin.v.loewis) Date: Thu, 6 Jan 2011 20:15:47 +0100 (CET) Subject: [Python-checkins] r87805 - in python/branches/py3k: Include/abstract.h Include/memoryobject.h Include/object.h Misc/NEWS PC/python3.def Message-ID: <20110106191547.BAF0CEE9E9@mail.python.org> Author: martin.v.loewis Date: Thu Jan 6 20:15:47 2011 New Revision: 87805 Log: Remove buffer API from stable ABI for now, see #10181. Modified: python/branches/py3k/Include/abstract.h python/branches/py3k/Include/memoryobject.h python/branches/py3k/Include/object.h python/branches/py3k/Misc/NEWS python/branches/py3k/PC/python3.def Modified: python/branches/py3k/Include/abstract.h ============================================================================== --- python/branches/py3k/Include/abstract.h (original) +++ python/branches/py3k/Include/abstract.h Thu Jan 6 20:15:47 2011 @@ -488,6 +488,7 @@ /* new buffer API */ +#ifndef Py_LIMITED_API #define PyObject_CheckBuffer(obj) \ (((obj)->ob_type->tp_as_buffer != NULL) && \ ((obj)->ob_type->tp_as_buffer->bf_getbuffer != NULL)) @@ -575,6 +576,7 @@ /* Releases a Py_buffer obtained from getbuffer ParseTuple's s*. */ +#endif /* Py_LIMITED_API */ PyAPI_FUNC(PyObject *) PyObject_Format(PyObject* obj, PyObject *format_spec); Modified: python/branches/py3k/Include/memoryobject.h ============================================================================== --- python/branches/py3k/Include/memoryobject.h (original) +++ python/branches/py3k/Include/memoryobject.h Thu Jan 6 20:15:47 2011 @@ -55,9 +55,11 @@ PyAPI_FUNC(PyObject *) PyMemoryView_FromObject(PyObject *base); +#ifndef Py_LIMITED_API PyAPI_FUNC(PyObject *) PyMemoryView_FromBuffer(Py_buffer *info); /* create new if bufptr is NULL will be a new bytesobject in base */ +#endif /* The struct is declared here so that macros can work, but it shouldn't Modified: python/branches/py3k/Include/object.h ============================================================================== --- python/branches/py3k/Include/object.h (original) +++ python/branches/py3k/Include/object.h Thu Jan 6 20:15:47 2011 @@ -143,7 +143,7 @@ typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *); typedef int(*objobjargproc)(PyObject *, PyObject *, PyObject *); - +#ifndef Py_LIMITED_API /* buffer interface */ typedef struct bufferinfo { void *buf; @@ -195,6 +195,7 @@ #define PyBUF_WRITE 0x200 /* End buffer interface */ +#endif /* Py_LIMITED_API */ typedef int (*objobjproc)(PyObject *, PyObject *); typedef int (*visitproc)(PyObject *, void *); Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Thu Jan 6 20:15:47 2011 @@ -8,6 +8,8 @@ Core and Builtins ----------------- +- Remove buffer API from stable ABI for now, see #10181. + - Issue #8651: PyArg_Parse*() functions raise an OverflowError if the file doesn't have PY_SSIZE_T_CLEAN define and the size doesn't fit in an int (length bigger than 2^31-1 bytes). Modified: python/branches/py3k/PC/python3.def ============================================================================== --- python/branches/py3k/PC/python3.def (original) +++ python/branches/py3k/PC/python3.def Thu Jan 6 20:15:47 2011 @@ -10,13 +10,6 @@ PyBaseObject_Type=python32.PyBaseObject_Type DATA PyBool_FromLong=python32.PyBool_FromLong PyBool_Type=python32.PyBool_Type DATA - PyBuffer_FillContiguousStrides=python32.PyBuffer_FillContiguousStrides - PyBuffer_FillInfo=python32.PyBuffer_FillInfo - PyBuffer_FromContiguous=python32.PyBuffer_FromContiguous - PyBuffer_GetPointer=python32.PyBuffer_GetPointer - PyBuffer_IsContiguous=python32.PyBuffer_IsContiguous - PyBuffer_Release=python32.PyBuffer_Release - PyBuffer_ToContiguous=python32.PyBuffer_ToContiguous PyByteArrayIter_Type=python32.PyByteArrayIter_Type DATA PyByteArray_AsString=python32.PyByteArray_AsString PyByteArray_Concat=python32.PyByteArray_Concat @@ -317,7 +310,6 @@ PyMem_Malloc=python32.PyMem_Malloc PyMem_Realloc=python32.PyMem_Realloc PyMemberDescr_Type=python32.PyMemberDescr_Type DATA - PyMemoryView_FromBuffer=python32.PyMemoryView_FromBuffer PyMemoryView_FromObject=python32.PyMemoryView_FromObject PyMemoryView_GetContiguous=python32.PyMemoryView_GetContiguous PyMemoryView_Type=python32.PyMemoryView_Type DATA @@ -399,7 +391,6 @@ PyObject_CallObject=python32.PyObject_CallObject PyObject_CheckReadBuffer=python32.PyObject_CheckReadBuffer PyObject_ClearWeakRefs=python32.PyObject_ClearWeakRefs - PyObject_CopyData=python32.PyObject_CopyData PyObject_DelItem=python32.PyObject_DelItem PyObject_DelItemString=python32.PyObject_DelItemString PyObject_Dir=python32.PyObject_Dir @@ -412,7 +403,6 @@ PyObject_GenericSetAttr=python32.PyObject_GenericSetAttr PyObject_GetAttr=python32.PyObject_GetAttr PyObject_GetAttrString=python32.PyObject_GetAttrString - PyObject_GetBuffer=python32.PyObject_GetBuffer PyObject_GetItem=python32.PyObject_GetItem PyObject_GetIter=python32.PyObject_GetIter PyObject_HasAttr=python32.PyObject_HasAttr From python-checkins at python.org Thu Jan 6 20:26:21 2011 From: python-checkins at python.org (martin.v.loewis) Date: Thu, 6 Jan 2011 20:26:21 +0100 (CET) Subject: [Python-checkins] r87806 - python/branches/py3k/Objects/typeslots.py Message-ID: <20110106192621.EE875EE982@mail.python.org> Author: martin.v.loewis Date: Thu Jan 6 20:26:21 2011 New Revision: 87806 Log: Support comment lines and missing indices in typeslots.h. Modified: python/branches/py3k/Objects/typeslots.py Modified: python/branches/py3k/Objects/typeslots.py ============================================================================== --- python/branches/py3k/Objects/typeslots.py (original) +++ python/branches/py3k/Objects/typeslots.py Thu Jan 6 20:26:21 2011 @@ -7,6 +7,8 @@ res = {} for line in sys.stdin: m = re.match("#define Py_([a-z_]+) ([0-9]+)", line) + if not m: + continue member = m.group(1) if member.startswith("tp_"): member = "ht_type."+member @@ -22,4 +24,7 @@ M = max(res.keys())+1 for i in range(1,M): - print("offsetof(PyHeapTypeObject, %s)," % res[i]) + if i in res: + print("offsetof(PyHeapTypeObject, %s)," % res[i]) + else: + print("0,") From python-checkins at python.org Thu Jan 6 20:28:18 2011 From: python-checkins at python.org (georg.brandl) Date: Thu, 6 Jan 2011 20:28:18 +0100 (CET) Subject: [Python-checkins] r87807 - python/branches/py3k/Doc/library/threading.rst Message-ID: <20110106192818.A861FEE982@mail.python.org> Author: georg.brandl Date: Thu Jan 6 20:28:18 2011 New Revision: 87807 Log: #10846: fix typo. Modified: python/branches/py3k/Doc/library/threading.rst Modified: python/branches/py3k/Doc/library/threading.rst ============================================================================== --- python/branches/py3k/Doc/library/threading.rst (original) +++ python/branches/py3k/Doc/library/threading.rst Thu Jan 6 20:28:18 2011 @@ -719,9 +719,9 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Semaphores are often used to guard resources with limited capacity, for example, -a database server. In any situation where the size of the resource size is -fixed, you should use a bounded semaphore. Before spawning any worker threads, -your main thread would initialize the semaphore:: +a database server. In any situation where the size of the resource is fixed, +you should use a bounded semaphore. Before spawning any worker threads, your +main thread would initialize the semaphore:: maxconnections = 5 ... From python-checkins at python.org Thu Jan 6 20:28:31 2011 From: python-checkins at python.org (martin.v.loewis) Date: Thu, 6 Jan 2011 20:28:31 +0100 (CET) Subject: [Python-checkins] r87808 - in python/branches/py3k: Include/typeslots.h Objects/typeslots.inc Message-ID: <20110106192831.4B5A0EE9BC@mail.python.org> Author: martin.v.loewis Date: Thu Jan 6 20:28:31 2011 New Revision: 87808 Log: Drop bf_getbuffer/bf_releasebuffer from stable ABI, see #10181. Modified: python/branches/py3k/Include/typeslots.h python/branches/py3k/Objects/typeslots.inc Modified: python/branches/py3k/Include/typeslots.h ============================================================================== --- python/branches/py3k/Include/typeslots.h (original) +++ python/branches/py3k/Include/typeslots.h Thu Jan 6 20:28:31 2011 @@ -1,5 +1,7 @@ -#define Py_bf_getbuffer 1 -#define Py_bf_releasebuffer 2 +/* Do not renumber the file; these numbers are part of the stable ABI. */ +/* Disabled, see #10181 */ +#undef Py_bf_getbuffer +#undef Py_bf_releasebuffer #define Py_mp_ass_subscript 3 #define Py_mp_length 4 #define Py_mp_subscript 5 Modified: python/branches/py3k/Objects/typeslots.inc ============================================================================== --- python/branches/py3k/Objects/typeslots.inc (original) +++ python/branches/py3k/Objects/typeslots.inc Thu Jan 6 20:28:31 2011 @@ -1,6 +1,6 @@ -/* Generated by typeslots.py $Revision: 87011 $ */ -offsetof(PyHeapTypeObject, as_buffer.bf_getbuffer), -offsetof(PyHeapTypeObject, as_buffer.bf_releasebuffer), +/* Generated by typeslots.py $Revision: 87806 $ */ +0, +0, offsetof(PyHeapTypeObject, as_mapping.mp_ass_subscript), offsetof(PyHeapTypeObject, as_mapping.mp_length), offsetof(PyHeapTypeObject, as_mapping.mp_subscript), From python-checkins at python.org Thu Jan 6 20:33:28 2011 From: python-checkins at python.org (martin.v.loewis) Date: Thu, 6 Jan 2011 20:33:28 +0100 (CET) Subject: [Python-checkins] r87809 - peps/trunk/pep-0384.txt Message-ID: <20110106193328.516FFEE985@mail.python.org> Author: martin.v.loewis Date: Thu Jan 6 20:33:28 2011 New Revision: 87809 Log: Issue #10181: remove buffer interface from ABI. Modified: peps/trunk/pep-0384.txt Modified: peps/trunk/pep-0384.txt ============================================================================== --- peps/trunk/pep-0384.txt (original) +++ peps/trunk/pep-0384.txt Thu Jan 6 20:33:28 2011 @@ -99,8 +99,6 @@ - PyObject (ob_refcnt, ob_type) - PyVarObject (ob_base, ob_size) -- Py_buffer (buf, obj, len, itemsize, readonly, ndim, shape, - strides, suboffsets, smalltable, internal) - PyMethodDef (ml_name, ml_meth, ml_flags, ml_doc) - PyMemberDef (name, type, offset, flags, doc) - PyGetSetDef (name, get, set, doc, closure) @@ -177,7 +175,6 @@ - sq_length sq_concat sq_repeat sq_item sq_ass_item sq_contains sq_inplace_concat sq_inplace_repeat - mp_length mp_subscript mp_ass_subscript -- bf_getbuffer bf_releasebuffer The following fields cannot be set during type definition: - tp_dict tp_mro tp_cache tp_subclasses tp_weaklist tp_print @@ -194,7 +191,7 @@ - Py_uintptr_t Py_intptr_t Py_ssize_t - unaryfunc binaryfunc ternaryfunc inquiry lenfunc ssizeargfunc ssizessizeargfunc ssizeobjargproc ssizessizeobjargproc objobjargproc - getbufferproc releasebufferproc objobjproc visitproc traverseproc + objobjproc visitproc traverseproc destructor getattrfunc getattrofunc setattrfunc setattrofunc reprfunc hashfunc richcmpfunc getiterfunc iternextfunc descrgetfunc descrsetfunc initproc newfunc allocfunc @@ -312,6 +309,14 @@ - Py_BEGIN_ALLOW_THREADS, Py_BLOCK_THREADS, Py_UNBLOCK_THREADS, Py_END_ALLOW_THREADS +The Buffer Interface +-------------------- + +The buffer interface (type Py_buffer, type slots bf_getbuffer and +bf_releasebuffer, etc) has been omitted from the ABI, since the stability +of the Py_buffer structure is not clear at this time. Inclusion in the +ABI can be considered in future releases. + Signature Changes ----------------- From python-checkins at python.org Thu Jan 6 21:44:14 2011 From: python-checkins at python.org (brett.cannon) Date: Thu, 06 Jan 2011 21:44:14 +0100 Subject: [Python-checkins] devguide: Start using sphinx.ext.intersphinx to link to module docs. Message-ID: brett.cannon pushed a9a81a97442a to devguide: http://hg.python.org/devguide/rev/a9a81a97442a changeset: 32:a9a81a97442a user: Brett Cannon date: Wed Jan 05 14:41:04 2011 -0800 summary: Start using sphinx.ext.intersphinx to link to module docs. files: conf.py runtests.rst diff --git a/conf.py b/conf.py --- a/conf.py +++ b/conf.py @@ -25,7 +25,8 @@ # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.todo'] +extensions = ['sphinx.ext.intersphinx', 'sphinx.ext.todo'] +intersphinx_mapping = {'python': ('http://docs.python.org/py3k', None)} todo_include_todos = True # Add any paths that contain templates here, relative to this directory. diff --git a/runtests.rst b/runtests.rst --- a/runtests.rst +++ b/runtests.rst @@ -16,8 +16,8 @@ ./python -m test That will run the entire standard test suite (i.e., all tests that do not -consume a lot of resources) using the ``test.regrtest`` module (Python's test -runner which you can execute directly if you prefer). +consume a lot of resources) using the :py:mod:`test.regrtest` module (Python's +test runner which you can execute directly if you prefer). To run **all** tests, you need to specify what resources you are willing to have consumed. For those flags (and others which can help debug various issues such as reference leaks), read the help text:: @@ -51,11 +51,11 @@ possible. Tests live in the ``Lib/test`` directory, where every file that includes tests has a ``test_`` prefix. -One difference, though, is that you are allowed to use the ``test.support`` -module. It contains various helpers that are tailored to Python's test suite. -Because of this it has no API or backwards-compatibility guarantees, which is -why the general public is not supposed to use the module. But when you are -writing tests for Python's test suite its use is encouraged. +One difference, though, is that you are allowed to use the +:py:mod:`test.support` module. It contains various helpers that are tailored to +Python's test suite. Because of this it has no API or backwards-compatibility +guarantees, which is why the general public is not supposed to use the module. +But when you are writing tests for Python's test suite its use is encouraged. If your test must write various temporary files to a specific directory, you can use the ``Lib/test/data`` directory for that purpose. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Jan 6 21:44:16 2011 From: python-checkins at python.org (brett.cannon) Date: Thu, 06 Jan 2011 21:44:16 +0100 Subject: [Python-checkins] devguide: Be a bit stronger in the opening wording; people shouldn't skip around in the Message-ID: brett.cannon pushed 2a87000c1f25 to devguide: http://hg.python.org/devguide/rev/2a87000c1f25 changeset: 33:2a87000c1f25 user: Brett Cannon date: Wed Jan 05 14:58:55 2011 -0800 summary: Be a bit stronger in the opening wording; people shouldn't skip around in the order of things nor skip reading period. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -7,6 +7,7 @@ setup patch runtests + coverage .. todolist:: @@ -15,10 +16,11 @@ Contributing ------------ -This list is in an overall suggested order for people wanting to contribute to -the Python programming language and/or the CPython interpreter. People should -follow the top-level bullet points in order, while sub-level bullet points can -be done in any order. +People who wish to contribute to Python **must** read the following documents +in their top-level order (sub-level documents can be read in any order). You +can stop where you feel comfortable and being contributing without reading and +understanding all of these documents, but please do not skip around within the +documentation. * :ref:`setup` * Coding style guides @@ -27,7 +29,7 @@ * :ref:`patch` * :ref:`runtests` * Projects to get familiar with the development process - * `Help increase test coverage `_ + * :ref:`coverage` * `Make all unit tests discoverable by unittest `_ * `Fix all warnings raised when running the test suite w/ -uall `_ * `Fixing documentation bugs `_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Jan 6 21:44:17 2011 From: python-checkins at python.org (brett.cannon) Date: Thu, 06 Jan 2011 21:44:17 +0100 Subject: [Python-checkins] devguide: Specify patches should be from the top-level directory. Message-ID: brett.cannon pushed 32b6edf7dda3 to devguide: http://hg.python.org/devguide/rev/32b6edf7dda3 changeset: 34:32b6edf7dda3 user: Brett Cannon date: Thu Jan 06 11:54:50 2011 -0800 summary: Specify patches should be from the top-level directory. files: patch.rst diff --git a/patch.rst b/patch.rst --- a/patch.rst +++ b/patch.rst @@ -61,7 +61,8 @@ This will make sure extraneous whitespace has been removed from your patch, etc. -To create your patch, you should generate a unified diff:: +To create your patch, you should generate a unified diff from your checkout's +top-level directory:: svn diff > patch.diff -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Jan 6 21:44:17 2011 From: python-checkins at python.org (brett.cannon) Date: Thu, 06 Jan 2011 21:44:17 +0100 Subject: [Python-checkins] devguide: Specify how to run regrtest.py directly. Message-ID: brett.cannon pushed a257c33bae29 to devguide: http://hg.python.org/devguide/rev/a257c33bae29 changeset: 35:a257c33bae29 user: Brett Cannon date: Thu Jan 06 12:43:14 2011 -0800 summary: Specify how to run regrtest.py directly. files: runtests.rst diff --git a/runtests.rst b/runtests.rst --- a/runtests.rst +++ b/runtests.rst @@ -16,8 +16,11 @@ ./python -m test That will run the entire standard test suite (i.e., all tests that do not -consume a lot of resources) using the :py:mod:`test.regrtest` module (Python's -test runner which you can execute directly if you prefer). +consume a lot of resources) using the :py:mod:`test.regrtest` module. Python's +test runner can also be executed directly when needed:: + + ./python Lib/test/regrtest.py + To run **all** tests, you need to specify what resources you are willing to have consumed. For those flags (and others which can help debug various issues such as reference leaks), read the help text:: -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Jan 6 21:44:18 2011 From: python-checkins at python.org (brett.cannon) Date: Thu, 06 Jan 2011 21:44:18 +0100 Subject: [Python-checkins] devguide: Point out that OS X users need to change examples to use python.exe instead of Message-ID: brett.cannon pushed 9199f5561476 to devguide: http://hg.python.org/devguide/rev/9199f5561476 changeset: 36:9199f5561476 user: Brett Cannon date: Thu Jan 06 12:43:45 2011 -0800 summary: Point out that OS X users need to change examples to use python.exe instead of python. files: setup.rst diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -114,7 +114,8 @@ Once Python is done building you will then have a working build of Python that can be run in-place; ``./python`` on most machines, ``./python.exe`` -on OS X. +on OS X (all examples throughout this documentation say ``./python`` but +implies you choose the proper name based on your OS). Windows -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Jan 6 21:44:18 2011 From: python-checkins at python.org (brett.cannon) Date: Thu, 06 Jan 2011 21:44:18 +0100 Subject: [Python-checkins] devguide: Start writing the coverage task, beginning with how to use coverage.py. Message-ID: brett.cannon pushed b65f3b1ad23b to devguide: http://hg.python.org/devguide/rev/b65f3b1ad23b changeset: 37:b65f3b1ad23b tag: tip user: Brett Cannon date: Thu Jan 06 12:44:07 2011 -0800 summary: Start writing the coverage task, beginning with how to use coverage.py. files: coverage.rst diff --git a/coverage.rst b/coverage.rst new file mode 100644 --- /dev/null +++ b/coverage.rst @@ -0,0 +1,123 @@ +.. _coverage: + +Increase Test Coverage +====================== + +Python development follows a practice that all semantics changes and additions +to the language and :abbr:`stdlib (standard library)` are accompanied by +appropriate unit tests. Unfortunately Python was in existence for a long time +before the practice came into effect. This has left chunks of the stdlib +untested which is not a desirable situation to be in. + +A good, easy way to become acquianted with Python's code and to help out is to +help increase the test coverage for Python's stdlib. Ideally we would like to +have 100% coverage, but any increase is a good one. Do realize, though, that +getting 100% coverage is not always possible. There could be platform-specific +code that simply will not execute for you, errors in the output, etc. You can +use your judgement as to what should and should not be covered, but being +conservative and assuming something should be covered is generally a good rule +to follow. + +Choosing what module you want to increase test coverage can be done in a couple +of ways. A third-party website at http://coverage.livinglogic.de/ provides an +overall view of how good coverage is for various modules (you will want to +focus on those in the ``Lib`` directory as those are the pure Python modules +from Python's stdlib, and thus easier to work with than the C extension +modules). Another is to follow the examples below and simply see what kind of +coverage your favorite module has. This is "stabbing in the dark", though, and +so it might take some time to find a module that needs coverage help. Finally, +you can simply run the test suite yourself with coverage turned on and see what +modules need help. This has the drawback as the test suite takes some time to +complete when run under coverage measuring. + + +Using coverage.py +----------------- + +One of the most popular third-party coverage tools is `coverage.py`_ which +provides very nice HTML output along with advanced features such as +:ref:`branch coverage `. If you prefer to stay with tools only +provided by the stdlib then that is possible to :ref:`using test.regrtest +`. + +Because the in-development version of Python is bleeding-edge, it is possible +that the latest release version of coverage.py will not work. In that case you +should try using the in-development of coverage.py to see if it has been +updated as needed. To do this you should check out the development version of +coverage.py into your checkout of Python and make a symlink (or simply copy if +you prefer) the ``coverage`` subdirectory:: + + hg clone https://bitbucket.org/ned/coveragepy + ln -s coveragepy/coverage + +Otherwise you can use the latest release of coverage.py. One option is to +download the source distribution of coverage.py and copy the ``coverage`` +directory into your Python checkout. The other option is to use your checkout +copy of Python to install coverage.py (but use the ``--user`` flag to +Distutils!). + +Regardless of how you installed coverage.py, the following should work:: + + ./python -m coverage + +Coverage.py will print out a little bit of helper text verifying that +everything is working. + +To run the test suite under coverage.py, do the following:: + + ./python -m coverage run --pylib Lib/test/regrtest.py + +If you want to run only a single test, specify the module/package being tested +in the ``--source`` flag (so as to prune the coverage reporting to only the +module/package you are interested in) and then append the name of the test you +wish to run to the command:: + + ./python -m coverage run --pylib --source=abc Lib/test/regrtest.py test_abc + +To see the results of the coverage run, you can view a text-based report with:: + + ./python -m coverage report + +You can use the ``--show-missing`` flag to get a list of lines that were not +executed:: + + ./python -m coverage report --show-missing + +But one of the strengths of coverage.py is its HTML-based reports which lets +you visually see what lines of code were not tested:: + + ./python -m coverage -d .coverage_html html + +You can then open the ``.coverage_html/index.html`` file in a web browser to +view the coverage results in a nicely formatted page. + + +.. _branch_coverage: + +Branch Coverage +''''''''''''''' + +For the truly daring, you can use another powerful feature of coverage.py: +branch coverage. Testing every possible branch path through code, while a great +goal to strive for, is not as important of a goal as it is to get 100% line +coverage for the entire stdlib (for now). + +If you decide to want to try to improve branch coverage, simply add the +``--branch`` flag to your coverage run:: + + ./python -m coverage run --pylib --branch + +This will lead to the report stating not only what lines were not covered, but +also what branch paths were not executed. + + +.. _coverage.py: http://nedbatchelder.com/code/coverage/ + + +.. _coverage_by_regrtest: + +Using test.regrtest +------------------- + +XXX + -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Jan 6 21:55:29 2011 From: python-checkins at python.org (raymond.hettinger) Date: Thu, 6 Jan 2011 21:55:29 +0100 (CET) Subject: [Python-checkins] r87810 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110106205529.46D2DEE9BA@mail.python.org> Author: raymond.hettinger Date: Thu Jan 6 21:55:29 2011 New Revision: 87810 Log: Typo. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Thu Jan 6 21:55:29 2011 @@ -884,8 +884,8 @@ the :keyword:`with`-statement, but there is no parallel for function decorators. In the above example, there is not a clean way for the *track_entry_and_exit* -context manager does not have a way to return a logging instance for use in the -body of enclosed statements. +context manager to return a logging instance for use in the body of enclosed +statements. (Contributed by Michael Foord in :issue:`9110`.) From python-checkins at python.org Thu Jan 6 21:56:23 2011 From: python-checkins at python.org (brett.cannon) Date: Thu, 06 Jan 2011 21:56:23 +0100 Subject: [Python-checkins] devguide: Make the commit hook happy. Message-ID: brett.cannon pushed 8f5805901aa7 to devguide: http://hg.python.org/devguide/rev/8f5805901aa7 changeset: 38:8f5805901aa7 tag: tip user: Brett Cannon date: Thu Jan 06 12:56:18 2011 -0800 summary: Make the commit hook happy. files: conf.py diff --git a/conf.py b/conf.py --- a/conf.py +++ b/conf.py @@ -122,7 +122,8 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +# Commented out as Hg doesn't track empty directories. +#html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Jan 6 22:57:06 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Thu, 6 Jan 2011 22:57:06 +0100 (CET) Subject: [Python-checkins] r87811 - in python/branches/py3k: Lib/test/test_time.py Modules/timemodule.c Message-ID: <20110106215706.A0214EE9C0@mail.python.org> Author: alexander.belopolsky Date: Thu Jan 6 22:57:06 2011 New Revision: 87811 Log: Further simplify gettmarg() Modified: python/branches/py3k/Lib/test/test_time.py python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Thu Jan 6 22:57:06 2011 @@ -131,6 +131,7 @@ self.assertRaises(OverflowError, time.asctime, (bigyear + 1,) + (0,)*8) self.assertRaises(TypeError, time.asctime, 0) self.assertRaises(TypeError, time.asctime, ()) + self.assertRaises(TypeError, time.asctime, (0,) * 10) def test_asctime_bounding_check(self): self._bounds_checking(time.asctime) Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Thu Jan 6 22:57:06 2011 @@ -297,34 +297,20 @@ gettmarg(PyObject *args, struct tm *p) { int y; - PyObject *t = NULL; memset((void *) p, '\0', sizeof(struct tm)); - if (PyTuple_Check(args)) { - t = args; - Py_INCREF(t); - } - else { + if (!PyTuple_Check(args)) { PyErr_SetString(PyExc_TypeError, "Tuple or struct_time argument required"); return 0; } - if (t == NULL || !PyArg_ParseTuple(t, "iiiiiiiii", - &y, - &p->tm_mon, - &p->tm_mday, - &p->tm_hour, - &p->tm_min, - &p->tm_sec, - &p->tm_wday, - &p->tm_yday, - &p->tm_isdst)) { - Py_XDECREF(t); + if (!PyArg_ParseTuple(args, "iiiiiiiii", + &y, &p->tm_mon, &p->tm_mday, + &p->tm_hour, &p->tm_min, &p->tm_sec, + &p->tm_wday, &p->tm_yday, &p->tm_isdst)) return 0; - } - Py_DECREF(t); /* XXX: Why 1900? If the goal is to interpret 2-digit years as those in * 20th / 21st century according to the POSIX standard, we can just treat From python-checkins at python.org Thu Jan 6 23:06:40 2011 From: python-checkins at python.org (brett.cannon) Date: Thu, 06 Jan 2011 23:06:40 +0100 Subject: [Python-checkins] devguide: Fix a typo found by Aaron Sterling. Message-ID: brett.cannon pushed cd098b2386af to devguide: http://hg.python.org/devguide/rev/cd098b2386af changeset: 39:cd098b2386af tag: tip user: Brett Cannon date: Thu Jan 06 14:06:32 2011 -0800 summary: Fix a typo found by Aaron Sterling. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -18,7 +18,7 @@ People who wish to contribute to Python **must** read the following documents in their top-level order (sub-level documents can be read in any order). You -can stop where you feel comfortable and being contributing without reading and +can stop where you feel comfortable and begin contributing without reading and understanding all of these documents, but please do not skip around within the documentation. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Thu Jan 6 23:32:41 2011 From: python-checkins at python.org (brett.cannon) Date: Thu, 6 Jan 2011 23:32:41 +0100 (CET) Subject: [Python-checkins] r87812 - in python/branches/py3k: Doc/reference/expressions.rst Lib/test/regrtest.py Misc/NEWS Message-ID: <20110106223241.3436DEE992@mail.python.org> Author: brett.cannon Date: Thu Jan 6 23:32:41 2011 New Revision: 87812 Log: Get --coverage to be an acceptable flag for test.regrtest again. Modified: python/branches/py3k/Doc/reference/expressions.rst python/branches/py3k/Lib/test/regrtest.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Doc/reference/expressions.rst ============================================================================== --- python/branches/py3k/Doc/reference/expressions.rst (original) +++ python/branches/py3k/Doc/reference/expressions.rst Thu Jan 6 23:32:41 2011 @@ -7,7 +7,7 @@ .. index:: expression, BNF -This chapter explains the meaning of the elements of expressions in Python. + This chapter explains the meaning of the elements of expressions in Python. **Syntax Notes:** In this and the following chapters, extended BNF notation will be used to describe syntax, not lexical analysis. When (one alternative of) a Modified: python/branches/py3k/Lib/test/regrtest.py ============================================================================== --- python/branches/py3k/Lib/test/regrtest.py (original) +++ python/branches/py3k/Lib/test/regrtest.py Thu Jan 6 23:32:41 2011 @@ -264,8 +264,8 @@ 'exclude', 'single', 'slow', 'random', 'fromfile', 'findleaks', 'use=', 'threshold=', 'trace', 'coverdir=', 'nocoverdir', 'runleaks', 'huntrleaks=', 'memlimit=', 'randseed=', - 'multiprocess=', 'slaveargs=', 'forever', 'debug', 'start=', - 'nowindows', 'header']) + 'multiprocess=', 'coverage', 'slaveargs=', 'forever', 'debug', + 'start=', 'nowindows', 'header']) except getopt.error as msg: usage(msg) Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Thu Jan 6 23:32:41 2011 @@ -172,6 +172,8 @@ Tests ----- +- Make the --coverage flag work for test.regrtest. + - Issue #1677694: Refactor and improve test_timeout. Original patch by Bj?rn Lindqvist. From python-checkins at python.org Fri Jan 7 00:08:16 2011 From: python-checkins at python.org (brett.cannon) Date: Fri, 7 Jan 2011 00:08:16 +0100 (CET) Subject: [Python-checkins] r87813 - python/branches/py3k/Doc/reference/expressions.rst Message-ID: <20110106230816.B333DEE9F9@mail.python.org> Author: brett.cannon Date: Fri Jan 7 00:08:16 2011 New Revision: 87813 Log: Undo an accidental commit in r87812. Modified: python/branches/py3k/Doc/reference/expressions.rst Modified: python/branches/py3k/Doc/reference/expressions.rst ============================================================================== --- python/branches/py3k/Doc/reference/expressions.rst (original) +++ python/branches/py3k/Doc/reference/expressions.rst Fri Jan 7 00:08:16 2011 @@ -7,7 +7,7 @@ .. index:: expression, BNF - This chapter explains the meaning of the elements of expressions in Python. +This chapter explains the meaning of the elements of expressions in Python. **Syntax Notes:** In this and the following chapters, extended BNF notation will be used to describe syntax, not lexical analysis. When (one alternative of) a From python-checkins at python.org Fri Jan 7 00:42:50 2011 From: python-checkins at python.org (brett.cannon) Date: Fri, 07 Jan 2011 00:42:50 +0100 Subject: [Python-checkins] devguide: A possible intro task that requires some initial coding. Message-ID: brett.cannon pushed edfd42089427 to devguide: http://hg.python.org/devguide/rev/edfd42089427 changeset: 40:edfd42089427 user: Brett Cannon date: Thu Jan 06 14:18:40 2011 -0800 summary: A possible intro task that requires some initial coding. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -80,6 +80,12 @@ See if tempfile or test.support has a context manager that creates and deletes a temp file so as to move off of test.support.TESTFN. +.. todo:: + Create test.support.optional_import() for tests to use to import modules + that are optional on various platforms. This would allow for moving away + from ImportError representing a skipped test and also rip out the + expectations stuff from regrtest and put it with the tests instead. + .. _buildbots: http://python.org/dev/buildbot/ .. _PEP 7: http://www.python.org/dev/peps/pep-0007 -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Jan 7 00:42:51 2011 From: python-checkins at python.org (brett.cannon) Date: Fri, 07 Jan 2011 00:42:51 +0100 Subject: [Python-checkins] devguide: Strongly suggest people don't run regrtest directly. Message-ID: brett.cannon pushed 312195716711 to devguide: http://hg.python.org/devguide/rev/312195716711 changeset: 41:312195716711 user: Brett Cannon date: Thu Jan 06 14:37:10 2011 -0800 summary: Strongly suggest people don't run regrtest directly. files: runtests.rst diff --git a/runtests.rst b/runtests.rst --- a/runtests.rst +++ b/runtests.rst @@ -17,7 +17,8 @@ That will run the entire standard test suite (i.e., all tests that do not consume a lot of resources) using the :py:mod:`test.regrtest` module. Python's -test runner can also be executed directly when needed:: +test runner can also be executed directly when needed, but this should be +avoided!:: ./python Lib/test/regrtest.py -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Jan 7 00:42:51 2011 From: python-checkins at python.org (brett.cannon) Date: Fri, 07 Jan 2011 00:42:51 +0100 Subject: [Python-checkins] devguide: Explain how to use test.regrtest to do coverage. Message-ID: brett.cannon pushed b04916d96002 to devguide: http://hg.python.org/devguide/rev/b04916d96002 changeset: 42:b04916d96002 tag: tip user: Brett Cannon date: Thu Jan 06 15:42:45 2011 -0800 summary: Explain how to use test.regrtest to do coverage. files: coverage.rst diff --git a/coverage.rst b/coverage.rst --- a/coverage.rst +++ b/coverage.rst @@ -86,9 +86,9 @@ But one of the strengths of coverage.py is its HTML-based reports which lets you visually see what lines of code were not tested:: - ./python -m coverage -d .coverage_html html + ./python -m coverage -d coverage_html html -You can then open the ``.coverage_html/index.html`` file in a web browser to +You can then open the ``coverage_html/index.html`` file in a web browser to view the coverage results in a nicely formatted page. @@ -119,5 +119,15 @@ Using test.regrtest ------------------- -XXX +If you prefer to rely solely on the stdlib to generate coverage data, you can +do so by passing the appropriate flags to :py:ref:`test.regrtest` (along with +any other flags you want to):: + ./python -m test --coverage -D `pwd`/coverage_data + +Do note the argument to ``-D``; if you do not specify an absolute path to where +you want the coverage data to end up it will go somewhere you don't expect. + +Once the tests are done you will find the directory you specified contains +files for each executed module along with which lines were executed how many +times. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Jan 7 01:23:42 2011 From: python-checkins at python.org (brett.cannon) Date: Fri, 07 Jan 2011 01:23:42 +0100 Subject: [Python-checkins] devguide: Add a possible todo for having people help figure out what is and is not part Message-ID: brett.cannon pushed 80b8733a3dc9 to devguide: http://hg.python.org/devguide/rev/80b8733a3dc9 changeset: 43:80b8733a3dc9 user: Brett Cannon date: Thu Jan 06 15:53:38 2011 -0800 summary: Add a possible todo for having people help figure out what is and is not part of the public API. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -86,6 +86,11 @@ from ImportError representing a skipped test and also rip out the expectations stuff from regrtest and put it with the tests instead. +.. todo:: + Think about beginner task of properly making APIs private (i.e., leading + underscore where needed); see http://mail.python.org/pipermail/python-dev/2010-November/105476.html + + .. _buildbots: http://python.org/dev/buildbot/ .. _PEP 7: http://www.python.org/dev/peps/pep-0007 -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Jan 7 01:23:43 2011 From: python-checkins at python.org (brett.cannon) Date: Fri, 07 Jan 2011 01:23:43 +0100 Subject: [Python-checkins] devguide: Since the test suite doesn't raise any warnings on a basic run, making the idea Message-ID: brett.cannon pushed 09668b5e2141 to devguide: http://hg.python.org/devguide/rev/09668b5e2141 changeset: 44:09668b5e2141 user: Brett Cannon date: Thu Jan 06 16:15:28 2011 -0800 summary: Since the test suite doesn't raise any warnings on a basic run, making the idea of having people try to fix warnings as a more advanced thing. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -31,11 +31,11 @@ * Projects to get familiar with the development process * :ref:`coverage` * `Make all unit tests discoverable by unittest `_ - * `Fix all warnings raised when running the test suite w/ -uall `_ * `Fixing documentation bugs `_ * Projects for once you are comfortable * `Helping triage issues `_ * `Fixing issues considered "easy" `_ (and beyond) + * `Fix all warnings raised when running the test suite w/ -uall `_ * Watching the buildbots_ * `Gaining 'Developer' privileges for the issue tracker `_ * `Triaging issues `_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Jan 7 01:23:44 2011 From: python-checkins at python.org (brett.cannon) Date: Fri, 07 Jan 2011 01:23:44 +0100 Subject: [Python-checkins] devguide: Clarify a todo. Message-ID: brett.cannon pushed 546495ae86fa to devguide: http://hg.python.org/devguide/rev/546495ae86fa changeset: 45:546495ae86fa tag: tip user: Brett Cannon date: Thu Jan 06 16:23:22 2011 -0800 summary: Clarify a todo. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -88,7 +88,8 @@ .. todo:: Think about beginner task of properly making APIs private (i.e., leading - underscore where needed); see http://mail.python.org/pipermail/python-dev/2010-November/105476.html + underscore where needed) or finally documenting them; + see http://mail.python.org/pipermail/python-dev/2010-November/105476.html -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Jan 7 01:31:31 2011 From: python-checkins at python.org (brett.cannon) Date: Fri, 07 Jan 2011 01:31:31 +0100 Subject: [Python-checkins] devguide: TODO about going through stagnant issues. Message-ID: brett.cannon pushed f2c7f67e707e to devguide: http://hg.python.org/devguide/rev/f2c7f67e707e changeset: 46:f2c7f67e707e tag: tip user: Brett Cannon date: Thu Jan 06 16:28:45 2011 -0800 summary: TODO about going through stagnant issues. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -91,6 +91,9 @@ underscore where needed) or finally documenting them; see http://mail.python.org/pipermail/python-dev/2010-November/105476.html +.. todo:: + Think about suggesting going through stagnant issues (rather advanced) + .. _buildbots: http://python.org/dev/buildbot/ -- Repository URL: http://hg.python.org/devguide From solipsis at pitrou.net Fri Jan 7 05:10:16 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Fri, 07 Jan 2011 05:10:16 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r87813): sum=0 Message-ID: py3k results for svn r87813 (hg cset 4db13b4e76aa) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflogf0HCbA', '-x'] From python-checkins at python.org Fri Jan 7 05:29:15 2011 From: python-checkins at python.org (phillip.eby) Date: Fri, 7 Jan 2011 05:29:15 +0100 (CET) Subject: [Python-checkins] r87814 - peps/trunk/pep-3333.txt Message-ID: <20110107042915.1FF96EE9AF@mail.python.org> Author: phillip.eby Date: Fri Jan 7 05:29:14 2011 New Revision: 87814 Log: Make CGI example correct for Py3 Modified: peps/trunk/pep-3333.txt Modified: peps/trunk/pep-3333.txt ============================================================================== --- peps/trunk/pep-3333.txt (original) +++ peps/trunk/pep-3333.txt Fri Jan 7 05:29:14 2011 @@ -315,8 +315,8 @@ sys.stdout.write('%s: %s\r\n' % header) sys.stdout.write('\r\n') - sys.stdout.write(data) # TODO: this needs to be binary on Py3 - sys.stdout.flush() + sys.stdout.buffer.write(data) + sys.stdout.buffer.flush() def start_response(status, response_headers, exc_info=None): if exc_info: From python-checkins at python.org Fri Jan 7 16:39:28 2011 From: python-checkins at python.org (phillip.eby) Date: Fri, 7 Jan 2011 16:39:28 +0100 (CET) Subject: [Python-checkins] r87815 - peps/trunk/pep-3333.txt Message-ID: <20110107153928.3CE34EE988@mail.python.org> Author: phillip.eby Date: Fri Jan 7 16:39:27 2011 New Revision: 87815 Log: More bytes I/O fixes Modified: peps/trunk/pep-3333.txt Modified: peps/trunk/pep-3333.txt ============================================================================== --- peps/trunk/pep-3333.txt (original) +++ peps/trunk/pep-3333.txt Fri Jan 7 16:39:27 2011 @@ -310,9 +310,9 @@ elif not headers_sent: # Before the first output, send the stored headers status, response_headers = headers_sent[:] = headers_set - sys.stdout.write('Status: %s\r\n' % status) + sys.stdout.buffer.write('Status: %s\r\n' % status) for header in response_headers: - sys.stdout.write('%s: %s\r\n' % header) + sys.stdout.buffer.write('%s: %s\r\n' % header) sys.stdout.write('\r\n') sys.stdout.buffer.write(data) From python-checkins at python.org Fri Jan 7 16:45:26 2011 From: python-checkins at python.org (phillip.eby) Date: Fri, 7 Jan 2011 16:45:26 +0100 (CET) Subject: [Python-checkins] r87816 - peps/trunk/pep-3333.txt Message-ID: <20110107154526.4B42CEEA31@mail.python.org> Author: phillip.eby Date: Fri Jan 7 16:45:26 2011 New Revision: 87816 Log: Fix re-raise syntax for Python 3 Modified: peps/trunk/pep-3333.txt Modified: peps/trunk/pep-3333.txt ============================================================================== --- peps/trunk/pep-3333.txt (original) +++ peps/trunk/pep-3333.txt Fri Jan 7 16:45:26 2011 @@ -323,7 +323,7 @@ try: if headers_sent: # Re-raise original exception if headers sent - raise exc_info[0], exc_info[1], exc_info[2] + raise exc_info[1].with_traceback(exc_info[2]) finally: exc_info = None # avoid dangling circular ref elif headers_set: @@ -874,9 +874,9 @@ However, if ``exc_info`` is provided, and the HTTP headers have already been sent, ``start_response`` **must** raise an error, and **should** -raise the ``exc_info`` tuple. That is:: +re-raise using the ``exc_info`` tuple. That is:: - raise exc_info[0], exc_info[1], exc_info[2] + raise exc_info[1].with_traceback(exc_info[2]) This will re-raise the exception trapped by the application, and in principle should abort the application. (It is not safe for the From python-checkins at python.org Fri Jan 7 16:46:57 2011 From: python-checkins at python.org (phillip.eby) Date: Fri, 7 Jan 2011 16:46:57 +0100 (CET) Subject: [Python-checkins] r87817 - peps/trunk/pep-3333.txt Message-ID: <20110107154657.8EC58EEA0F@mail.python.org> Author: phillip.eby Date: Fri Jan 7 16:46:57 2011 New Revision: 87817 Log: Note that code samples are Python 3 now (I hope!) Modified: peps/trunk/pep-3333.txt Modified: peps/trunk/pep-3333.txt ============================================================================== --- peps/trunk/pep-3333.txt (original) +++ peps/trunk/pep-3333.txt Fri Jan 7 16:46:57 2011 @@ -17,7 +17,8 @@ This is an updated version of PEP 333, modified slightly to improve usability under Python 3, and to incorporate several long-standing -de-facto amendments to the WSGI protocol. +de-facto amendments to the WSGI protocol. (Its code samples have +also been ported to Python 3.) While for procedural reasons [6]_, this must be a distinct PEP, no changes were made that invalidate previously-compliant servers or From python-checkins at python.org Fri Jan 7 16:53:02 2011 From: python-checkins at python.org (phillip.eby) Date: Fri, 7 Jan 2011 16:53:02 +0100 (CET) Subject: [Python-checkins] r87818 - peps/trunk/pep-3333.txt Message-ID: <20110107155302.BB786EEA07@mail.python.org> Author: phillip.eby Date: Fri Jan 7 16:53:02 2011 New Revision: 87818 Log: Need to actually encode headers being sent... Modified: peps/trunk/pep-3333.txt Modified: peps/trunk/pep-3333.txt ============================================================================== --- peps/trunk/pep-3333.txt (original) +++ peps/trunk/pep-3333.txt Fri Jan 7 16:53:02 2011 @@ -283,12 +283,15 @@ enc, esc = sys.getfilesystemencoding(), 'surrogateescape' - def wsgi_string(u): + def unicode_to_wsgi(u): # Convert an environment variable to a WSGI "bytes-as-unicode" string return u.encode(enc, esc).decode('iso-8859-1') + def wsgi_to_bytes(s): + return s.encode('iso-8859-1') + def run_with_cgi(application): - environ = {k: wsgi_string(v) for k,v in os.environ.items()} + environ = {k: unicode_to_wsgi(v) for k,v in os.environ.items()} environ['wsgi.input'] = sys.stdin environ['wsgi.errors'] = sys.stderr environ['wsgi.version'] = (1, 0) @@ -305,19 +308,21 @@ headers_sent = [] def write(data): + out = sys.stdout.buffer + if not headers_set: raise AssertionError("write() before start_response()") elif not headers_sent: # Before the first output, send the stored headers status, response_headers = headers_sent[:] = headers_set - sys.stdout.buffer.write('Status: %s\r\n' % status) + out.write(wsgi_to_bytes('Status: %s\r\n' % status)) for header in response_headers: - sys.stdout.buffer.write('%s: %s\r\n' % header) - sys.stdout.write('\r\n') + out.write(wsgi_to_bytes('%s: %s\r\n' % header)) + out.write(wsgi_to_bytes('\r\n')) - sys.stdout.buffer.write(data) - sys.stdout.buffer.flush() + out.write(data) + out.flush() def start_response(status, response_headers, exc_info=None): if exc_info: From python-checkins at python.org Fri Jan 7 16:56:14 2011 From: python-checkins at python.org (phillip.eby) Date: Fri, 7 Jan 2011 16:56:14 +0100 (CET) Subject: [Python-checkins] r87819 - peps/trunk/pep-3333.txt Message-ID: <20110107155614.67118EEA09@mail.python.org> Author: phillip.eby Date: Fri Jan 7 16:56:14 2011 New Revision: 87819 Log: Also, input is bytes, not unicode... Modified: peps/trunk/pep-3333.txt Modified: peps/trunk/pep-3333.txt ============================================================================== --- peps/trunk/pep-3333.txt (original) +++ peps/trunk/pep-3333.txt Fri Jan 7 16:56:14 2011 @@ -292,7 +292,7 @@ def run_with_cgi(application): environ = {k: unicode_to_wsgi(v) for k,v in os.environ.items()} - environ['wsgi.input'] = sys.stdin + environ['wsgi.input'] = sys.stdin.buffer environ['wsgi.errors'] = sys.stderr environ['wsgi.version'] = (1, 0) environ['wsgi.multithread'] = False From python-checkins at python.org Fri Jan 7 19:28:45 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 7 Jan 2011 19:28:45 +0100 (CET) Subject: [Python-checkins] r87820 - python/branches/py3k/Doc/library/exceptions.rst Message-ID: <20110107182845.CE25AEE9FF@mail.python.org> Author: georg.brandl Date: Fri Jan 7 19:28:45 2011 New Revision: 87820 Log: #10856: document (Base)Exception.args better. Modified: python/branches/py3k/Doc/library/exceptions.rst Modified: python/branches/py3k/Doc/library/exceptions.rst ============================================================================== --- python/branches/py3k/Doc/library/exceptions.rst (original) +++ python/branches/py3k/Doc/library/exceptions.rst Fri Jan 7 19:28:45 2011 @@ -18,12 +18,10 @@ The built-in exceptions listed below can be generated by the interpreter or built-in functions. Except where mentioned, they have an "associated value" -indicating the detailed cause of the error. This may be a string or a tuple -containing several items of information (e.g., an error code and a string -explaining the code). The associated value is usually passed to the exception -class's constructor. If the exception class is derived from the standard root -class :exc:`BaseException`, the associated value is present as the exception -instance's :attr:`args` attribute. +indicating the detailed cause of the error. This may be a string or a tuple of +several items of information (e.g., an error code and a string explaining the +code). The associated value is usually passed as arguments to the exception +class's constructor. User code can raise built-in exceptions. This can be used to test an exception handler or to report an error condition "just like" the situation in which the @@ -38,16 +36,32 @@ The following exceptions are used mostly as base classes for other exceptions. -.. XXX document with_traceback() - .. exception:: BaseException The base class for all built-in exceptions. It is not meant to be directly - inherited by user-defined classes (for that use :exc:`Exception`). If + inherited by user-defined classes (for that, use :exc:`Exception`). If :func:`bytes` or :func:`str` is called on an instance of this class, the - representation of the argument(s) to the instance are returned or the empty - string when there were no arguments. All arguments are stored in :attr:`args` - as a tuple. + representation of the argument(s) to the instance are returned, or the empty + string when there were no arguments. + + .. attribute:: args + + The tuple of arguments given to the exception constructor. Some built-in + exceptions (like :exc:`IOError`) expect a certain number of arguments and + assign a special meaning to the elements of this tuple, while others are + usually called only with a single string giving an error message. + + .. method:: with_traceback(tb) + + This method sets *tb* as the new traceback for the exception and returns + the exception object. It is usually used in exception handling code like + this:: + + try: + ... + except SomeException: + tb = sys.exc_info()[2] + raise OtherException(...).with_traceback(tb) .. exception:: Exception From python-checkins at python.org Fri Jan 7 19:33:07 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 7 Jan 2011 19:33:07 +0100 (CET) Subject: [Python-checkins] r87821 - python/branches/py3k/Doc/library/threading.rst Message-ID: <20110107183307.C565DEEA46@mail.python.org> Author: antoine.pitrou Date: Fri Jan 7 19:33:07 2011 New Revision: 87821 Log: Put link to source at the end. There's nothing edificating in threading.py. Modified: python/branches/py3k/Doc/library/threading.rst Modified: python/branches/py3k/Doc/library/threading.rst ============================================================================== --- python/branches/py3k/Doc/library/threading.rst (original) +++ python/branches/py3k/Doc/library/threading.rst Fri Jan 7 19:33:07 2011 @@ -28,11 +28,6 @@ However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously. -.. seealso:: - - Latest version of the :source:`threading module Python source code - ` - This module defines the following functions and objects: @@ -970,3 +965,9 @@ abide by this restriction will lead to intermittent exceptions and crashes during interpreter shutdown (as the late imports attempt to access machinery which is no longer in a valid state). + + +.. seealso:: + + Latest version of the :source:`threading module Python source code + ` From python-checkins at python.org Fri Jan 7 19:42:21 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 7 Jan 2011 19:42:21 +0100 (CET) Subject: [Python-checkins] r87822 - python/branches/py3k/Doc/library/atexit.rst Message-ID: <20110107184221.7FF47EEA0E@mail.python.org> Author: antoine.pitrou Date: Fri Jan 7 19:42:21 2011 New Revision: 87822 Log: atexit.py doesn't exist Modified: python/branches/py3k/Doc/library/atexit.rst Modified: python/branches/py3k/Doc/library/atexit.rst ============================================================================== --- python/branches/py3k/Doc/library/atexit.rst (original) +++ python/branches/py3k/Doc/library/atexit.rst Fri Jan 7 19:42:21 2011 @@ -11,11 +11,6 @@ functions. Functions thus registered are automatically executed upon normal interpreter termination. -.. seealso:: - - Latest version of the :source:`atexit Python source code - ` - Note: the functions registered via this module are not called when the program is killed by a signal not handled by Python, when a Python fatal internal error is detected, or when :func:`os._exit` is called. @@ -103,3 +98,4 @@ This obviously only works with functions that don't take arguments. + From python-checkins at python.org Fri Jan 7 19:43:14 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 7 Jan 2011 19:43:14 +0100 (CET) Subject: [Python-checkins] r87823 - python/branches/py3k/Doc/library/collections.rst Message-ID: <20110107184314.9C688EEA34@mail.python.org> Author: antoine.pitrou Date: Fri Jan 7 19:43:14 2011 New Revision: 87823 Log: Put those source links together Modified: python/branches/py3k/Doc/library/collections.rst Modified: python/branches/py3k/Doc/library/collections.rst ============================================================================== --- python/branches/py3k/Doc/library/collections.rst (original) +++ python/branches/py3k/Doc/library/collections.rst Fri Jan 7 19:43:14 2011 @@ -31,11 +31,6 @@ :ref:`abstract-base-classes` that can be used to test whether a class provides a particular interface, for example, whether it is hashable or a mapping. -.. seealso:: - - Latest version of the :source:`collections module Python source code - ` - :class:`Counter` objects ------------------------ @@ -1069,6 +1064,9 @@ .. seealso:: + * Latest version of the :source:`collections module Python source code + ` + * Latest version of the :source:`Python source code for the collections abstract base classes ` From python-checkins at python.org Fri Jan 7 19:47:22 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 7 Jan 2011 19:47:22 +0100 (CET) Subject: [Python-checkins] r87824 - in python/branches/py3k: Misc/NEWS Modules/_io/fileio.c Modules/main.c Parser/tokenizer.c Message-ID: <20110107184722.CCF36D4CC@mail.python.org> Author: victor.stinner Date: Fri Jan 7 19:47:22 2011 New Revision: 87824 Log: Issue #10841: set binary mode on files; the parser translates newlines On Windows, set the binary mode on stdin, stdout, stderr and all io.FileIO objects (to not translate newlines, \r\n <=> \n). The Python parser translates newlines (\r\n => \n). Modified: python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/_io/fileio.c python/branches/py3k/Modules/main.c python/branches/py3k/Parser/tokenizer.c Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Fri Jan 7 19:47:22 2011 @@ -8,6 +8,10 @@ Core and Builtins ----------------- +- Issue #10841: On Windows, set the binary mode on stdin, stdout, stderr and + all io.FileIO objects (to not translate newlines, \r\n <=> \n). The Python + parser translates newlines (\r\n => \n). + - Remove buffer API from stable ABI for now, see #10181. - Issue #8651: PyArg_Parse*() functions raise an OverflowError if the file Modified: python/branches/py3k/Modules/_io/fileio.c ============================================================================== --- python/branches/py3k/Modules/_io/fileio.c (original) +++ python/branches/py3k/Modules/_io/fileio.c Fri Jan 7 19:47:22 2011 @@ -388,6 +388,11 @@ goto error; } +#if defined(MS_WINDOWS) || defined(__CYGWIN__) + /* don't translate newlines (\r\n <=> \n) */ + _setmode(self->fd, O_BINARY); +#endif + if (PyObject_SetAttrString((PyObject *)self, "name", nameobj) < 0) goto error; Modified: python/branches/py3k/Modules/main.c ============================================================================== --- python/branches/py3k/Modules/main.c (original) +++ python/branches/py3k/Modules/main.c Fri Jan 7 19:47:22 2011 @@ -527,11 +527,14 @@ stdin_is_interactive = Py_FdIsInteractive(stdin, (char *)0); - if (Py_UnbufferedStdioFlag) { #if defined(MS_WINDOWS) || defined(__CYGWIN__) - _setmode(fileno(stdin), O_BINARY); - _setmode(fileno(stdout), O_BINARY); + /* don't translate newlines (\r\n <=> \n) */ + _setmode(fileno(stdin), O_BINARY); + _setmode(fileno(stdout), O_BINARY); + _setmode(fileno(stderr), O_BINARY); #endif + + if (Py_UnbufferedStdioFlag) { #ifdef HAVE_SETVBUF setvbuf(stdin, (char *)NULL, _IONBF, BUFSIZ); setvbuf(stdout, (char *)NULL, _IONBF, BUFSIZ); Modified: python/branches/py3k/Parser/tokenizer.c ============================================================================== --- python/branches/py3k/Parser/tokenizer.c (original) +++ python/branches/py3k/Parser/tokenizer.c Fri Jan 7 19:47:22 2011 @@ -892,6 +892,13 @@ } if (tok->prompt != NULL) { char *newtok = PyOS_Readline(stdin, stdout, tok->prompt); + if (newtok != NULL) { + char *translated = translate_newlines(newtok, 0, tok); + PyMem_FREE(newtok); + if (translated == NULL) + return EOF; + newtok = translated; + } #ifndef PGEN if (tok->encoding && newtok && *newtok) { /* Recode to UTF-8 */ From python-checkins at python.org Fri Jan 7 19:56:20 2011 From: python-checkins at python.org (victor.stinner) Date: Fri, 7 Jan 2011 19:56:20 +0100 (CET) Subject: [Python-checkins] r87825 - python/branches/py3k/Parser/tokenizer.c Message-ID: <20110107185620.1F23CEEA45@mail.python.org> Author: victor.stinner Date: Fri Jan 7 19:56:19 2011 New Revision: 87825 Log: Issue #10841: don't translate newlines for pgen Modified: python/branches/py3k/Parser/tokenizer.c Modified: python/branches/py3k/Parser/tokenizer.c ============================================================================== --- python/branches/py3k/Parser/tokenizer.c (original) +++ python/branches/py3k/Parser/tokenizer.c Fri Jan 7 19:56:19 2011 @@ -892,6 +892,7 @@ } if (tok->prompt != NULL) { char *newtok = PyOS_Readline(stdin, stdout, tok->prompt); +#ifndef PGEN if (newtok != NULL) { char *translated = translate_newlines(newtok, 0, tok); PyMem_FREE(newtok); @@ -899,7 +900,6 @@ return EOF; newtok = translated; } -#ifndef PGEN if (tok->encoding && newtok && *newtok) { /* Recode to UTF-8 */ Py_ssize_t buflen; From python-checkins at python.org Fri Jan 7 19:58:21 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 7 Jan 2011 19:58:21 +0100 (CET) Subject: [Python-checkins] r87826 - in python/branches/py3k/Doc/library: glob.rst quopri.rst uu.rst Message-ID: <20110107185821.68A65EEA40@mail.python.org> Author: antoine.pitrou Date: Fri Jan 7 19:58:21 2011 New Revision: 87826 Log: Put those "seealso"s together Modified: python/branches/py3k/Doc/library/glob.rst python/branches/py3k/Doc/library/quopri.rst python/branches/py3k/Doc/library/uu.rst Modified: python/branches/py3k/Doc/library/glob.rst ============================================================================== --- python/branches/py3k/Doc/library/glob.rst (original) +++ python/branches/py3k/Doc/library/glob.rst Fri Jan 7 19:58:21 2011 @@ -15,9 +15,6 @@ subshell. (For tilde and shell variable expansion, use :func:`os.path.expanduser` and :func:`os.path.expandvars`.) -.. seealso:: - - Latest version of the :source:`glob module Python source code ` .. function:: glob(pathname) @@ -53,3 +50,5 @@ Module :mod:`fnmatch` Shell-style filename (not path) expansion + Latest version of the :source:`glob module Python source code ` + Modified: python/branches/py3k/Doc/library/quopri.rst ============================================================================== --- python/branches/py3k/Doc/library/quopri.rst (original) +++ python/branches/py3k/Doc/library/quopri.rst Fri Jan 7 19:58:21 2011 @@ -17,11 +17,6 @@ :mod:`base64` module is more compact if there are many such characters, as when sending a graphics file. -.. seealso:: - - Latest version of the :source:`quopri module Python source code - ` - .. function:: decode(input, output, header=False) Decode the contents of the *input* file and write the resulting decoded binary @@ -63,3 +58,5 @@ Module :mod:`base64` Encode and decode MIME base64 data + Latest version of the :source:`quopri module Python source code + ` Modified: python/branches/py3k/Doc/library/uu.rst ============================================================================== --- python/branches/py3k/Doc/library/uu.rst (original) +++ python/branches/py3k/Doc/library/uu.rst Fri Jan 7 19:58:21 2011 @@ -21,10 +21,6 @@ This code was contributed by Lance Ellinghouse, and modified by Jack Jansen. -.. seealso:: - - Latest version of the :source:`uu module Python source code ` - The :mod:`uu` module defines the following functions: @@ -61,3 +57,4 @@ Module :mod:`binascii` Support module containing ASCII-to-binary and binary-to-ASCII conversions. + Latest version of the :source:`uu module Python source code ` From python-checkins at python.org Fri Jan 7 20:01:48 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 7 Jan 2011 20:01:48 +0100 (CET) Subject: [Python-checkins] r87827 - in python/branches/py3k/Doc/library: calendar.rst fnmatch.rst Message-ID: <20110107190148.E4267EE981@mail.python.org> Author: antoine.pitrou Date: Fri Jan 7 20:01:48 2011 New Revision: 87827 Log: Group seealsos Modified: python/branches/py3k/Doc/library/calendar.rst python/branches/py3k/Doc/library/fnmatch.rst Modified: python/branches/py3k/Doc/library/calendar.rst ============================================================================== --- python/branches/py3k/Doc/library/calendar.rst (original) +++ python/branches/py3k/Doc/library/calendar.rst Fri Jan 7 20:01:48 2011 @@ -21,10 +21,6 @@ calendar in Dershowitz and Reingold's book "Calendrical Calculations", where it's the base calendar for all computations. -.. seealso:: - - Latest version of the :source:`calendar module Python source code - ` .. class:: Calendar(firstweekday=0) @@ -314,3 +310,5 @@ Module :mod:`time` Low-level time related functions. + Latest version of the :source:`calendar module Python source code + ` Modified: python/branches/py3k/Doc/library/fnmatch.rst ============================================================================== --- python/branches/py3k/Doc/library/fnmatch.rst (original) +++ python/branches/py3k/Doc/library/fnmatch.rst Fri Jan 7 20:01:48 2011 @@ -33,10 +33,6 @@ a period are not special for this module, and are matched by the ``*`` and ``?`` patterns. -.. seealso:: - - Latest version of the :source:`fnmatch Python source code - ` .. function:: fnmatch(filename, pattern) @@ -93,3 +89,5 @@ Module :mod:`glob` Unix shell-style path expansion. + Latest version of the :source:`fnmatch Python source code + ` From python-checkins at python.org Fri Jan 7 20:16:13 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 7 Jan 2011 20:16:13 +0100 (CET) Subject: [Python-checkins] r87828 - python/branches/py3k/Doc/library/queue.rst Message-ID: <20110107191613.0E948EEA45@mail.python.org> Author: antoine.pitrou Date: Fri Jan 7 20:16:12 2011 New Revision: 87828 Log: Mention multiprocessing.Queue in the queue docs Modified: python/branches/py3k/Doc/library/queue.rst Modified: python/branches/py3k/Doc/library/queue.rst ============================================================================== --- python/branches/py3k/Doc/library/queue.rst (original) +++ python/branches/py3k/Doc/library/queue.rst Fri Jan 7 20:16:12 2011 @@ -19,10 +19,6 @@ the entries are kept sorted (using the :mod:`heapq` module) and the lowest valued entry is retrieved first. -.. seealso:: - - Latest version of the :source:`queue module Python source code - ` The :mod:`queue` module defines the following classes and exceptions: @@ -180,3 +176,12 @@ q.join() # block until all tasks are done + +.. seealso:: + + Class :class:`multiprocessing.Queue` + A queue class for use in a multi-processing (rather than multi-threading) + context. + + Latest version of the :source:`queue module Python source code + ` From python-checkins at python.org Fri Jan 7 20:59:19 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Fri, 7 Jan 2011 20:59:19 +0100 (CET) Subject: [Python-checkins] r87829 - in python/branches/py3k: Doc/library/time.rst Lib/test/test_time.py Misc/NEWS Modules/timemodule.c Message-ID: <20110107195919.5BCF0EE52@mail.python.org> Author: alexander.belopolsky Date: Fri Jan 7 20:59:19 2011 New Revision: 87829 Log: Issue #10827: Changed the rules for 2-digit years. The time.asctime function will now format any year when time.accept2dyear is false and will accept years >= 1000 otherwise. The year range accepted by time.mktime and time.strftime is still system dependent, but time.mktime will now accept full range supported by the OS. Conversion of 2-digit years to 4-digit is deprecated. Modified: python/branches/py3k/Doc/library/time.rst python/branches/py3k/Lib/test/test_time.py python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Doc/library/time.rst ============================================================================== --- python/branches/py3k/Doc/library/time.rst (original) +++ python/branches/py3k/Doc/library/time.rst Fri Jan 7 20:59:19 2011 @@ -24,9 +24,9 @@ .. index:: single: Year 2038 -* The functions in this module do not handle dates and times before the epoch or +* The functions in this module may not handle dates and times before the epoch or far in the future. The cut-off point in the future is determined by the C - library; for Unix, it is typically in 2038. + library; for 32-bit systems, it is typically in 2038. .. index:: single: Year 2000 @@ -34,20 +34,31 @@ .. _time-y2kissues: -* **Year 2000 (Y2K) issues**: Python depends on the platform's C library, which +* **Year 2000 (Y2K) issues**: Python depends on the platform's C library, which generally doesn't have year 2000 issues, since all dates and times are - represented internally as seconds since the epoch. Functions accepting a - :class:`struct_time` (see below) generally require a 4-digit year. For backward - compatibility, 2-digit years are supported if the module variable - ``accept2dyear`` is a non-zero integer; this variable is initialized to ``1`` - unless the environment variable :envvar:`PYTHONY2K` is set to a non-empty - string, in which case it is initialized to ``0``. Thus, you can set - :envvar:`PYTHONY2K` to a non-empty string in the environment to require 4-digit - years for all year input. When 2-digit years are accepted, they are converted - according to the POSIX or X/Open standard: values 69-99 are mapped to 1969-1999, - and values 0--68 are mapped to 2000--2068. Values 100--1899 are always illegal. - Note that this is new as of Python 1.5.2(a2); earlier versions, up to Python - 1.5.1 and 1.5.2a1, would add 1900 to year values below 1900. + represented internally as seconds since the epoch. Function :func:`strptime` + can parse 2-digit years when given ``%y`` format code. When 2-digit years are + parsed, they are converted according to the POSIX and ISO C standards: values + 69--99 are mapped to 1969--1999, and values 0--68 are mapped to 2000--2068. + + For backward compatibility, years with less than 4 digits are treated + specially by :func:`asctime`, :func:`mktime`, and :func:`strftime` functions + that operate on a 9-tuple or :class:`struct_time` values. If year (the first + value in the 9-tuple) is specified with less than 4 digits, its interpretation + depends on the value of ``accept2dyear`` variable. + + If ``accept2dyear`` is true (default), a backward compatibility behavior is + invoked as follows: + + - for 2-digit year, century is guessed according to POSIX rules for + ``%y`` strptime format. A deprecation warning is issued when century + information is guessed in this way. + + - for 3-digit or negative year, a :exc:`ValueError` exception is raised. + + If ``accept2dyear`` is false (set by the program or as a result of a + non-empty value assigned to ``PYTHONY2K`` environment variable) all year + values are interpreted as given. .. index:: single: UTC Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Fri Jan 7 20:59:19 2011 @@ -3,6 +3,7 @@ import unittest import locale import sysconfig +import warnings class TimeTestCase(unittest.TestCase): @@ -19,10 +20,10 @@ time.clock() def test_conversions(self): - self.assertTrue(time.ctime(self.t) - == time.asctime(time.localtime(self.t))) - self.assertTrue(int(time.mktime(time.localtime(self.t))) - == int(self.t)) + self.assertEqual(time.ctime(self.t), + time.asctime(time.localtime(self.t))) + self.assertEqual(int(time.mktime(time.localtime(self.t))), + int(self.t)) def test_sleep(self): time.sleep(1.2) @@ -44,7 +45,7 @@ # Check year [1900, max(int)] self.assertRaises(ValueError, func, - (1899, 1, 1, 0, 0, 0, 0, 1, -1)) + (999, 1, 1, 0, 0, 0, 0, 1, -1)) if time.accept2dyear: self.assertRaises(ValueError, func, (-1, 1, 1, 0, 0, 0, 0, 1, -1)) @@ -97,7 +98,8 @@ # No test for daylight savings since strftime() does not change output # based on its value. expected = "2000 01 01 00 00 00 1 001" - result = time.strftime("%Y %m %d %H %M %S %w %j", (0,)*9) + with support.check_warnings(): + result = time.strftime("%Y %m %d %H %M %S %w %j", (0,)*9) self.assertEqual(expected, result) def test_strptime(self): @@ -141,14 +143,15 @@ self.assertEqual(time.ctime(t), 'Sun Sep 16 01:03:52 1973') t = time.mktime((2000, 1, 1, 0, 0, 0, 0, 0, -1)) self.assertEqual(time.ctime(t), 'Sat Jan 1 00:00:00 2000') - try: - bigval = time.mktime((10000, 1, 10) + (0,)*6) - except (ValueError, OverflowError): - # If mktime fails, ctime will fail too. This may happen - # on some platforms. - pass - else: - self.assertEqual(time.ctime(bigval)[-5:], '10000') + for year in [-100, 100, 1000, 2000, 10000]: + try: + testval = time.mktime((year, 1, 10) + (0,)*6) + except (ValueError, OverflowError): + # If mktime fails, ctime will fail too. This may happen + # on some platforms. + pass + else: + self.assertEqual(time.ctime(testval)[20:], str(year)) @unittest.skipIf(not hasattr(time, "tzset"), "time module has no attribute tzset") @@ -239,14 +242,14 @@ gt1 = time.gmtime(None) t0 = time.mktime(gt0) t1 = time.mktime(gt1) - self.assertTrue(0 <= (t1-t0) < 0.2) + self.assertAlmostEqual(t1, t0, delta=0.2) def test_localtime_without_arg(self): lt0 = time.localtime() lt1 = time.localtime(None) t0 = time.mktime(lt0) t1 = time.mktime(lt1) - self.assertTrue(0 <= (t1-t0) < 0.2) + self.assertAlmostEqual(t1, t0, delta=0.2) class TestLocale(unittest.TestCase): def setUp(self): @@ -274,16 +277,18 @@ time.accept2dyear = self.saved_accept2dyear def yearstr(self, y): - return time.strftime('%Y', (y,) + (0,) * 8) + # return time.strftime('%Y', (y,) + (0,) * 8) + return time.asctime((y,) + (0,) * 8).split()[-1] def test_2dyear(self): - self.assertEqual(self.yearstr(0), '2000') - self.assertEqual(self.yearstr(69), '1969') - self.assertEqual(self.yearstr(68), '2068') - self.assertEqual(self.yearstr(99), '1999') + with support.check_warnings(): + self.assertEqual(self.yearstr(0), '2000') + self.assertEqual(self.yearstr(69), '1969') + self.assertEqual(self.yearstr(68), '2068') + self.assertEqual(self.yearstr(99), '1999') def test_invalid(self): - self.assertRaises(ValueError, self.yearstr, 1899) + self.assertRaises(ValueError, self.yearstr, 999) self.assertRaises(ValueError, self.yearstr, 100) self.assertRaises(ValueError, self.yearstr, -1) @@ -293,10 +298,15 @@ class TestDontAccept2Year(TestAccept2Year): accept2dyear = 0 def test_2dyear(self): - self.assertRaises(ValueError, self.yearstr, 0) - self.assertRaises(ValueError, self.yearstr, 69) - self.assertRaises(ValueError, self.yearstr, 68) - self.assertRaises(ValueError, self.yearstr, 99) + self.assertEqual(self.yearstr(0), '0') + self.assertEqual(self.yearstr(69), '69') + self.assertEqual(self.yearstr(68), '68') + self.assertEqual(self.yearstr(99), '99') + self.assertEqual(self.yearstr(999), '999') + self.assertEqual(self.yearstr(9999), '9999') + + def test_invalid(self): + pass class TestDontAccept2YearBool(TestDontAccept2Year): accept2dyear = False Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Fri Jan 7 20:59:19 2011 @@ -36,6 +36,14 @@ Library ------- +- Issue #10827: Changed the rules for 2-digit years. The time.asctime + function will now format any year when ``time.accept2dyear`` is + false and will accept years >= 1000 otherwise. The year range + accepted by ``time.mktime`` and ``time.strftime`` is still system + dependent, but ``time.mktime`` will now accept full range supported + by the OS. Conversion of 2-digit years to 4-digit is deprecated. + + - Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Fri Jan 7 20:59:19 2011 @@ -312,34 +312,42 @@ &p->tm_wday, &p->tm_yday, &p->tm_isdst)) return 0; - /* XXX: Why 1900? If the goal is to interpret 2-digit years as those in - * 20th / 21st century according to the POSIX standard, we can just treat - * 0 <= y < 100 as special. Year 100 is probably too ambiguous and should - * be rejected, but years 101 through 1899 can be passed through. + /* If year is specified with less than 4 digits, its interpretation + * depends on the accept2dyear value. + * + * If accept2dyear is true (default), a backward compatibility behavior is + * invoked as follows: + * + * - for 2-digit year, century is guessed according to POSIX rules for + * %y strptime format: 21st century for y < 69, 20th century + * otherwise. A deprecation warning is issued when century + * information is guessed in this way. + * + * - for 3-digit or negative year, a ValueError exception is raised. + * + * If accept2dyear is false (set by the program or as a result of a + * non-empty value assigned to PYTHONY2K environment variable) all year + * values are interpreted as given. */ - if (y < 1900) { + if (y < 1000) { PyObject *accept = PyDict_GetItemString(moddict, "accept2dyear"); int acceptval = accept != NULL && PyObject_IsTrue(accept); if (acceptval == -1) return 0; if (acceptval) { - if (69 <= y && y <= 99) - y += 1900; - else if (0 <= y && y <= 68) + if (0 <= y && y < 69) y += 2000; + else if (69 <= y && y < 100) + y += 1900; else { PyErr_SetString(PyExc_ValueError, "year out of range"); return 0; } - } - /* XXX: When accept2dyear is false, we don't have to reject y < 1900. - * Consider removing the following else-clause. */ - else { - PyErr_SetString(PyExc_ValueError, - "year out of range"); - return 0; + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "Century info guessed for a 2-digit year.", 1) != 0) + return 0; } } p->tm_year = y - 1900; @@ -462,6 +470,15 @@ else if (!gettmarg(tup, &buf) || !checktm(&buf)) return NULL; + /* XXX: Reportedly, some systems have issues formating dates prior to year + * 1900. These systems should be identified and this check should be + * moved to appropriate system specific section below. */ + if (buf.tm_year < 0) { + PyErr_Format(PyExc_ValueError, "year=%d is before 1900; " + "the strftime() method requires year >= 1900", + buf.tm_year + 1900); + } + /* Normalize tm_isdst just in case someone foolishly implements %Z based on the assumption that tm_isdst falls within the range of [-1, 1] */ From python-checkins at python.org Fri Jan 7 21:33:09 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 7 Jan 2011 21:33:09 +0100 (CET) Subject: [Python-checkins] r87830 - python/branches/py3k/Doc/library/queue.rst Message-ID: <20110107203309.2A14AEE52@mail.python.org> Author: raymond.hettinger Date: Fri Jan 7 21:33:09 2011 New Revision: 87830 Log: Combine the two seealso sections. Modified: python/branches/py3k/Doc/library/queue.rst Modified: python/branches/py3k/Doc/library/queue.rst ============================================================================== --- python/branches/py3k/Doc/library/queue.rst (original) +++ python/branches/py3k/Doc/library/queue.rst Fri Jan 7 21:33:09 2011 @@ -60,12 +60,6 @@ Exception raised when non-blocking :meth:`put` (or :meth:`put_nowait`) is called on a :class:`Queue` object which is full. -.. seealso:: - - :class:`collections.deque` is an alternative implementation of unbounded - queues with fast atomic :func:`append` and :func:`popleft` operations that - do not require locking. - .. _queueobjects: @@ -183,5 +177,9 @@ A queue class for use in a multi-processing (rather than multi-threading) context. + :class:`collections.deque` is an alternative implementation of unbounded + queues with fast atomic :func:`append` and :func:`popleft` operations that + do not require locking. + Latest version of the :source:`queue module Python source code ` From python-checkins at python.org Fri Jan 7 21:58:26 2011 From: python-checkins at python.org (georg.brandl) Date: Fri, 7 Jan 2011 21:58:26 +0100 (CET) Subject: [Python-checkins] r87831 - python/branches/py3k/Doc/library/queue.rst Message-ID: <20110107205826.1E204EE988@mail.python.org> Author: georg.brandl Date: Fri Jan 7 21:58:25 2011 New Revision: 87831 Log: Fix indent. Modified: python/branches/py3k/Doc/library/queue.rst Modified: python/branches/py3k/Doc/library/queue.rst ============================================================================== --- python/branches/py3k/Doc/library/queue.rst (original) +++ python/branches/py3k/Doc/library/queue.rst Fri Jan 7 21:58:25 2011 @@ -177,7 +177,7 @@ A queue class for use in a multi-processing (rather than multi-threading) context. - :class:`collections.deque` is an alternative implementation of unbounded + :class:`collections.deque` is an alternative implementation of unbounded queues with fast atomic :func:`append` and :func:`popleft` operations that do not require locking. From python-checkins at python.org Fri Jan 7 22:04:30 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 7 Jan 2011 22:04:30 +0100 (CET) Subject: [Python-checkins] r87832 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110107210430.F2676EEA43@mail.python.org> Author: raymond.hettinger Date: Fri Jan 7 22:04:30 2011 New Revision: 87832 Log: Update the digest of PEP 3333 based on comments for Phillip Eby. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Fri Jan 7 22:04:30 2011 @@ -376,18 +376,32 @@ The *native strings* are always of type :class:`str` but are restricted to code points between *u0000* through *u00FF* which are translatable to bytes using -*Latin-1* encoding. These strings are used with :func:`start_response` as -response headers or statuses and must follow :rfc:`2616` with respect to +*Latin-1* encoding. These strings are used for the keys and values in the +environ dictionary and for response headers and statuses in the +:func:`start_response` function. They must follow :rfc:`2616` with respect to encoding. That is, they must either be *ISO-8859-1* characters or use :rfc:`2047` MIME encoding. -To make the environment accessible using native strings, the :mod:`wsgiref` -module has a new function, :func:`wsgiref.handlers.read_environ` which -transcodes CGI variables from :attr:`os.environ` into native strings and returns -a new dictionary. This function provides a WSGI native string friendly -abstraction which is especially helpful given that the environment variables are -handled differently on various operating systems (native unicode on Windows or -UTF-8 encoded bytes on some Unix installations). +For developers porting WSGI applications from Python 2, here are the salient +points: + +* If the app already used strings for headers in Python 2, no change is needed. + +* If instead, the app encoded output headers or decoded input headers, then the + headers will need to be re-encoded to Latin-1. For example, an output header + encoded in utf-8 was using ``h.encode('utf-8')`` now needs to convert from + bytes to native strings using ``h.encode('utf-8').decode('latin-1')``. + +* Values yielded by an application or sent using the :meth:`write` method + must be byte strings. The :func:`start_response` function and environ + must use native strings. The two cannot be mixed. + +For server implementers writing CGI-to-WSGI pathways or other CGI-style +protocols, the users must to be able access the environment using native strings +eventhough the underlying platform may have a different convention. To bridge +this gap, the :mod:`wsgiref` module has a new function, +:func:`wsgiref.handlers.read_environ` for transcoding CGI variables from +:attr:`os.environ` into native strings and returning a new dictionary. .. seealso:: From python-checkins at python.org Fri Jan 7 22:17:56 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 7 Jan 2011 22:17:56 +0100 (CET) Subject: [Python-checkins] r87833 - python/branches/py3k/Doc/library/collections.rst Message-ID: <20110107211756.E9C17EEA71@mail.python.org> Author: raymond.hettinger Date: Fri Jan 7 22:17:56 2011 New Revision: 87833 Log: Revert r87823 which moved the source link to the wrong section. Modified: python/branches/py3k/Doc/library/collections.rst Modified: python/branches/py3k/Doc/library/collections.rst ============================================================================== --- python/branches/py3k/Doc/library/collections.rst (original) +++ python/branches/py3k/Doc/library/collections.rst Fri Jan 7 22:17:56 2011 @@ -31,6 +31,11 @@ :ref:`abstract-base-classes` that can be used to test whether a class provides a particular interface, for example, whether it is hashable or a mapping. +.. seealso:: + + Latest version of the :source:`collections module Python source code + ` + :class:`Counter` objects ------------------------ @@ -1064,9 +1069,6 @@ .. seealso:: - * Latest version of the :source:`collections module Python source code - ` - * Latest version of the :source:`Python source code for the collections abstract base classes ` From python-checkins at python.org Fri Jan 7 22:44:05 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 7 Jan 2011 22:44:05 +0100 (CET) Subject: [Python-checkins] r87834 - in python/branches/py3k: Misc/ACKS Misc/NEWS Objects/obmalloc.c Message-ID: <20110107214405.9F663EEA4E@mail.python.org> Author: antoine.pitrou Date: Fri Jan 7 22:43:59 2011 New Revision: 87834 Log: Issue #8020: Avoid a crash where the small objects allocator would read non-Python managed memory while it is being modified by another thread. Patch by Matt Bandy. Modified: python/branches/py3k/Misc/ACKS python/branches/py3k/Misc/NEWS python/branches/py3k/Objects/obmalloc.c Modified: python/branches/py3k/Misc/ACKS ============================================================================== --- python/branches/py3k/Misc/ACKS (original) +++ python/branches/py3k/Misc/ACKS Fri Jan 7 22:43:59 2011 @@ -46,6 +46,7 @@ Greg Ball Luigi Ballabio Jeff Balogh +Matt Bandy Michael J. Barber Chris Barker Nick Barnes Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Fri Jan 7 22:43:59 2011 @@ -36,6 +36,10 @@ Library ------- +- Issue #8020: Avoid a crash where the small objects allocator would read + non-Python managed memory while it is being modified by another thread. + Patch by Matt Bandy. + - Issue #10827: Changed the rules for 2-digit years. The time.asctime function will now format any year when ``time.accept2dyear`` is false and will accept years >= 1000 otherwise. The year range Modified: python/branches/py3k/Objects/obmalloc.c ============================================================================== --- python/branches/py3k/Objects/obmalloc.c (original) +++ python/branches/py3k/Objects/obmalloc.c Fri Jan 7 22:43:59 2011 @@ -682,11 +682,19 @@ obmalloc in a small constant time, independent of the number of arenas obmalloc controls. Since this test is needed at every entry point, it's extremely desirable that it be this fast. + +Since Py_ADDRESS_IN_RANGE may be reading from memory which was not allocated +by Python, it is important that (POOL)->arenaindex is read only once, as +another thread may be concurrently modifying the value without holding the +GIL. To accomplish this, the arenaindex_temp variable is used to store +(POOL)->arenaindex for the duration of the Py_ADDRESS_IN_RANGE macro's +execution. The caller of the macro is responsible for declaring this +variable. */ #define Py_ADDRESS_IN_RANGE(P, POOL) \ - ((POOL)->arenaindex < maxarenas && \ - (uptr)(P) - arenas[(POOL)->arenaindex].address < (uptr)ARENA_SIZE && \ - arenas[(POOL)->arenaindex].address != 0) + ((arenaindex_temp = (POOL)->arenaindex) < maxarenas && \ + (uptr)(P) - arenas[arenaindex_temp].address < (uptr)ARENA_SIZE && \ + arenas[arenaindex_temp].address != 0) /* This is only useful when running memory debuggers such as @@ -945,6 +953,9 @@ block *lastfree; poolp next, prev; uint size; +#ifndef Py_USING_MEMORY_DEBUGGER + uint arenaindex_temp; +#endif if (p == NULL) /* free(NULL) has no effect */ return; @@ -1167,6 +1178,9 @@ void *bp; poolp pool; size_t size; +#ifndef Py_USING_MEMORY_DEBUGGER + uint arenaindex_temp; +#endif if (p == NULL) return PyObject_Malloc(nbytes); @@ -1867,8 +1881,10 @@ int Py_ADDRESS_IN_RANGE(void *P, poolp pool) { - return pool->arenaindex < maxarenas && - (uptr)P - arenas[pool->arenaindex].address < (uptr)ARENA_SIZE && - arenas[pool->arenaindex].address != 0; + uint arenaindex_temp = pool->arenaindex; + + return arenaindex_temp < maxarenas && + (uptr)P - arenas[arenaindex_temp].address < (uptr)ARENA_SIZE && + arenas[arenaindex_temp].address != 0; } #endif From python-checkins at python.org Fri Jan 7 22:47:02 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 7 Jan 2011 22:47:02 +0100 (CET) Subject: [Python-checkins] r87835 - python/branches/py3k/Misc/NEWS Message-ID: <20110107214702.BBFA5EEA24@mail.python.org> Author: antoine.pitrou Date: Fri Jan 7 22:47:02 2011 New Revision: 87835 Log: Put NEWS entry in the right section. Modified: python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Fri Jan 7 22:47:02 2011 @@ -8,6 +8,10 @@ Core and Builtins ----------------- +- Issue #8020: Avoid a crash where the small objects allocator would read + non-Python managed memory while it is being modified by another thread. + Patch by Matt Bandy. + - Issue #10841: On Windows, set the binary mode on stdin, stdout, stderr and all io.FileIO objects (to not translate newlines, \r\n <=> \n). The Python parser translates newlines (\r\n => \n). @@ -36,10 +40,6 @@ Library ------- -- Issue #8020: Avoid a crash where the small objects allocator would read - non-Python managed memory while it is being modified by another thread. - Patch by Matt Bandy. - - Issue #10827: Changed the rules for 2-digit years. The time.asctime function will now format any year when ``time.accept2dyear`` is false and will accept years >= 1000 otherwise. The year range From python-checkins at python.org Fri Jan 7 22:49:25 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 7 Jan 2011 22:49:25 +0100 (CET) Subject: [Python-checkins] r87836 - in python/branches/release31-maint: Misc/ACKS Misc/NEWS Objects/obmalloc.c Message-ID: <20110107214925.3E8F5EEA5E@mail.python.org> Author: antoine.pitrou Date: Fri Jan 7 22:49:25 2011 New Revision: 87836 Log: Merged revisions 87834 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87834 | antoine.pitrou | 2011-01-07 22:43:59 +0100 (ven., 07 janv. 2011) | 5 lines Issue #8020: Avoid a crash where the small objects allocator would read non-Python managed memory while it is being modified by another thread. Patch by Matt Bandy. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Misc/ACKS python/branches/release31-maint/Misc/NEWS python/branches/release31-maint/Objects/obmalloc.c Modified: python/branches/release31-maint/Misc/ACKS ============================================================================== --- python/branches/release31-maint/Misc/ACKS (original) +++ python/branches/release31-maint/Misc/ACKS Fri Jan 7 22:49:25 2011 @@ -39,6 +39,7 @@ Greg Ball Luigi Ballabio Jeff Balogh +Matt Bandy Michael J. Barber Chris Barker Nick Barnes Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Fri Jan 7 22:49:25 2011 @@ -10,6 +10,10 @@ Core and Builtins ----------------- +- Issue #8020: Avoid a crash where the small objects allocator would read + non-Python managed memory while it is being modified by another thread. + Patch by Matt Bandy. + - Issue #8278: On Windows and with a NTFS filesystem, os.stat() and os.utime() can now handle dates after 2038. Modified: python/branches/release31-maint/Objects/obmalloc.c ============================================================================== --- python/branches/release31-maint/Objects/obmalloc.c (original) +++ python/branches/release31-maint/Objects/obmalloc.c Fri Jan 7 22:49:25 2011 @@ -667,11 +667,19 @@ obmalloc in a small constant time, independent of the number of arenas obmalloc controls. Since this test is needed at every entry point, it's extremely desirable that it be this fast. + +Since Py_ADDRESS_IN_RANGE may be reading from memory which was not allocated +by Python, it is important that (POOL)->arenaindex is read only once, as +another thread may be concurrently modifying the value without holding the +GIL. To accomplish this, the arenaindex_temp variable is used to store +(POOL)->arenaindex for the duration of the Py_ADDRESS_IN_RANGE macro's +execution. The caller of the macro is responsible for declaring this +variable. */ #define Py_ADDRESS_IN_RANGE(P, POOL) \ - ((POOL)->arenaindex < maxarenas && \ - (uptr)(P) - arenas[(POOL)->arenaindex].address < (uptr)ARENA_SIZE && \ - arenas[(POOL)->arenaindex].address != 0) + ((arenaindex_temp = (POOL)->arenaindex) < maxarenas && \ + (uptr)(P) - arenas[arenaindex_temp].address < (uptr)ARENA_SIZE && \ + arenas[arenaindex_temp].address != 0) /* This is only useful when running memory debuggers such as @@ -923,6 +931,9 @@ block *lastfree; poolp next, prev; uint size; +#ifndef Py_USING_MEMORY_DEBUGGER + uint arenaindex_temp; +#endif if (p == NULL) /* free(NULL) has no effect */ return; @@ -1137,6 +1148,9 @@ void *bp; poolp pool; size_t size; +#ifndef Py_USING_MEMORY_DEBUGGER + uint arenaindex_temp; +#endif if (p == NULL) return PyObject_Malloc(nbytes); @@ -1758,8 +1772,10 @@ int Py_ADDRESS_IN_RANGE(void *P, poolp pool) { - return pool->arenaindex < maxarenas && - (uptr)P - arenas[pool->arenaindex].address < (uptr)ARENA_SIZE && - arenas[pool->arenaindex].address != 0; + uint arenaindex_temp = pool->arenaindex; + + return arenaindex_temp < maxarenas && + (uptr)P - arenas[arenaindex_temp].address < (uptr)ARENA_SIZE && + arenas[arenaindex_temp].address != 0; } #endif From python-checkins at python.org Fri Jan 7 22:49:44 2011 From: python-checkins at python.org (antoine.pitrou) Date: Fri, 7 Jan 2011 22:49:44 +0100 (CET) Subject: [Python-checkins] r87837 - in python/branches/release27-maint: Misc/ACKS Misc/NEWS Objects/obmalloc.c Message-ID: <20110107214944.CEA9EEEA4E@mail.python.org> Author: antoine.pitrou Date: Fri Jan 7 22:49:44 2011 New Revision: 87837 Log: Merged revisions 87834 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87834 | antoine.pitrou | 2011-01-07 22:43:59 +0100 (ven., 07 janv. 2011) | 5 lines Issue #8020: Avoid a crash where the small objects allocator would read non-Python managed memory while it is being modified by another thread. Patch by Matt Bandy. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Misc/ACKS python/branches/release27-maint/Misc/NEWS python/branches/release27-maint/Objects/obmalloc.c Modified: python/branches/release27-maint/Misc/ACKS ============================================================================== --- python/branches/release27-maint/Misc/ACKS (original) +++ python/branches/release27-maint/Misc/ACKS Fri Jan 7 22:49:44 2011 @@ -41,6 +41,7 @@ Greg Ball Luigi Ballabio Jeff Balogh +Matt Bandy Michael J. Barber Chris Barker Nick Barnes Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Fri Jan 7 22:49:44 2011 @@ -9,6 +9,10 @@ Core and Builtins ----------------- +- Issue #8020: Avoid a crash where the small objects allocator would read + non-Python managed memory while it is being modified by another thread. + Patch by Matt Bandy. + - Issue #8278: On Windows and with a NTFS filesystem, os.stat() and os.utime() can now handle dates after 2038. @@ -25,6 +29,13 @@ Library ------- +- Issue #10827: Changed the rules for 2-digit years. The time.asctime + function will now format any year when ``time.accept2dyear`` is + false and will accept years >= 1000 otherwise. The year range + accepted by ``time.mktime`` and ``time.strftime`` is still system + dependent, but ``time.mktime`` will now accept full range supported + by the OS. Conversion of 2-digit years to 4-digit is deprecated. + - Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. Modified: python/branches/release27-maint/Objects/obmalloc.c ============================================================================== --- python/branches/release27-maint/Objects/obmalloc.c (original) +++ python/branches/release27-maint/Objects/obmalloc.c Fri Jan 7 22:49:44 2011 @@ -682,11 +682,19 @@ obmalloc in a small constant time, independent of the number of arenas obmalloc controls. Since this test is needed at every entry point, it's extremely desirable that it be this fast. + +Since Py_ADDRESS_IN_RANGE may be reading from memory which was not allocated +by Python, it is important that (POOL)->arenaindex is read only once, as +another thread may be concurrently modifying the value without holding the +GIL. To accomplish this, the arenaindex_temp variable is used to store +(POOL)->arenaindex for the duration of the Py_ADDRESS_IN_RANGE macro's +execution. The caller of the macro is responsible for declaring this +variable. */ #define Py_ADDRESS_IN_RANGE(P, POOL) \ - ((POOL)->arenaindex < maxarenas && \ - (uptr)(P) - arenas[(POOL)->arenaindex].address < (uptr)ARENA_SIZE && \ - arenas[(POOL)->arenaindex].address != 0) + ((arenaindex_temp = (POOL)->arenaindex) < maxarenas && \ + (uptr)(P) - arenas[arenaindex_temp].address < (uptr)ARENA_SIZE && \ + arenas[arenaindex_temp].address != 0) /* This is only useful when running memory debuggers such as @@ -945,6 +953,9 @@ block *lastfree; poolp next, prev; uint size; +#ifndef Py_USING_MEMORY_DEBUGGER + uint arenaindex_temp; +#endif if (p == NULL) /* free(NULL) has no effect */ return; @@ -1167,6 +1178,9 @@ void *bp; poolp pool; size_t size; +#ifndef Py_USING_MEMORY_DEBUGGER + uint arenaindex_temp; +#endif if (p == NULL) return PyObject_Malloc(nbytes); @@ -1865,8 +1879,10 @@ int Py_ADDRESS_IN_RANGE(void *P, poolp pool) { - return pool->arenaindex < maxarenas && - (uptr)P - arenas[pool->arenaindex].address < (uptr)ARENA_SIZE && - arenas[pool->arenaindex].address != 0; + uint arenaindex_temp = pool->arenaindex; + + return arenaindex_temp < maxarenas && + (uptr)P - arenas[arenaindex_temp].address < (uptr)ARENA_SIZE && + arenas[arenaindex_temp].address != 0; } #endif From python-checkins at python.org Fri Jan 7 22:54:18 2011 From: python-checkins at python.org (raymond.hettinger) Date: Fri, 7 Jan 2011 22:54:18 +0100 (CET) Subject: [Python-checkins] r87838 - python/branches/py3k/Doc/library/threading.rst Message-ID: <20110107215418.5D942EEA6B@mail.python.org> Author: raymond.hettinger Date: Fri Jan 7 22:54:18 2011 New Revision: 87838 Log: Revert r87821 which moved the source link to the wrong section (from the module intro covering the module to a section on thread imports). Modified: python/branches/py3k/Doc/library/threading.rst Modified: python/branches/py3k/Doc/library/threading.rst ============================================================================== --- python/branches/py3k/Doc/library/threading.rst (original) +++ python/branches/py3k/Doc/library/threading.rst Fri Jan 7 22:54:18 2011 @@ -28,6 +28,11 @@ However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously. +.. seealso:: + + Latest version of the :source:`threading module Python source code + ` + This module defines the following functions and objects: @@ -965,9 +970,3 @@ abide by this restriction will lead to intermittent exceptions and crashes during interpreter shutdown (as the late imports attempt to access machinery which is no longer in a valid state). - - -.. seealso:: - - Latest version of the :source:`threading module Python source code - ` From python-checkins at python.org Fri Jan 7 22:57:26 2011 From: python-checkins at python.org (r.david.murray) Date: Fri, 7 Jan 2011 22:57:26 +0100 (CET) Subject: [Python-checkins] r87839 - in python/branches/py3k: Lib/email/header.py Lib/email/test/test_email.py Misc/NEWS Message-ID: <20110107215726.3B131EEA67@mail.python.org> Author: r.david.murray Date: Fri Jan 7 22:57:25 2011 New Revision: 87839 Log: Fix formatting of values with embedded newlines when rfc2047 encoding Before this patch if a value being encoded had an embedded newline, the line following the newline would have no leading whitespace, and the whitespace it did have was encoded into the word. Now the existing whitespace gets turned into a blank, the way it does in other header reformatting, and the _continuation_ws gets added at the beginning of the encoded line. Modified: python/branches/py3k/Lib/email/header.py python/branches/py3k/Lib/email/test/test_email.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/email/header.py ============================================================================== --- python/branches/py3k/Lib/email/header.py (original) +++ python/branches/py3k/Lib/email/header.py Fri Jan 7 22:57:25 2011 @@ -305,10 +305,15 @@ self._continuation_ws, splitchars) for string, charset in self._chunks: lines = string.splitlines() - for line in lines: + formatter.feed(lines[0], charset) + for line in lines[1:]: + formatter.newline() + if charset.header_encoding is not None: + formatter.feed(self._continuation_ws, USASCII) + line = ' ' + line.lstrip() formatter.feed(line, charset) - if len(lines) > 1: - formatter.newline() + if len(lines) > 1: + formatter.newline() formatter.add_transition() return formatter._str(linesep) Modified: python/branches/py3k/Lib/email/test/test_email.py ============================================================================== --- python/branches/py3k/Lib/email/test/test_email.py (original) +++ python/branches/py3k/Lib/email/test/test_email.py Fri Jan 7 22:57:25 2011 @@ -968,6 +968,19 @@ """) + def test_long_rfc2047_header_with_embedded_fws(self): + h = Header(textwrap.dedent("""\ + We're going to pretend this header is in a non-ascii character set + \tto see if line wrapping with encoded words and embedded + folding white space works"""), + charset='utf-8', + header_name='Test') + self.assertEqual(h.encode()+'\n', textwrap.dedent("""\ + =?utf-8?q?We=27re_going_to_pretend_this_header_is_in_a_non-ascii_chara?= + =?utf-8?q?cter_set?= + =?utf-8?q?_to_see_if_line_wrapping_with_encoded_words_and_embedded?= + =?utf-8?q?_folding_white_space_works?=""")+'\n') + # Test mangling of "From " lines in the body of a message Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Fri Jan 7 22:57:25 2011 @@ -40,6 +40,11 @@ Library ------- +- email.header.Header was incorrectly encoding folding white space when + rfc2047-encoding header values with embedded newlines, leaving them + without folding whitespace. It now uses the continuation_ws, as it + does for continuation lines that it creates itself. + - Issue #10827: Changed the rules for 2-digit years. The time.asctime function will now format any year when ``time.accept2dyear`` is false and will accept years >= 1000 otherwise. The year range @@ -47,7 +52,6 @@ dependent, but ``time.mktime`` will now accept full range supported by the OS. Conversion of 2-digit years to 4-digit is deprecated. - - Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. From python-checkins at python.org Sat Jan 8 00:25:30 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 8 Jan 2011 00:25:30 +0100 (CET) Subject: [Python-checkins] r87840 - in python/branches/py3k: Doc/library/email.generator.rst Doc/library/email.header.rst Doc/library/email.message.rst Doc/whatsnew/3.2.rst Lib/email/charset.py Lib/email/header.py Lib/email/message.py Lib/email/test/test_email.py Misc/NEWS Message-ID: <20110107232530.94485EEA18@mail.python.org> Author: r.david.murray Date: Sat Jan 8 00:25:30 2011 New Revision: 87840 Log: #10686: recode non-ASCII headers to 'unknown-8bit' instead of ?s. This applies only when generating strings from non-RFC compliant binary input; it makes the existing recoding behavior more consistent (ie: now no data is lost when recoding). Modified: python/branches/py3k/Doc/library/email.generator.rst python/branches/py3k/Doc/library/email.header.rst python/branches/py3k/Doc/library/email.message.rst python/branches/py3k/Doc/whatsnew/3.2.rst python/branches/py3k/Lib/email/charset.py python/branches/py3k/Lib/email/header.py python/branches/py3k/Lib/email/message.py python/branches/py3k/Lib/email/test/test_email.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Doc/library/email.generator.rst ============================================================================== --- python/branches/py3k/Doc/library/email.generator.rst (original) +++ python/branches/py3k/Doc/library/email.generator.rst Sat Jan 8 00:25:30 2011 @@ -79,8 +79,8 @@ Messages parsed with a Bytes parser that have a :mailheader:`Content-Transfer-Encoding` of 8bit will be converted to a - use a 7bit Content-Transfer-Encoding. Any other non-ASCII bytes in the - message structure will be converted to '?' characters. + use a 7bit Content-Transfer-Encoding. Non-ASCII bytes in the headers + will be :rfc:`2047` encoded with a charset of `unknown-8bit`. .. versionchanged:: 3.2 Added support for re-encoding 8bit message bodies, and the *linesep* Modified: python/branches/py3k/Doc/library/email.header.rst ============================================================================== --- python/branches/py3k/Doc/library/email.header.rst (original) +++ python/branches/py3k/Doc/library/email.header.rst Sat Jan 8 00:25:30 2011 @@ -130,8 +130,14 @@ .. method:: __str__() - A helper for :class:`str`'s :func:`encode` method. Returns the header as - a Unicode string. + Returns an approximation of the :class:`Header` as a string, using an + unlimited line length. All pieces are converted to unicode using the + specified encoding and joined together appropriately. Any pieces with a + charset of `unknown-8bit` are decoded as `ASCII` using the `replace` + error handler. + + .. versionchanged:: 3.2 + Added handling for the `unknown-8bit` charset. .. method:: __eq__(other) Modified: python/branches/py3k/Doc/library/email.message.rst ============================================================================== --- python/branches/py3k/Doc/library/email.message.rst (original) +++ python/branches/py3k/Doc/library/email.message.rst Sat Jan 8 00:25:30 2011 @@ -169,9 +169,10 @@ Note that in all cases, any envelope header present in the message is not included in the mapping interface. - In a model generated from bytes, any header values that (in contravention - of the RFCs) contain non-ASCII bytes will have those bytes transformed - into '?' characters when the values are retrieved through this interface. + In a model generated from bytes, any header values that (in contravention of + the RFCs) contain non-ASCII bytes will, when retrieved through this + interface, be represented as :class:`~email.header.Header` objects with + a charset of `unknown-8bit`. .. method:: __len__() Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Sat Jan 8 00:25:30 2011 @@ -618,6 +618,8 @@ * Given bytes input to the model, :class:`~email.generator.Generator` will convert message bodies that have a :mailheader:`Content-Transfer-Encoding` of *8bit* to instead have a *7bit* :mailheader:`Content-Transfer-Encoding`. + XXX: Headers with Un-encoded non-ASCII bytes will be :rfc:`2047`\ -encoded + using the charset `unknown-8bit`. * A new class :class:`~email.generator.BytesGenerator` produces bytes as output, preserving any unchanged non-ASCII data that was present in the input used to Modified: python/branches/py3k/Lib/email/charset.py ============================================================================== --- python/branches/py3k/Lib/email/charset.py (original) +++ python/branches/py3k/Lib/email/charset.py Sat Jan 8 00:25:30 2011 @@ -28,6 +28,7 @@ RFC2047_CHROME_LEN = 7 DEFAULT_CHARSET = 'us-ascii' +UNKNOWN8BIT = 'unknown-8bit' EMPTYSTRING = '' @@ -153,6 +154,16 @@ +# Convenience function for encoding strings, taking into account +# that they might be unknown-8bit (ie: have surrogate-escaped bytes) +def _encode(string, codec): + if codec == UNKNOWN8BIT: + return string.encode('ascii', 'surrogateescape') + else: + return string.encode(codec) + + + class Charset: """Map character sets to their email properties. @@ -282,8 +293,7 @@ :return: The encoded string, with RFC 2047 chrome. """ codec = self.output_codec or 'us-ascii' - charset = self.get_output_charset() - header_bytes = string.encode(codec) + header_bytes = _encode(string, codec) # 7bit/8bit encodings return the string unchanged (modulo conversions) encoder_module = self._get_encoder(header_bytes) if encoder_module is None: @@ -309,7 +319,7 @@ """ # See which encoding we should use. codec = self.output_codec or 'us-ascii' - header_bytes = string.encode(codec) + header_bytes = _encode(string, codec) encoder_module = self._get_encoder(header_bytes) encoder = partial(encoder_module.header_encode, charset=str(self)) # Calculate the number of characters that the RFC 2047 chrome will @@ -333,7 +343,7 @@ for character in string: current_line.append(character) this_line = EMPTYSTRING.join(current_line) - length = encoder_module.header_length(this_line.encode(charset)) + length = encoder_module.header_length(_encode(this_line, charset)) if length > maxlen: # This last character doesn't fit so pop it off. current_line.pop() @@ -343,12 +353,12 @@ else: separator = (' ' if lines else '') joined_line = EMPTYSTRING.join(current_line) - header_bytes = joined_line.encode(codec) + header_bytes = _encode(joined_line, codec) lines.append(encoder(header_bytes)) current_line = [character] maxlen = next(maxlengths) - extra joined_line = EMPTYSTRING.join(current_line) - header_bytes = joined_line.encode(codec) + header_bytes = _encode(joined_line, codec) lines.append(encoder(header_bytes)) return lines Modified: python/branches/py3k/Lib/email/header.py ============================================================================== --- python/branches/py3k/Lib/email/header.py (original) +++ python/branches/py3k/Lib/email/header.py Sat Jan 8 00:25:30 2011 @@ -17,7 +17,8 @@ import email.base64mime from email.errors import HeaderParseError -from email.charset import Charset +from email import charset as _charset +Charset = _charset.Charset NL = '\n' SPACE = ' ' @@ -210,6 +211,9 @@ # from a charset to None/us-ascii, or from None/us-ascii to a # charset. Only do this for the second and subsequent chunks. nextcs = charset + if nextcs == _charset.UNKNOWN8BIT: + original_bytes = string.encode('ascii', 'surrogateescape') + string = original_bytes.decode('ascii', 'replace') if uchunks: if lastcs not in (None, 'us-ascii'): if nextcs in (None, 'us-ascii'): @@ -263,7 +267,8 @@ # Ensure that the bytes we're storing can be decoded to the output # character set, otherwise an early error is thrown. output_charset = charset.output_codec or 'us-ascii' - s.encode(output_charset, errors) + if output_charset != _charset.UNKNOWN8BIT: + s.encode(output_charset, errors) self._chunks.append((s, charset)) def encode(self, splitchars=';, \t', maxlinelen=None, linesep='\n'): Modified: python/branches/py3k/Lib/email/message.py ============================================================================== --- python/branches/py3k/Lib/email/message.py (original) +++ python/branches/py3k/Lib/email/message.py Sat Jan 8 00:25:30 2011 @@ -16,7 +16,9 @@ # Intrapackage imports from email import utils from email import errors -from email.charset import Charset +from email import header +from email import charset as _charset +Charset = _charset.Charset SEMISPACE = '; ' @@ -31,16 +33,15 @@ # Helper functions -def _sanitize_surrogates(value): - # If the value contains surrogates, re-decode and replace the original - # non-ascii bytes with '?'s. Used to sanitize header values before letting - # them escape as strings. +def _sanitize_header(name, value): + # If the header value contains surrogates, return a Header using + # the unknown-8bit charset to encode the bytes as encoded words. if not isinstance(value, str): - # Header object + # Assume it is already a header object return value if _has_surrogates(value): - original_bytes = value.encode('ascii', 'surrogateescape') - return original_bytes.decode('ascii', 'replace').replace('\ufffd', '?') + return header.Header(value, charset=_charset.UNKNOWN8BIT, + header_name=name) else: return value @@ -398,7 +399,7 @@ Any fields deleted and re-inserted are always appended to the header list. """ - return [_sanitize_surrogates(v) for k, v in self._headers] + return [_sanitize_header(k, v) for k, v in self._headers] def items(self): """Get all the message's header fields and values. @@ -408,7 +409,7 @@ Any fields deleted and re-inserted are always appended to the header list. """ - return [(k, _sanitize_surrogates(v)) for k, v in self._headers] + return [(k, _sanitize_header(k, v)) for k, v in self._headers] def get(self, name, failobj=None): """Get a header value. @@ -419,7 +420,7 @@ name = name.lower() for k, v in self._headers: if k.lower() == name: - return _sanitize_surrogates(v) + return _sanitize_header(k, v) return failobj # @@ -439,7 +440,7 @@ name = name.lower() for k, v in self._headers: if k.lower() == name: - values.append(_sanitize_surrogates(v)) + values.append(_sanitize_header(k, v)) if not values: return failobj return values Modified: python/branches/py3k/Lib/email/test/test_email.py ============================================================================== --- python/branches/py3k/Lib/email/test/test_email.py (original) +++ python/branches/py3k/Lib/email/test/test_email.py Sat Jan 8 00:25:30 2011 @@ -2841,7 +2841,7 @@ cte='8bit', bodyline='p?stal').encode('utf-8') msg = email.message_from_bytes(m) - self.assertEqual(msg.get_payload(), "p??stal\n") + self.assertEqual(msg.get_payload(), "p\uFFFD\uFFFDstal\n") self.assertEqual(msg.get_payload(decode=True), "p?stal\n".encode('utf-8')) @@ -2874,7 +2874,7 @@ cte='quoted-printable', bodyline='p=C3=B6st?l').encode('utf-8') msg = email.message_from_bytes(m) - self.assertEqual(msg.get_payload(), 'p=C3=B6st??l\n') + self.assertEqual(msg.get_payload(), 'p=C3=B6st\uFFFD\uFFFDl\n') self.assertEqual(msg.get_payload(decode=True), 'p?st?l\n'.encode('utf-8')) @@ -2899,52 +2899,65 @@ '<,.V Author: r.david.murray Date: Sat Jan 8 00:31:57 2011 New Revision: 87841 Log: Blocked revisions 87840 via svnmerge ........ r87840 | r.david.murray | 2011-01-07 18:25:30 -0500 (Fri, 07 Jan 2011) | 6 lines #10686: recode non-ASCII headers to 'unknown-8bit' instead of ?s. This applies only when generating strings from non-RFC compliant binary input; it makes the existing recoding behavior more consistent (ie: now no data is lost when recoding). ........ Modified: python/branches/release31-maint/ (props changed) From python-checkins at python.org Sat Jan 8 00:32:46 2011 From: python-checkins at python.org (r.david.murray) Date: Sat, 8 Jan 2011 00:32:46 +0100 (CET) Subject: [Python-checkins] r87842 - python/branches/release27-maint Message-ID: <20110107233246.9E244EEA75@mail.python.org> Author: r.david.murray Date: Sat Jan 8 00:32:46 2011 New Revision: 87842 Log: Blocked revisions 87840 via svnmerge ........ r87840 | r.david.murray | 2011-01-07 18:25:30 -0500 (Fri, 07 Jan 2011) | 6 lines #10686: recode non-ASCII headers to 'unknown-8bit' instead of ?s. This applies only when generating strings from non-RFC compliant binary input; it makes the existing recoding behavior more consistent (ie: now no data is lost when recoding). ........ Modified: python/branches/release27-maint/ (props changed) From python-checkins at python.org Sat Jan 8 01:13:34 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Sat, 8 Jan 2011 01:13:34 +0100 (CET) Subject: [Python-checkins] r87843 - in python/branches/py3k: Lib/datetime.py Lib/test/datetimetester.py Modules/_datetimemodule.c Modules/timemodule.c Message-ID: <20110108001334.A2ADBEEA6A@mail.python.org> Author: alexander.belopolsky Date: Sat Jan 8 01:13:34 2011 New Revision: 87843 Log: Issue #1777412: extended year range of strftime down to 1000. Modified: python/branches/py3k/Lib/datetime.py python/branches/py3k/Lib/test/datetimetester.py python/branches/py3k/Modules/_datetimemodule.c python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Lib/datetime.py ============================================================================== --- python/branches/py3k/Lib/datetime.py (original) +++ python/branches/py3k/Lib/datetime.py Sat Jan 8 01:13:34 2011 @@ -173,9 +173,9 @@ # Correctly substitute for %z and %Z escapes in strftime formats. def _wrap_strftime(object, format, timetuple): year = timetuple[0] - if year < 1900: - raise ValueError("year=%d is before 1900; the datetime strftime() " - "methods require year >= 1900" % year) + if year < 1000: + raise ValueError("year=%d is before 1000; the datetime strftime() " + "methods require year >= 1000" % year) # Don't call utcoffset() or tzname() unless actually needed. freplace = None # the string to use for %f zreplace = None # the string to use for %z @@ -1189,7 +1189,7 @@ """Format using strftime(). The date part of the timestamp passed to underlying strftime should not be used. """ - # The year must be >= 1900 else Python's strftime implementation + # The year must be >= 1000 else Python's strftime implementation # can raise a bogus exception. timetuple = (1900, 1, 1, self._hour, self._minute, self._second, Modified: python/branches/py3k/Lib/test/datetimetester.py ============================================================================== --- python/branches/py3k/Lib/test/datetimetester.py (original) +++ python/branches/py3k/Lib/test/datetimetester.py Sat Jan 8 01:13:34 2011 @@ -1284,10 +1284,10 @@ self.assertTrue(self.theclass.max) def test_strftime_out_of_range(self): - # For nasty technical reasons, we can't handle years before 1900. + # For nasty technical reasons, we can't handle years before 1000. cls = self.theclass - self.assertEqual(cls(1900, 1, 1).strftime("%Y"), "1900") - for y in 1, 49, 51, 99, 100, 1000, 1899: + self.assertEqual(cls(1000, 1, 1).strftime("%Y"), "1000") + for y in 1, 49, 51, 99, 100, 999: self.assertRaises(ValueError, cls(y, 1, 1).strftime, "%Y") def test_replace(self): Modified: python/branches/py3k/Modules/_datetimemodule.c ============================================================================== --- python/branches/py3k/Modules/_datetimemodule.c (original) +++ python/branches/py3k/Modules/_datetimemodule.c Sat Jan 8 01:13:34 2011 @@ -1166,10 +1166,10 @@ if (!pin) return NULL; - /* Give up if the year is before 1900. + /* Give up if the year is before 1000. * Python strftime() plays games with the year, and different * games depending on whether envar PYTHON2K is set. This makes - * years before 1900 a nightmare, even if the platform strftime + * years before 1000 a nightmare, even if the platform strftime * supports them (and not all do). * We could get a lot farther here by avoiding Python's strftime * wrapper and calling the C strftime() directly, but that isn't @@ -1182,10 +1182,10 @@ assert(PyLong_Check(pyyear)); year = PyLong_AsLong(pyyear); Py_DECREF(pyyear); - if (year < 1900) { + if (year < 1000) { PyErr_Format(PyExc_ValueError, "year=%ld is before " - "1900; the datetime strftime() " - "methods require year >= 1900", + "1000; the datetime strftime() " + "methods require year >= 1000", year); return NULL; } @@ -3663,7 +3663,7 @@ /* Python's strftime does insane things with the year part of the * timetuple. The year is forced to (the otherwise nonsensical) - * 1900 to worm around that. + * 1900 to work around that. */ tuple = Py_BuildValue("iiiiiiiii", 1900, 1, 1, /* year, month, day */ Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Sat Jan 8 01:13:34 2011 @@ -471,9 +471,9 @@ return NULL; /* XXX: Reportedly, some systems have issues formating dates prior to year - * 1900. These systems should be identified and this check should be + * 1000. These systems should be identified and this check should be * moved to appropriate system specific section below. */ - if (buf.tm_year < 0) { + if (buf.tm_year < -900) { PyErr_Format(PyExc_ValueError, "year=%d is before 1900; " "the strftime() method requires year >= 1900", buf.tm_year + 1900); From nnorwitz at gmail.com Sat Jan 8 01:19:59 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Fri, 7 Jan 2011 19:19:59 -0500 Subject: [Python-checkins] Python Regression Test Failures refleak (1) Message-ID: <20110108001959.GA17790@kbk-i386-bb.dyndns.org> More important issues: ---------------------- test_bz2 leaked [0, 0, 77] references, sum=77 Less important issues: ---------------------- From python-checkins at python.org Sat Jan 8 02:23:02 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Sat, 8 Jan 2011 02:23:02 +0100 (CET) Subject: [Python-checkins] r87844 - in python/branches/py3k: Lib/test/test_time.py Modules/timemodule.c Message-ID: <20110108012302.53036EEA18@mail.python.org> Author: alexander.belopolsky Date: Sat Jan 8 02:23:02 2011 New Revision: 87844 Log: Fixed error handling branches. Thanks Victor Stinner for pointing this out. Modified: python/branches/py3k/Lib/test/test_time.py python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Sat Jan 8 02:23:02 2011 @@ -308,13 +308,24 @@ def test_invalid(self): pass +class TestAccept2YearBad(TestAccept2Year): + class X: + def __bool__(self): + raise RuntimeError('boo') + accept2dyear = X() + def test_2dyear(self): + pass + def test_invalid(self): + self.assertRaises(RuntimeError, self.yearstr, 200) + + class TestDontAccept2YearBool(TestDontAccept2Year): accept2dyear = False def test_main(): support.run_unittest(TimeTestCase, TestLocale, - TestAccept2Year, TestAccept2YearBool, + TestAccept2Year, TestAccept2YearBool, TestAccept2YearBad, TestDontAccept2Year, TestDontAccept2YearBool) if __name__ == "__main__": Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Sat Jan 8 02:23:02 2011 @@ -332,23 +332,27 @@ if (y < 1000) { PyObject *accept = PyDict_GetItemString(moddict, "accept2dyear"); - int acceptval = accept != NULL && PyObject_IsTrue(accept); - if (acceptval == -1) - return 0; - if (acceptval) { - if (0 <= y && y < 69) - y += 2000; - else if (69 <= y && y < 100) - y += 1900; - else { - PyErr_SetString(PyExc_ValueError, - "year out of range"); + if (accept != NULL) { + int acceptval = PyObject_IsTrue(accept); + if (acceptval == -1) return 0; + if (acceptval) { + if (0 <= y && y < 69) + y += 2000; + else if (69 <= y && y < 100) + y += 1900; + else { + PyErr_SetString(PyExc_ValueError, + "year out of range"); + return 0; + } + if (PyErr_WarnEx(PyExc_DeprecationWarning, + "Century info guessed for a 2-digit year.", 1) != 0) + return 0; } - if (PyErr_WarnEx(PyExc_DeprecationWarning, - "Century info guessed for a 2-digit year.", 1) != 0) - return 0; } + else + return 0; } p->tm_year = y - 1900; p->tm_mon--; @@ -477,6 +481,7 @@ PyErr_Format(PyExc_ValueError, "year=%d is before 1900; " "the strftime() method requires year >= 1900", buf.tm_year + 1900); + return NULL; } /* Normalize tm_isdst just in case someone foolishly implements %Z From python-checkins at python.org Sat Jan 8 02:56:31 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 8 Jan 2011 02:56:31 +0100 (CET) Subject: [Python-checkins] r87845 - in python/branches/py3k: Lib/test/test_time.py Modules/timemodule.c Message-ID: <20110108015631.9370CEEA24@mail.python.org> Author: victor.stinner Date: Sat Jan 8 02:56:31 2011 New Revision: 87845 Log: Issue #1777412: strftime() accepts year >= 1 instead of year >= 1900 * With Visual Studio, year have to be in [1; 9999] * Add more tests on the year field Modified: python/branches/py3k/Lib/test/test_time.py python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Sat Jan 8 02:56:31 2011 @@ -43,14 +43,8 @@ # Make sure that strftime() checks the bounds of the various parts #of the time tuple (0 is valid for *all* values). - # Check year [1900, max(int)] - self.assertRaises(ValueError, func, - (999, 1, 1, 0, 0, 0, 0, 1, -1)) - if time.accept2dyear: - self.assertRaises(ValueError, func, - (-1, 1, 1, 0, 0, 0, 0, 1, -1)) - self.assertRaises(ValueError, func, - (100, 1, 1, 0, 0, 0, 0, 1, -1)) + # The year field is tested by other test cases above + # Check month [1, 12] + zero support self.assertRaises(ValueError, func, (1900, -1, 1, 0, 0, 0, 0, 1, -1)) @@ -267,8 +261,10 @@ # This should not cause an exception time.strftime("%B", (2009,2,1,0,0,0,0,0,0)) -class TestAccept2Year(unittest.TestCase): - accept2dyear = 1 + +class _BaseYearTest(unittest.TestCase): + accept2dyear = None + def setUp(self): self.saved_accept2dyear = time.accept2dyear time.accept2dyear = self.accept2dyear @@ -277,10 +273,37 @@ time.accept2dyear = self.saved_accept2dyear def yearstr(self, y): - # return time.strftime('%Y', (y,) + (0,) * 8) + raise NotImplementedError() + +class _TestAsctimeYear: + def yearstr(self, y): return time.asctime((y,) + (0,) * 8).split()[-1] - def test_2dyear(self): + def test_large_year(self): + # Check that it doesn't crash with year > 9999 + self.assertEqual(self.yearstr(12345), '12345') + self.assertEqual(self.yearstr(123456789), '123456789') + +class _TestStrftimeYear: + def yearstr(self, y): + return time.strftime('%Y', (y,) + (0,) * 8).split()[-1] + + def test_large_year(self): + # Just check that it doesn't crash with year > 9999: it may or may not + # raise an error depending on the OS and compiler + try: + self.yearstr(12345) + except ValueError: + pass + try: + self.yearstr(123456) + except ValueError: + pass + +class _Test2dYear(_BaseYearTest): + accept2dyear = 1 + + def test_year(self): with support.check_warnings(): self.assertEqual(self.yearstr(0), '2000') self.assertEqual(self.yearstr(69), '1969') @@ -288,27 +311,41 @@ self.assertEqual(self.yearstr(99), '1999') def test_invalid(self): - self.assertRaises(ValueError, self.yearstr, 999) - self.assertRaises(ValueError, self.yearstr, 100) self.assertRaises(ValueError, self.yearstr, -1) + self.assertRaises(ValueError, self.yearstr, 100) + self.assertRaises(ValueError, self.yearstr, 999) -class TestAccept2YearBool(TestAccept2Year): - accept2dyear = True - -class TestDontAccept2Year(TestAccept2Year): +class _Test4dYear(_BaseYearTest): accept2dyear = 0 - def test_2dyear(self): - self.assertEqual(self.yearstr(0), '0') + + def test_year(self): + self.assertEqual(self.yearstr(1), '1') self.assertEqual(self.yearstr(69), '69') self.assertEqual(self.yearstr(68), '68') self.assertEqual(self.yearstr(99), '99') self.assertEqual(self.yearstr(999), '999') self.assertEqual(self.yearstr(9999), '9999') - def test_invalid(self): - pass +class TestAsctimeAccept2dYear(_TestAsctimeYear, _Test2dYear): + pass + +class TestStrftimeAccept2dYear(_TestStrftimeYear, _Test2dYear): + pass -class TestAccept2YearBad(TestAccept2Year): +class TestAsctime4dyear(_TestAsctimeYear, _Test4dYear): + pass + +class TestStrftime4dyear(_TestStrftimeYear, _Test4dYear): + def test_bounds(self): + self.assertRaises(ValueError, self.yearstr, 0) + +class Test2dyearBool(_TestAsctimeYear, _Test2dYear): + accept2dyear = True + +class Test4dyearBool(_TestAsctimeYear, _Test4dYear): + accept2dyear = False + +class TestAccept2YearBad(_TestAsctimeYear, _BaseYearTest): class X: def __bool__(self): raise RuntimeError('boo') @@ -319,14 +356,17 @@ self.assertRaises(RuntimeError, self.yearstr, 200) -class TestDontAccept2YearBool(TestDontAccept2Year): - accept2dyear = False - - def test_main(): - support.run_unittest(TimeTestCase, TestLocale, - TestAccept2Year, TestAccept2YearBool, TestAccept2YearBad, - TestDontAccept2Year, TestDontAccept2YearBool) + support.run_unittest( + TimeTestCase, + TestLocale, + TestAsctimeAccept2dYear, + TestStrftimeAccept2dYear, + TestAsctime4dyear, + TestStrftime4dyear, + Test2dyearBool, + Test4dyearBool, + TestAccept2YearBad) if __name__ == "__main__": test_main() Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Sat Jan 8 02:56:31 2011 @@ -474,15 +474,21 @@ else if (!gettmarg(tup, &buf) || !checktm(&buf)) return NULL; - /* XXX: Reportedly, some systems have issues formating dates prior to year - * 1000. These systems should be identified and this check should be - * moved to appropriate system specific section below. */ - if (buf.tm_year < -900) { - PyErr_Format(PyExc_ValueError, "year=%d is before 1900; " - "the strftime() method requires year >= 1900", +#ifdef _MSC_VER + if (buf.tm_year + 1900 < 1 || 9999 < buf.tm_year + 1900) { + PyErr_Format(PyExc_ValueError, + "strftime() requires year in [1; 9999]", buf.tm_year + 1900); return NULL; } +#else + if (buf.tm_year + 1900 < 1) { + PyErr_Format(PyExc_ValueError, + "strftime() requires year >= 1", + buf.tm_year + 1900); + return NULL; + } +#endif /* Normalize tm_isdst just in case someone foolishly implements %Z based on the assumption that tm_isdst falls within the range of From python-checkins at python.org Sat Jan 8 03:00:24 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 8 Jan 2011 03:00:24 +0100 (CET) Subject: [Python-checkins] r87846 - python/branches/py3k/Lib/test/test_time.py Message-ID: <20110108020024.6C78EEEA24@mail.python.org> Author: victor.stinner Date: Sat Jan 8 03:00:24 2011 New Revision: 87846 Log: Issue #1777412: test large years value for strftime('%Y') Modified: python/branches/py3k/Lib/test/test_time.py Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Sat Jan 8 03:00:24 2011 @@ -280,7 +280,7 @@ return time.asctime((y,) + (0,) * 8).split()[-1] def test_large_year(self): - # Check that it doesn't crash with year > 9999 + # Check that it doesn't crash for year > 9999 self.assertEqual(self.yearstr(12345), '12345') self.assertEqual(self.yearstr(123456789), '123456789') @@ -289,16 +289,21 @@ return time.strftime('%Y', (y,) + (0,) * 8).split()[-1] def test_large_year(self): - # Just check that it doesn't crash with year > 9999: it may or may not - # raise an error depending on the OS and compiler + # Check that it doesn't crash for year > 9999 try: - self.yearstr(12345) + text = self.yearstr(12345) except ValueError: + # If Python is compiled with Visual Studio, + # year is limited to [1; 9999] pass + else: + self.assertEqual(text, '12345') try: - self.yearstr(123456) + text = self.yearstr(123456789) except ValueError: pass + else: + self.assertEqual(text, '123456789') class _Test2dYear(_BaseYearTest): accept2dyear = 1 From python-checkins at python.org Sat Jan 8 03:46:33 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 8 Jan 2011 03:46:33 +0100 (CET) Subject: [Python-checkins] r87847 - python/branches/py3k/Lib/test/test_time.py Message-ID: <20110108024633.CF22CEEA43@mail.python.org> Author: victor.stinner Date: Sat Jan 8 03:46:33 2011 New Revision: 87847 Log: Issue #1777412: fix test_time for Mac OS X and OpenIndiana Modified: python/branches/py3k/Lib/test/test_time.py Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Sat Jan 8 03:46:33 2011 @@ -293,17 +293,22 @@ try: text = self.yearstr(12345) except ValueError: - # If Python is compiled with Visual Studio, - # year is limited to [1; 9999] + # strftime() is limited to [1; 9999] with Visual Studio pass else: - self.assertEqual(text, '12345') + # Issue #10864: OpenIndiana is limited to 4 digits, but Python + # doesn't raise a ValueError + #self.assertEqual(text, '12345') + self.assertIn(text, ('2345', '12345')) try: text = self.yearstr(123456789) except ValueError: pass else: - self.assertEqual(text, '123456789') + # Issue #10864: OpenIndiana is limited to 4 digits, but Python + # doesn't raise a ValueError + #self.assertEqual(text, '123456789') + self.assertIn(text, ('123456789', '6789')) class _Test2dYear(_BaseYearTest): accept2dyear = 1 @@ -324,11 +329,11 @@ accept2dyear = 0 def test_year(self): - self.assertEqual(self.yearstr(1), '1') - self.assertEqual(self.yearstr(69), '69') - self.assertEqual(self.yearstr(68), '68') - self.assertEqual(self.yearstr(99), '99') - self.assertEqual(self.yearstr(999), '999') + self.assertIn(self.yearstr(1), ('1', '0001')) + self.assertIn(self.yearstr(68), ('68', '0068')) + self.assertIn(self.yearstr(69), ('69', '0069')) + self.assertIn(self.yearstr(99), ('99', '0099')) + self.assertIn(self.yearstr(999), ('999', '0999')) self.assertEqual(self.yearstr(9999), '9999') class TestAsctimeAccept2dYear(_TestAsctimeYear, _Test2dYear): From python-checkins at python.org Sat Jan 8 04:06:53 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 8 Jan 2011 04:06:53 +0100 (CET) Subject: [Python-checkins] r87848 - in python/branches/py3k: Lib/test/test_time.py Modules/timemodule.c Message-ID: <20110108030653.1BB66EEA29@mail.python.org> Author: victor.stinner Date: Sat Jan 8 04:06:52 2011 New Revision: 87848 Log: Issue #1777412: Remove all limits on tm_year from time.strftime() The buildbots will tell us which platform does support or not negative years. Modified: python/branches/py3k/Lib/test/test_time.py python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Sat Jan 8 04:06:52 2011 @@ -294,21 +294,13 @@ text = self.yearstr(12345) except ValueError: # strftime() is limited to [1; 9999] with Visual Studio - pass - else: - # Issue #10864: OpenIndiana is limited to 4 digits, but Python - # doesn't raise a ValueError - #self.assertEqual(text, '12345') - self.assertIn(text, ('2345', '12345')) - try: - text = self.yearstr(123456789) - except ValueError: - pass - else: - # Issue #10864: OpenIndiana is limited to 4 digits, but Python - # doesn't raise a ValueError - #self.assertEqual(text, '123456789') - self.assertIn(text, ('123456789', '6789')) + return + # Issue #10864: OpenIndiana is limited to 4 digits, + # but Python doesn't raise a ValueError + #self.assertEqual(text, '12345') + #self.assertEqual(self.yearstr(123456789), '123456789') + self.assertIn(text, ('2345', '12345')) + self.assertIn(self.yearstr(123456789), ('123456789', '6789')) class _Test2dYear(_BaseYearTest): accept2dyear = 1 @@ -336,6 +328,17 @@ self.assertIn(self.yearstr(999), ('999', '0999')) self.assertEqual(self.yearstr(9999), '9999') + def test_negative(self): + try: + text = self.yearstr(-1) + except ValueError: + # strftime() is limited to [1; 9999] with Visual Studio + return + self.assertIn(text, ('-1', '-001')) + + self.assertEqual(self.yearstr(-1234), '-1234') + self.assertEqual(self.yearstr(-123456), '-123456') + class TestAsctimeAccept2dYear(_TestAsctimeYear, _Test2dYear): pass @@ -346,8 +349,7 @@ pass class TestStrftime4dyear(_TestStrftimeYear, _Test4dYear): - def test_bounds(self): - self.assertRaises(ValueError, self.yearstr, 0) + pass class Test2dyearBool(_TestAsctimeYear, _Test2dYear): accept2dyear = True Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Sat Jan 8 04:06:52 2011 @@ -332,7 +332,7 @@ if (y < 1000) { PyObject *accept = PyDict_GetItemString(moddict, "accept2dyear"); - if (accept != NULL) { + if (accept != NULL) { int acceptval = PyObject_IsTrue(accept); if (acceptval == -1) return 0; @@ -481,13 +481,6 @@ buf.tm_year + 1900); return NULL; } -#else - if (buf.tm_year + 1900 < 1) { - PyErr_Format(PyExc_ValueError, - "strftime() requires year >= 1", - buf.tm_year + 1900); - return NULL; - } #endif /* Normalize tm_isdst just in case someone foolishly implements %Z From python-checkins at python.org Sat Jan 8 04:16:05 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 8 Jan 2011 04:16:05 +0100 (CET) Subject: [Python-checkins] r87849 - python/branches/py3k/Lib/test/test_ssl.py Message-ID: <20110108031605.A039BEEA40@mail.python.org> Author: victor.stinner Date: Sat Jan 8 04:16:05 2011 New Revision: 87849 Log: test_ssl: test SHA256 using sha256.tbs-internet.com instead of sha2.hboeck.de Modified: python/branches/py3k/Lib/test/test_ssl.py Modified: python/branches/py3k/Lib/test/test_ssl.py ============================================================================== --- python/branches/py3k/Lib/test/test_ssl.py (original) +++ python/branches/py3k/Lib/test/test_ssl.py Sat Jan 8 04:16:05 2011 @@ -599,8 +599,8 @@ # SHA256 was added in OpenSSL 0.9.8 if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15): self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION) - # NOTE: https://sha256.tbs-internet.com is another possible test host - remote = ("sha2.hboeck.de", 443) + # https://sha2.hboeck.de/ was used until 2011-01-08 (no route to host) + remote = ("sha256.tbs-internet.com", 443) sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem") with support.transient_internet("sha2.hboeck.de"): s = ssl.wrap_socket(socket.socket(socket.AF_INET), From python-checkins at python.org Sat Jan 8 04:35:36 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 8 Jan 2011 04:35:36 +0100 (CET) Subject: [Python-checkins] r87850 - python/branches/py3k/Modules/timemodule.c Message-ID: <20110108033536.53095EEA53@mail.python.org> Author: victor.stinner Date: Sat Jan 8 04:35:36 2011 New Revision: 87850 Log: Issue #10864: limit year to [1; 9999] for strftime() on Solaris Modified: python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Sat Jan 8 04:35:36 2011 @@ -474,7 +474,7 @@ else if (!gettmarg(tup, &buf) || !checktm(&buf)) return NULL; -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(sun) if (buf.tm_year + 1900 < 1 || 9999 < buf.tm_year + 1900) { PyErr_Format(PyExc_ValueError, "strftime() requires year in [1; 9999]", From solipsis at pitrou.net Sat Jan 8 05:08:54 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 08 Jan 2011 05:08:54 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r87846): sum=24 Message-ID: py3k results for svn r87846 (hg cset 91333738d043) -------------------------------------------------- test_multiprocessing leaked [0, 24, 0] references, sum=24 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflogesCJIk', '-x'] From python-checkins at python.org Sat Jan 8 08:01:56 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 8 Jan 2011 08:01:56 +0100 (CET) Subject: [Python-checkins] r87853 - in python/branches/py3k: Lib/functools.py Lib/test/test_functools.py Misc/ACKS Misc/NEWS Message-ID: <20110108070156.D3D36EEA63@mail.python.org> Author: raymond.hettinger Date: Sat Jan 8 08:01:56 2011 New Revision: 87853 Log: Issue #10042: Fixed the total_ordering decorator to handle cross-type comparisons that could lead to infinite recursion. Modified: python/branches/py3k/Lib/functools.py python/branches/py3k/Lib/test/test_functools.py python/branches/py3k/Misc/ACKS python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/functools.py ============================================================================== --- python/branches/py3k/Lib/functools.py (original) +++ python/branches/py3k/Lib/functools.py Sat Jan 8 08:01:56 2011 @@ -68,17 +68,17 @@ def total_ordering(cls): """Class decorator that fills in missing ordering methods""" convert = { - '__lt__': [('__gt__', lambda self, other: other < self), - ('__le__', lambda self, other: not other < self), + '__lt__': [('__gt__', lambda self, other: not (self < other or self == other)), + ('__le__', lambda self, other: self < other or self == other), ('__ge__', lambda self, other: not self < other)], - '__le__': [('__ge__', lambda self, other: other <= self), - ('__lt__', lambda self, other: not other <= self), + '__le__': [('__ge__', lambda self, other: not self <= other or self == other), + ('__lt__', lambda self, other: self <= other and not self == other), ('__gt__', lambda self, other: not self <= other)], - '__gt__': [('__lt__', lambda self, other: other > self), - ('__ge__', lambda self, other: not other > self), + '__gt__': [('__lt__', lambda self, other: not (self > other or self == other)), + ('__ge__', lambda self, other: self > other or self == other), ('__le__', lambda self, other: not self > other)], - '__ge__': [('__le__', lambda self, other: other >= self), - ('__gt__', lambda self, other: not other >= self), + '__ge__': [('__le__', lambda self, other: (not self >= other) or self == other), + ('__gt__', lambda self, other: self >= other and not self == other), ('__lt__', lambda self, other: not self >= other)] } # Find user-defined comparisons (not those inherited from object). Modified: python/branches/py3k/Lib/test/test_functools.py ============================================================================== --- python/branches/py3k/Lib/test/test_functools.py (original) +++ python/branches/py3k/Lib/test/test_functools.py Sat Jan 8 08:01:56 2011 @@ -457,6 +457,8 @@ self.value = value def __lt__(self, other): return self.value < other.value + def __eq__(self, other): + return self.value == other.value self.assertTrue(A(1) < A(2)) self.assertTrue(A(2) > A(1)) self.assertTrue(A(1) <= A(2)) @@ -471,6 +473,8 @@ self.value = value def __le__(self, other): return self.value <= other.value + def __eq__(self, other): + return self.value == other.value self.assertTrue(A(1) < A(2)) self.assertTrue(A(2) > A(1)) self.assertTrue(A(1) <= A(2)) @@ -485,6 +489,8 @@ self.value = value def __gt__(self, other): return self.value > other.value + def __eq__(self, other): + return self.value == other.value self.assertTrue(A(1) < A(2)) self.assertTrue(A(2) > A(1)) self.assertTrue(A(1) <= A(2)) @@ -499,6 +505,8 @@ self.value = value def __ge__(self, other): return self.value >= other.value + def __eq__(self, other): + return self.value == other.value self.assertTrue(A(1) < A(2)) self.assertTrue(A(2) > A(1)) self.assertTrue(A(1) <= A(2)) @@ -524,6 +532,22 @@ class A: pass + def test_bug_10042(self): + @functools.total_ordering + class TestTO: + def __init__(self, value): + self.value = value + def __eq__(self, other): + if isinstance(other, TestTO): + return self.value == other.value + return False + def __lt__(self, other): + if isinstance(other, TestTO): + return self.value < other.value + raise TypeError + with self.assertRaises(TypeError): + TestTO(8) <= () + class TestLRU(unittest.TestCase): def test_lru(self): Modified: python/branches/py3k/Misc/ACKS ============================================================================== --- python/branches/py3k/Misc/ACKS (original) +++ python/branches/py3k/Misc/ACKS Sat Jan 8 08:01:56 2011 @@ -700,6 +700,7 @@ Steven Reiz Roeland Rengelink Tim Rice +Francesco Ricciardi Jan Pieter Riegel Armin Rigo Nicholas Riley Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 8 08:01:56 2011 @@ -40,6 +40,9 @@ Library ------- +- Issue #10042: Fixed the total_ordering decorator to handle cross-type + comparisons that could lead to infinite recursion. + - Issue #10686: the email package now :rfc:`2047`\ -encodes headers with non-ASCII bytes (parsed by a Bytes Parser) when doing conversion to 7bit-clean presentation, instead of replacing them with ?s. From python-checkins at python.org Sat Jan 8 10:03:11 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 8 Jan 2011 10:03:11 +0100 (CET) Subject: [Python-checkins] r87856 - python/branches/py3k/Doc/library/decimal.rst Message-ID: <20110108090311.AB950EEA54@mail.python.org> Author: raymond.hettinger Date: Sat Jan 8 10:03:11 2011 New Revision: 87856 Log: Issue #10813: Small improvement to decimal money format recipe. Modified: python/branches/py3k/Doc/library/decimal.rst Modified: python/branches/py3k/Doc/library/decimal.rst ============================================================================== --- python/branches/py3k/Doc/library/decimal.rst (original) +++ python/branches/py3k/Doc/library/decimal.rst Sat Jan 8 10:03:11 2011 @@ -1657,7 +1657,8 @@ build(trailneg) for i in range(places): build(next() if digits else '0') - build(dp) + if places: + build(dp) if not digits: build('0') i = 0 From python-checkins at python.org Sat Jan 8 10:18:56 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 8 Jan 2011 10:18:56 +0100 (CET) Subject: [Python-checkins] r87857 - in python/branches/release31-maint: Doc/tutorial/stdlib.rst Message-ID: <20110108091856.109A7EEA5D@mail.python.org> Author: georg.brandl Date: Sat Jan 8 10:18:55 2011 New Revision: 87857 Log: Merged revisions 86882 via svnmerge from svn+ssh://svn.python.org/python/branches/py3k ........ r86882 | georg.brandl | 2010-11-30 09:20:16 +0100 (Di, 30 Nov 2010) | 1 line Fix input type for zlib. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Doc/tutorial/stdlib.rst Modified: python/branches/release31-maint/Doc/tutorial/stdlib.rst ============================================================================== --- python/branches/release31-maint/Doc/tutorial/stdlib.rst (original) +++ python/branches/release31-maint/Doc/tutorial/stdlib.rst Sat Jan 8 10:18:55 2011 @@ -207,14 +207,14 @@ :mod:`tarfile`. :: >>> import zlib - >>> s = 'witch which has which witches wrist watch' + >>> s = b'witch which has which witches wrist watch' >>> len(s) 41 >>> t = zlib.compress(s) >>> len(t) 37 >>> zlib.decompress(t) - 'witch which has which witches wrist watch' + b'witch which has which witches wrist watch' >>> zlib.crc32(s) 226805979 From python-checkins at python.org Sat Jan 8 10:35:38 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 8 Jan 2011 10:35:38 +0100 (CET) Subject: [Python-checkins] r87858 - python/branches/py3k/Doc/library/stdtypes.rst Message-ID: <20110108093538.5DE62EEA63@mail.python.org> Author: raymond.hettinger Date: Sat Jan 8 10:35:38 2011 New Revision: 87858 Log: Issue 10533: Need example of using __missing__. Modified: python/branches/py3k/Doc/library/stdtypes.rst Modified: python/branches/py3k/Doc/library/stdtypes.rst ============================================================================== --- python/branches/py3k/Doc/library/stdtypes.rst (original) +++ python/branches/py3k/Doc/library/stdtypes.rst Sat Jan 8 10:35:38 2011 @@ -2117,8 +2117,20 @@ returned or raised by the ``__missing__(key)`` call if the key is not present. No other operations or methods invoke :meth:`__missing__`. If :meth:`__missing__` is not defined, :exc:`KeyError` is raised. - :meth:`__missing__` must be a method; it cannot be an instance variable. For - an example, see :class:`collections.defaultdict`. + :meth:`__missing__` must be a method; it cannot be an instance variable:: + + >>> class Counter(dict): + ... def __missing__(self, key): + ... return 0 + >>> c = Counter() + >>> c['red'] + 0 + >>> c['red'] += 1 + >>> c['red'] + 1 + + See :class:`collections.Counter` for a complete implementation including + other methods helpful for accumulating and managing tallies. .. describe:: d[key] = value From python-checkins at python.org Sat Jan 8 10:45:43 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 8 Jan 2011 10:45:43 +0100 (CET) Subject: [Python-checkins] r87859 - python/branches/py3k/Doc/library/wave.rst Message-ID: <20110108094543.51CECEE984@mail.python.org> Author: georg.brandl Date: Sat Jan 8 10:45:43 2011 New Revision: 87859 Log: #10855: document close() semantics of wave objects. Modified: python/branches/py3k/Doc/library/wave.rst Modified: python/branches/py3k/Doc/library/wave.rst ============================================================================== --- python/branches/py3k/Doc/library/wave.rst (original) +++ python/branches/py3k/Doc/library/wave.rst Sat Jan 8 10:45:43 2011 @@ -14,8 +14,8 @@ .. function:: open(file, mode=None) - If *file* is a string, open the file by that name, other treat it as a seekable - file-like object. *mode* can be any of + If *file* is a string, open the file by that name, otherwise treat it as a + seekable file-like object. *mode* can be any of ``'r'``, ``'rb'`` Read only mode. @@ -26,9 +26,14 @@ Note that it does not allow read/write WAV files. A *mode* of ``'r'`` or ``'rb'`` returns a :class:`Wave_read` object, while a - *mode* of ``'w'`` or ``'wb'`` returns a :class:`Wave_write` object. If *mode* - is omitted and a file-like object is passed as *file*, ``file.mode`` is used as - the default value for *mode* (the ``'b'`` flag is still added if necessary). + *mode* of ``'w'`` or ``'wb'`` returns a :class:`Wave_write` object. If + *mode* is omitted and a file-like object is passed as *file*, ``file.mode`` + is used as the default value for *mode* (the ``'b'`` flag is still added if + necessary). + + If you pass in a file-like object, the wave object will not close it when its + :meth:`close` method is called; it is the caller's responsibility to close + the file object. .. function:: openfp(file, mode) @@ -52,8 +57,8 @@ .. method:: Wave_read.close() - Close the stream, and make the instance unusable. This is called automatically - on object collection. + Close the stream if it was opened by :mod:`wave`, and make the instance + unusable. This is called automatically on object collection. .. method:: Wave_read.getnchannels() @@ -139,8 +144,8 @@ .. method:: Wave_write.close() - Make sure *nframes* is correct, and close the file. This method is called upon - deletion. + Make sure *nframes* is correct, and close the file if it was opened by + :mod:`wave`. This method is called upon object collection. .. method:: Wave_write.setnchannels(n) @@ -196,6 +201,7 @@ Write audio frames and make sure *nframes* is correct. + Note that it is invalid to set any parameters after calling :meth:`writeframes` or :meth:`writeframesraw`, and any attempt to do so will raise :exc:`wave.Error`. From python-checkins at python.org Sat Jan 8 10:55:31 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 8 Jan 2011 10:55:31 +0100 (CET) Subject: [Python-checkins] r87860 - in python/branches/py3k: Lib/contextlib.py Lib/test/test_with.py Misc/NEWS Message-ID: <20110108095531.BB011EE984@mail.python.org> Author: antoine.pitrou Date: Sat Jan 8 10:55:31 2011 New Revision: 87860 Log: Issue #10859: Make `contextlib.GeneratorContextManager` officially private by renaming it to `_GeneratorContextManager`. Modified: python/branches/py3k/Lib/contextlib.py python/branches/py3k/Lib/test/test_with.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/contextlib.py ============================================================================== --- python/branches/py3k/Lib/contextlib.py (original) +++ python/branches/py3k/Lib/contextlib.py Sat Jan 8 10:55:31 2011 @@ -17,7 +17,7 @@ return inner -class GeneratorContextManager(ContextDecorator): +class _GeneratorContextManager(ContextDecorator): """Helper for @contextmanager decorator.""" def __init__(self, gen): @@ -92,7 +92,7 @@ """ @wraps(func) def helper(*args, **kwds): - return GeneratorContextManager(func(*args, **kwds)) + return _GeneratorContextManager(func(*args, **kwds)) return helper Modified: python/branches/py3k/Lib/test/test_with.py ============================================================================== --- python/branches/py3k/Lib/test/test_with.py (original) +++ python/branches/py3k/Lib/test/test_with.py Sat Jan 8 10:55:31 2011 @@ -9,26 +9,26 @@ import sys import unittest from collections import deque -from contextlib import GeneratorContextManager, contextmanager +from contextlib import _GeneratorContextManager, contextmanager from test.support import run_unittest -class MockContextManager(GeneratorContextManager): +class MockContextManager(_GeneratorContextManager): def __init__(self, gen): - GeneratorContextManager.__init__(self, gen) + _GeneratorContextManager.__init__(self, gen) self.enter_called = False self.exit_called = False self.exit_args = None def __enter__(self): self.enter_called = True - return GeneratorContextManager.__enter__(self) + return _GeneratorContextManager.__enter__(self) def __exit__(self, type, value, traceback): self.exit_called = True self.exit_args = (type, value, traceback) - return GeneratorContextManager.__exit__(self, type, - value, traceback) + return _GeneratorContextManager.__exit__(self, type, + value, traceback) def mock_contextmanager(func): Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 8 10:55:31 2011 @@ -40,6 +40,9 @@ Library ------- +- Issue #10859: Make ``contextlib.GeneratorContextManager`` officially + private by renaming it to ``_GeneratorContextManager``. + - Issue #10042: Fixed the total_ordering decorator to handle cross-type comparisons that could lead to infinite recursion. From python-checkins at python.org Sat Jan 8 11:23:29 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 8 Jan 2011 11:23:29 +0100 (CET) Subject: [Python-checkins] r87861 - in python/branches/py3k/Lib/test: sha256.pem test_ssl.py Message-ID: <20110108102329.846BBEEA54@mail.python.org> Author: antoine.pitrou Date: Sat Jan 8 11:23:29 2011 New Revision: 87861 Log: Fix test_ssl after r87849 Modified: python/branches/py3k/Lib/test/sha256.pem python/branches/py3k/Lib/test/test_ssl.py Modified: python/branches/py3k/Lib/test/sha256.pem ============================================================================== --- python/branches/py3k/Lib/test/sha256.pem (original) +++ python/branches/py3k/Lib/test/sha256.pem Sat Jan 8 11:23:29 2011 @@ -1,33 +1,129 @@ +# Certificate chain for https://sha256.tbs-internet.com + 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=sha-256 production/CN=sha256.tbs-internet.com + i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC -----BEGIN CERTIFICATE----- -MIIFxzCCA6+gAwIBAgIJALnlnf5uzTkIMA0GCSqGSIb3DQEBCwUAMEsxCzAJBgNV -BAYTAkRFMRcwFQYDVQQKEw5zY2hva29rZWtzLm9yZzEjMCEGCSqGSIb3DQEJARYU -aGFubm9Ac2Nob2tva2Vrcy5vcmcwHhcNMTAwMTI3MDAyMTI1WhcNMjAwMTI1MDAy -MTI1WjBLMQswCQYDVQQGEwJERTEXMBUGA1UEChMOc2Nob2tva2Vrcy5vcmcxIzAh -BgkqhkiG9w0BCQEWFGhhbm5vQHNjaG9rb2tla3Mub3JnMIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEApJ4ODPwEooMW35dQPlBqdvcfkEvjhcsA7jmJfFqN -e/1T34zT44X9+KnMBSG2InacbD7eyFgjfaENFsZ87YkEBDIFZ/SHotLJZORQ8PUj -YoxPG4mjKN+yL2WthNcYbRyJreTbbDroNMuw6tkTSxeSXyYFQrKMCUfErVbZa/d5 -RvfFVk+Au9dVUFhed/Stn5cv+a0ffvpyA7ygihm1kMFICbvPeI0846tmC2Ph7rM5 -pYQyNBDOVpULODTk5Wu6jiiJJygvJWCZ1FdpsdBs5aKWHWdRhX++quGuflTTjH5d -qaIka4op9H7XksYphTDXmV+qHnva5jbPogwutDQcVsGBQcJaLmQqhsQK13bf4khE -iWJvfBLfHn8OOpY25ZwwuigJIwifNCxQeeT1FrLmyuYNhz2phPpzx065kqSUSR+A -Iw8DPE6e65UqMDKqZnID3dQeiQaFrHEV+Ibo0U/tD0YSBw5p33TMh0Es33IBWMac -m7x4hIFWdhl8W522u6qOrTswY3s8vB7blNWqMc9n7oWH8ybFf7EgKeDVtEN9AyBE -0WotXIEZWI+WvDbU1ACJXau9sQhYP/eerg7Zwr3iGUy4IQ5oUJibnjtcE+z8zmDN -pE6YcMCLJyLjXiQ3iHG9mNXzw7wPnslTbEEEukrfSlHGgW8Dm+VrNyW0JUM1bntx -vbMCAwEAAaOBrTCBqjAdBgNVHQ4EFgQUCedv7pDTuXtCxm4HTw9hUtrTvsowewYD -VR0jBHQwcoAUCedv7pDTuXtCxm4HTw9hUtrTvsqhT6RNMEsxCzAJBgNVBAYTAkRF -MRcwFQYDVQQKEw5zY2hva29rZWtzLm9yZzEjMCEGCSqGSIb3DQEJARYUaGFubm9A -c2Nob2tva2Vrcy5vcmeCCQC55Z3+bs05CDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 -DQEBCwUAA4ICAQBHKAxA7WA/MEFjet03K8ouzEOr6Jrk2fZOuRhoDZ+9gr4FtaJB -P3Hh5D00kuSOvDnwsvCohxeNd1KTMAwVmVoH+NZkHERn3UXniUENlp18koI1ehlr -CZbXbzzE9Te9BelliSFA63q0cq0yJN1x9GyabU34XkAouCAmOqfSpKNZWZHGBHPF -bbYnZrHEMcsye6vKeTOcg1GqUHGrQM2WK0QaOwnCQv2RblI9VN+SeRoUJ44qTXdW -TwIYStsIPesacNcAQTStnHgKqIPx4zCwdx5xo8zONbXJfocqwyFqiAofvb9dN1nW -g1noVBcXB+oRBZW5CjFw87U88itq39i9+BWl835DWLBW2pVmx1QTLGv0RNgs/xVx -mWnjH4nNHvrjn6pRmqHZTk/SS0Hkl2qtDsynVxIl8EiMTfWSU3DBTuD2J/RSzuOE -eKtAbaoXkXE31jCl4FEZLITIZd8UkXacb9rN304tAK92L76JOAV+xOZxFRipmvx4 -+A9qQXgLhtP4VaDajb44V/kCKPSA0Vm3apehke9Wl8dDtagfos1e6MxSu3EVLXRF -SP2U777V77pdMSd0f/7cerKn5FjrxW1v1FaP1oIGniMk4qQNTgA/jvvhjybsPlVA -jsfnhWGbh1voJa0RQcMiRMsxpw2P1KNOEu37W2eq/vFghVztZJQUmb5iNw== +MIIGXTCCBUWgAwIBAgIRAMmag+ygSAdxZsbyzYjhuW0wDQYJKoZIhvcNAQELBQAw +gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl +bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u +ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv +cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg +Q0EgU0dDMB4XDTEwMDIxODAwMDAwMFoXDTEyMDIxOTIzNTk1OVowgcsxCzAJBgNV +BAYTAkZSMQ4wDAYDVQQREwUxNDAwMDERMA8GA1UECBMIQ2FsdmFkb3MxDTALBgNV +BAcTBENBRU4xGzAZBgNVBAkTEjIyIHJ1ZSBkZSBCcmV0YWduZTEVMBMGA1UEChMM +VEJTIElOVEVSTkVUMRcwFQYDVQQLEw4wMDAyIDQ0MDQ0MzgxMDEbMBkGA1UECxMS +c2hhLTI1NiBwcm9kdWN0aW9uMSAwHgYDVQQDExdzaGEyNTYudGJzLWludGVybmV0 +LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbuM8VT7f0nntwu +N3F7v9KIBlhKNAxqCrziOXU5iqUt8HrQB3DtHbdmII+CpVUlwlmepsx6G+srEZ9a +MIGAy0nxi5aLb7watkyIdPjJTMvTUBQ/+RPWzt5JtYbbY9BlJ+yci0dctP74f4NU +ISLtlrEjUbf2gTohLrcE01TfmOF6PDEbB5PKDi38cB3NzKfizWfrOaJW6Q1C1qOJ +y4/4jkUREX1UFUIxzx7v62VfjXSGlcjGpBX1fvtABQOSLeE0a6gciDZs1REqroFf +5eXtqYphpTa14Z83ITXMfgg5Nze1VtMnzI9Qx4blYBw4dgQVEuIsYr7FDBOITDzc +VEVXZx0CAwEAAaOCAj8wggI7MB8GA1UdIwQYMBaAFAdEdoWTKLx/bXjSCuv6TEvf +2YIfMB0GA1UdDgQWBBSJKI/AYVI9RQNY0QPIqc8ej2QivTAOBgNVHQ8BAf8EBAMC +BaAwDAYDVR0TAQH/BAIwADA0BgNVHSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIG +CisGAQQBgjcKAwMGCWCGSAGG+EIEATBMBgNVHSAERTBDMEEGCysGAQQBgOU3AgQB +MDIwMAYIKwYBBQUHAgEWJGh0dHBzOi8vd3d3LnRicy1pbnRlcm5ldC5jb20vQ0Ev +Q1BTNDBtBgNVHR8EZjBkMDKgMKAuhixodHRwOi8vY3JsLnRicy1pbnRlcm5ldC5j +b20vVEJTWDUwOUNBU0dDLmNybDAuoCygKoYoaHR0cDovL2NybC50YnMteDUwOS5j +b20vVEJTWDUwOUNBU0dDLmNybDCBpgYIKwYBBQUHAQEEgZkwgZYwOAYIKwYBBQUH +MAKGLGh0dHA6Ly9jcnQudGJzLWludGVybmV0LmNvbS9UQlNYNTA5Q0FTR0MuY3J0 +MDQGCCsGAQUFBzAChihodHRwOi8vY3J0LnRicy14NTA5LmNvbS9UQlNYNTA5Q0FT +R0MuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC50YnMteDUwOS5jb20wPwYD +VR0RBDgwNoIXc2hhMjU2LnRicy1pbnRlcm5ldC5jb22CG3d3dy5zaGEyNTYudGJz +LWludGVybmV0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAA5NL0D4QSqhErhlkdPmz +XtiMvdGL+ZehM4coTRIpasM/Agt36Rc0NzCvnQwKE+wkngg1Gy2qe7Q0E/ziqBtB +fZYzdVgu1zdiL4kTaf+wFKYAFGsFbyeEmXysy+CMwaNoF2vpSjCU1UD56bEnTX/W +fxVZYxtBQUpnu2wOsm8cDZuZRv9XrYgAhGj9Tt6F0aVHSDGn59uwShG1+BVF/uju +SCyPTTjL1oc7YElJUzR/x4mQJYvtQI8gDIDAGEOs7v3R/gKa5EMfbUQUI4C84UbI +Yz09Jdnws/MkC/Hm1BZEqk89u7Hvfv+oHqEb0XaUo0TDfsxE0M1sMdnLb91QNQBm +UQ== +-----END CERTIFICATE----- + 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC + i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQXpDZ0ETJMV02WTx3GTnhhTANBgkqhkiG9w0BAQUFADBv +MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk +ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF +eHRlcm5hbCBDQSBSb290MB4XDTA1MTIwMTAwMDAwMFoXDTE5MDYyNDE5MDYzMFow +gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl +bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u +ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv +cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg +Q0EgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsgOkO3f7wzN6 +rOjg45tR5vjBfzK7qmV9IBxb/QW9EEXxG+E7FNhZqQLtwGBKoSsHTnQqV75wWMk0 +9tinWvftBkSpj5sTi/8cbzJfUvTSVYh3Qxv6AVVjMMH/ruLjE6y+4PoaPs8WoYAQ +ts5R4Z1g8c/WnTepLst2x0/Wv7GmuoQi+gXvHU6YrBiu7XkeYhzc95QdviWSJRDk +owhb5K43qhcvjRmBfO/paGlCliDGZp8mHwrI21mwobWpVjTxZRwYO3bd4+TGcI4G +Ie5wmHwE8F7SK1tgSqbBacKjDa93j7txKkfz/Yd2n7TGqOXiHPsJpG655vrKtnXk +9vs1zoDeJQIDAQABo4IBljCCAZIwHQYDVR0OBBYEFAdEdoWTKLx/bXjSCuv6TEvf +2YIfMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMCAGA1UdJQQZ +MBcGCisGAQQBgjcKAwMGCWCGSAGG+EIEATAYBgNVHSAEETAPMA0GCysGAQQBgOU3 +AgQBMHsGA1UdHwR0MHIwOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0Fk +ZFRydXN0RXh0ZXJuYWxDQVJvb3QuY3JsMDagNKAyhjBodHRwOi8vY3JsLmNvbW9k +by5uZXQvQWRkVHJ1c3RFeHRlcm5hbENBUm9vdC5jcmwwgYAGCCsGAQUFBwEBBHQw +cjA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5jb21vZG9jYS5jb20vQWRkVHJ1c3RV +VE5TR0NDQS5jcnQwNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvLm5ldC9B +ZGRUcnVzdFVUTlNHQ0NBLmNydDARBglghkgBhvhCAQEEBAMCAgQwDQYJKoZIhvcN +AQEFBQADggEBAK2zEzs+jcIrVK9oDkdDZNvhuBYTdCfpxfFs+OAujW0bIfJAy232 +euVsnJm6u/+OrqKudD2tad2BbejLLXhMZViaCmK7D9nrXHx4te5EP8rL19SUVqLY +1pTnv5dhNgEgvA7n5lIzDSYs7yRLsr7HJsYPr6SeYSuZizyX1SNz7ooJ32/F3X98 +RB0Mlc/E0OyOrkQ9/y5IrnpnaSora8CnUrV5XNOg+kyCz9edCyx4D5wXYcwZPVWz +8aDqquESrezPyjtfi4WRO4s/VD3HLZvOxzMrWAVYCDG9FxaOhF0QGuuG1F7F3GKV +v6prNyCl016kRl2j1UT+a7gLd8fA25A4C9E= +-----END CERTIFICATE----- + 2 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root + i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC +-----BEGIN CERTIFICATE----- +MIIEZjCCA06gAwIBAgIQUSYKkxzif5zDpV954HKugjANBgkqhkiG9w0BAQUFADCB +kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw +IFNHQzAeFw0wNTA2MDcwODA5MTBaFw0xOTA2MjQxOTA2MzBaMG8xCzAJBgNVBAYT +AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0 +ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB +IFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC39xoz5vIABC05 +4E5b7R+8bA/Ntfojts7emxEzl6QpTH2Tn71KvJPtAxrjj8/lbVBa1pcplFqAsEl6 +2y6V/bjKvzc4LR4+kUGtcFbH8E8/6DKedMrIkFTpxl8PeJ2aQDwOrGGqXhSPnoeh +alDc15pOrwWzpnGUnHGzUGAKxxOdOAeGAqjpqGkmGJCrTLBPI6s6T4TY386f4Wlv +u9dC12tE5Met7m1BX3JacQg3s3llpFmglDf3AC8NwpJy2tA4ctsUqEXEXSp9t7TW +xO6szRNEt8kr3UMAJfphuWlqWCMRt6czj1Z1WfXNKddGtworZbbTQm8Vsrh7++/p +XVPVNFonAgMBAAGjgdgwgdUwHwYDVR0jBBgwFoAUUzLRs89/+uDxoF2FTpLSnkUd +tE8wHQYDVR0OBBYEFK29mHo0tCb3+sQmVO8DveAky1QaMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MBEGCWCGSAGG+EIBAQQEAwIBAjAgBgNVHSUEGTAX +BgorBgEEAYI3CgMDBglghkgBhvhCBAEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDov +L2NybC51c2VydHJ1c3QuY29tL1VUTi1EQVRBQ29ycFNHQy5jcmwwDQYJKoZIhvcN +AQEFBQADggEBAMbuUxdoFLJRIh6QWA2U/b3xcOWGLcM2MY9USEbnLQg3vGwKYOEO +rVE04BKT6b64q7gmtOmWPSiPrmQH/uAB7MXjkesYoPF1ftsK5p+R26+udd8jkWjd +FwBaS/9kbHDrARrQkNnHptZt9hPk/7XJ0h4qy7ElQyZ42TCbTg0evmnv3+r+LbPM ++bDdtRTKkdSytaX7ARmjR3mfnYyVhzT4HziS2jamEfpr62vp3EV4FTkG101B5CHI +3C+H0be/SGB1pWLLJN47YaApIKa+xWycxOkKaSLvkTr6Jq/RW0GnOuL4OAdCq8Fb ++M5tug8EPzI0rNwEKNdwMBQmBsTkm5jVz3g= +-----END CERTIFICATE----- + 3 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC + i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB +kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw +IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG +EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD +VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu +dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 +E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ +D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK +4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq +lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW +bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB +o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT +MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js +LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr +BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB +AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj +j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH +KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv +2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 +mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- Modified: python/branches/py3k/Lib/test/test_ssl.py ============================================================================== --- python/branches/py3k/Lib/test/test_ssl.py (original) +++ python/branches/py3k/Lib/test/test_ssl.py Sat Jan 8 11:23:29 2011 @@ -602,7 +602,7 @@ # https://sha2.hboeck.de/ was used until 2011-01-08 (no route to host) remote = ("sha256.tbs-internet.com", 443) sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem") - with support.transient_internet("sha2.hboeck.de"): + with support.transient_internet("sha256.tbs-internet.com"): s = ssl.wrap_socket(socket.socket(socket.AF_INET), cert_reqs=ssl.CERT_REQUIRED, ca_certs=sha256_cert,) From python-checkins at python.org Sat Jan 8 11:26:54 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 8 Jan 2011 11:26:54 +0100 (CET) Subject: [Python-checkins] r87862 - python/branches/py3k/Doc/library/operator.rst Message-ID: <20110108102654.11D93EEA54@mail.python.org> Author: raymond.hettinger Date: Sat Jan 8 11:26:53 2011 New Revision: 87862 Log: Issue 9717: Segregate and improve the documentation of "in-place" operators in the operator module. Modified: python/branches/py3k/Doc/library/operator.rst Modified: python/branches/py3k/Doc/library/operator.rst ============================================================================== --- python/branches/py3k/Doc/library/operator.rst (original) +++ python/branches/py3k/Doc/library/operator.rst Sat Jan 8 11:26:53 2011 @@ -225,91 +225,6 @@ Set the value of *a* at index *b* to *c*. - -Many operations have an "in-place" version. The following functions provide a -more primitive access to in-place operators than the usual syntax does; for -example, the :term:`statement` ``x += y`` is equivalent to -``x = operator.iadd(x, y)``. Another way to put it is to say that -``z = operator.iadd(x, y)`` is equivalent to the compound statement -``z = x; z += y``. - -.. function:: iadd(a, b) - __iadd__(a, b) - - ``a = iadd(a, b)`` is equivalent to ``a += b``. - - -.. function:: iand(a, b) - __iand__(a, b) - - ``a = iand(a, b)`` is equivalent to ``a &= b``. - - -.. function:: iconcat(a, b) - __iconcat__(a, b) - - ``a = iconcat(a, b)`` is equivalent to ``a += b`` for *a* and *b* sequences. - - -.. function:: ifloordiv(a, b) - __ifloordiv__(a, b) - - ``a = ifloordiv(a, b)`` is equivalent to ``a //= b``. - - -.. function:: ilshift(a, b) - __ilshift__(a, b) - - ``a = ilshift(a, b)`` is equivalent to ``a <<= b``. - - -.. function:: imod(a, b) - __imod__(a, b) - - ``a = imod(a, b)`` is equivalent to ``a %= b``. - - -.. function:: imul(a, b) - __imul__(a, b) - - ``a = imul(a, b)`` is equivalent to ``a *= b``. - - -.. function:: ior(a, b) - __ior__(a, b) - - ``a = ior(a, b)`` is equivalent to ``a |= b``. - - -.. function:: ipow(a, b) - __ipow__(a, b) - - ``a = ipow(a, b)`` is equivalent to ``a **= b``. - - -.. function:: irshift(a, b) - __irshift__(a, b) - - ``a = irshift(a, b)`` is equivalent to ``a >>= b``. - - -.. function:: isub(a, b) - __isub__(a, b) - - ``a = isub(a, b)`` is equivalent to ``a -= b``. - - -.. function:: itruediv(a, b) - __itruediv__(a, b) - - ``a = itruediv(a, b)`` is equivalent to ``a /= b``. - - -.. function:: ixor(a, b) - __ixor__(a, b) - - ``a = ixor(a, b)`` is equivalent to ``a ^= b``. - Example: Build a dictionary that maps the ordinals from ``0`` to ``255`` to their character equivalents. @@ -490,3 +405,112 @@ | Ordering | ``a > b`` | ``gt(a, b)`` | +-----------------------+-------------------------+---------------------------------------+ +Inplace Operators +================= + +Many operations have an "in-place" version. Listed below are functions +providing a more primitive access to in-place operators than the usual syntax +does; for example, the :term:`statement` ``x += y`` is equivalent to +``x = operator.iadd(x, y)``. Another way to put it is to say that +``z = operator.iadd(x, y)`` is equivalent to the compound statement +``z = x; z += y``. + +In those examples, note that when an in-place method is called, the computation +and assignment are performed in two separate steps. The in-place functions +listed below only do the first step, calling the in-place method. The second +step, assignment, is not handled. + +For immutable targets such as strings, numbers, and tuples, the updated +value is computed, but not assigned back to the input variable: + +>>> a = 'hello' +>>> iadd(a, ' world') +'hello world' +>>> a +'hello' + +For mutable targets such as lists and dictionaries, the inplace method +will perform the update, so no subsequent assignment is necessary: + +>>> s = ['h', 'e', 'l', 'l', 'o'] +>>> iadd(s, [' ', 'w', 'o', 'r', 'l', 'd']) +['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'] +>>> s +['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'] + +.. function:: iadd(a, b) + __iadd__(a, b) + + ``a = iadd(a, b)`` is equivalent to ``a += b``. + + +.. function:: iand(a, b) + __iand__(a, b) + + ``a = iand(a, b)`` is equivalent to ``a &= b``. + + +.. function:: iconcat(a, b) + __iconcat__(a, b) + + ``a = iconcat(a, b)`` is equivalent to ``a += b`` for *a* and *b* sequences. + + +.. function:: ifloordiv(a, b) + __ifloordiv__(a, b) + + ``a = ifloordiv(a, b)`` is equivalent to ``a //= b``. + + +.. function:: ilshift(a, b) + __ilshift__(a, b) + + ``a = ilshift(a, b)`` is equivalent to ``a <<= b``. + + +.. function:: imod(a, b) + __imod__(a, b) + + ``a = imod(a, b)`` is equivalent to ``a %= b``. + + +.. function:: imul(a, b) + __imul__(a, b) + + ``a = imul(a, b)`` is equivalent to ``a *= b``. + + +.. function:: ior(a, b) + __ior__(a, b) + + ``a = ior(a, b)`` is equivalent to ``a |= b``. + + +.. function:: ipow(a, b) + __ipow__(a, b) + + ``a = ipow(a, b)`` is equivalent to ``a **= b``. + + +.. function:: irshift(a, b) + __irshift__(a, b) + + ``a = irshift(a, b)`` is equivalent to ``a >>= b``. + + +.. function:: isub(a, b) + __isub__(a, b) + + ``a = isub(a, b)`` is equivalent to ``a -= b``. + + +.. function:: itruediv(a, b) + __itruediv__(a, b) + + ``a = itruediv(a, b)`` is equivalent to ``a /= b``. + + +.. function:: ixor(a, b) + __ixor__(a, b) + + ``a = ixor(a, b)`` is equivalent to ``a ^= b``. From python-checkins at python.org Sat Jan 8 11:28:12 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 8 Jan 2011 11:28:12 +0100 (CET) Subject: [Python-checkins] r87863 - python/branches/py3k/Lib/test/support.py Message-ID: <20110108102812.116F1EEA70@mail.python.org> Author: antoine.pitrou Date: Sat Jan 8 11:28:11 2011 New Revision: 87863 Log: Add EHOSTUNREACH ('No route to host') to the errnos trapped by transient_internet(). Modified: python/branches/py3k/Lib/test/support.py Modified: python/branches/py3k/Lib/test/support.py ============================================================================== --- python/branches/py3k/Lib/test/support.py (original) +++ python/branches/py3k/Lib/test/support.py Sat Jan 8 11:28:11 2011 @@ -800,6 +800,7 @@ default_errnos = [ ('ECONNREFUSED', 111), ('ECONNRESET', 104), + ('EHOSTUNREACH', 113), ('ENETUNREACH', 101), ('ETIMEDOUT', 110), ] From python-checkins at python.org Sat Jan 8 11:31:09 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 8 Jan 2011 11:31:09 +0100 (CET) Subject: [Python-checkins] r87864 - in python/branches/release31-maint: Lib/test/sha256.pem Lib/test/support.py Lib/test/test_ssl.py Message-ID: <20110108103109.B9C1FEEA56@mail.python.org> Author: antoine.pitrou Date: Sat Jan 8 11:31:09 2011 New Revision: 87864 Log: Merged revisions 87861,87863 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87861 | antoine.pitrou | 2011-01-08 11:23:29 +0100 (sam., 08 janv. 2011) | 3 lines Fix test_ssl after r87849 ........ r87863 | antoine.pitrou | 2011-01-08 11:28:11 +0100 (sam., 08 janv. 2011) | 3 lines Add EHOSTUNREACH ('No route to host') to the errnos trapped by transient_internet(). ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/test/sha256.pem python/branches/release31-maint/Lib/test/support.py python/branches/release31-maint/Lib/test/test_ssl.py Modified: python/branches/release31-maint/Lib/test/sha256.pem ============================================================================== --- python/branches/release31-maint/Lib/test/sha256.pem (original) +++ python/branches/release31-maint/Lib/test/sha256.pem Sat Jan 8 11:31:09 2011 @@ -1,33 +1,129 @@ +# Certificate chain for https://sha256.tbs-internet.com + 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=sha-256 production/CN=sha256.tbs-internet.com + i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC -----BEGIN CERTIFICATE----- -MIIFxzCCA6+gAwIBAgIJALnlnf5uzTkIMA0GCSqGSIb3DQEBCwUAMEsxCzAJBgNV -BAYTAkRFMRcwFQYDVQQKEw5zY2hva29rZWtzLm9yZzEjMCEGCSqGSIb3DQEJARYU -aGFubm9Ac2Nob2tva2Vrcy5vcmcwHhcNMTAwMTI3MDAyMTI1WhcNMjAwMTI1MDAy -MTI1WjBLMQswCQYDVQQGEwJERTEXMBUGA1UEChMOc2Nob2tva2Vrcy5vcmcxIzAh -BgkqhkiG9w0BCQEWFGhhbm5vQHNjaG9rb2tla3Mub3JnMIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEApJ4ODPwEooMW35dQPlBqdvcfkEvjhcsA7jmJfFqN -e/1T34zT44X9+KnMBSG2InacbD7eyFgjfaENFsZ87YkEBDIFZ/SHotLJZORQ8PUj -YoxPG4mjKN+yL2WthNcYbRyJreTbbDroNMuw6tkTSxeSXyYFQrKMCUfErVbZa/d5 -RvfFVk+Au9dVUFhed/Stn5cv+a0ffvpyA7ygihm1kMFICbvPeI0846tmC2Ph7rM5 -pYQyNBDOVpULODTk5Wu6jiiJJygvJWCZ1FdpsdBs5aKWHWdRhX++quGuflTTjH5d -qaIka4op9H7XksYphTDXmV+qHnva5jbPogwutDQcVsGBQcJaLmQqhsQK13bf4khE -iWJvfBLfHn8OOpY25ZwwuigJIwifNCxQeeT1FrLmyuYNhz2phPpzx065kqSUSR+A -Iw8DPE6e65UqMDKqZnID3dQeiQaFrHEV+Ibo0U/tD0YSBw5p33TMh0Es33IBWMac -m7x4hIFWdhl8W522u6qOrTswY3s8vB7blNWqMc9n7oWH8ybFf7EgKeDVtEN9AyBE -0WotXIEZWI+WvDbU1ACJXau9sQhYP/eerg7Zwr3iGUy4IQ5oUJibnjtcE+z8zmDN -pE6YcMCLJyLjXiQ3iHG9mNXzw7wPnslTbEEEukrfSlHGgW8Dm+VrNyW0JUM1bntx -vbMCAwEAAaOBrTCBqjAdBgNVHQ4EFgQUCedv7pDTuXtCxm4HTw9hUtrTvsowewYD -VR0jBHQwcoAUCedv7pDTuXtCxm4HTw9hUtrTvsqhT6RNMEsxCzAJBgNVBAYTAkRF -MRcwFQYDVQQKEw5zY2hva29rZWtzLm9yZzEjMCEGCSqGSIb3DQEJARYUaGFubm9A -c2Nob2tva2Vrcy5vcmeCCQC55Z3+bs05CDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 -DQEBCwUAA4ICAQBHKAxA7WA/MEFjet03K8ouzEOr6Jrk2fZOuRhoDZ+9gr4FtaJB -P3Hh5D00kuSOvDnwsvCohxeNd1KTMAwVmVoH+NZkHERn3UXniUENlp18koI1ehlr -CZbXbzzE9Te9BelliSFA63q0cq0yJN1x9GyabU34XkAouCAmOqfSpKNZWZHGBHPF -bbYnZrHEMcsye6vKeTOcg1GqUHGrQM2WK0QaOwnCQv2RblI9VN+SeRoUJ44qTXdW -TwIYStsIPesacNcAQTStnHgKqIPx4zCwdx5xo8zONbXJfocqwyFqiAofvb9dN1nW -g1noVBcXB+oRBZW5CjFw87U88itq39i9+BWl835DWLBW2pVmx1QTLGv0RNgs/xVx -mWnjH4nNHvrjn6pRmqHZTk/SS0Hkl2qtDsynVxIl8EiMTfWSU3DBTuD2J/RSzuOE -eKtAbaoXkXE31jCl4FEZLITIZd8UkXacb9rN304tAK92L76JOAV+xOZxFRipmvx4 -+A9qQXgLhtP4VaDajb44V/kCKPSA0Vm3apehke9Wl8dDtagfos1e6MxSu3EVLXRF -SP2U777V77pdMSd0f/7cerKn5FjrxW1v1FaP1oIGniMk4qQNTgA/jvvhjybsPlVA -jsfnhWGbh1voJa0RQcMiRMsxpw2P1KNOEu37W2eq/vFghVztZJQUmb5iNw== +MIIGXTCCBUWgAwIBAgIRAMmag+ygSAdxZsbyzYjhuW0wDQYJKoZIhvcNAQELBQAw +gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl +bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u +ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv +cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg +Q0EgU0dDMB4XDTEwMDIxODAwMDAwMFoXDTEyMDIxOTIzNTk1OVowgcsxCzAJBgNV +BAYTAkZSMQ4wDAYDVQQREwUxNDAwMDERMA8GA1UECBMIQ2FsdmFkb3MxDTALBgNV +BAcTBENBRU4xGzAZBgNVBAkTEjIyIHJ1ZSBkZSBCcmV0YWduZTEVMBMGA1UEChMM +VEJTIElOVEVSTkVUMRcwFQYDVQQLEw4wMDAyIDQ0MDQ0MzgxMDEbMBkGA1UECxMS +c2hhLTI1NiBwcm9kdWN0aW9uMSAwHgYDVQQDExdzaGEyNTYudGJzLWludGVybmV0 +LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbuM8VT7f0nntwu +N3F7v9KIBlhKNAxqCrziOXU5iqUt8HrQB3DtHbdmII+CpVUlwlmepsx6G+srEZ9a +MIGAy0nxi5aLb7watkyIdPjJTMvTUBQ/+RPWzt5JtYbbY9BlJ+yci0dctP74f4NU +ISLtlrEjUbf2gTohLrcE01TfmOF6PDEbB5PKDi38cB3NzKfizWfrOaJW6Q1C1qOJ +y4/4jkUREX1UFUIxzx7v62VfjXSGlcjGpBX1fvtABQOSLeE0a6gciDZs1REqroFf +5eXtqYphpTa14Z83ITXMfgg5Nze1VtMnzI9Qx4blYBw4dgQVEuIsYr7FDBOITDzc +VEVXZx0CAwEAAaOCAj8wggI7MB8GA1UdIwQYMBaAFAdEdoWTKLx/bXjSCuv6TEvf +2YIfMB0GA1UdDgQWBBSJKI/AYVI9RQNY0QPIqc8ej2QivTAOBgNVHQ8BAf8EBAMC +BaAwDAYDVR0TAQH/BAIwADA0BgNVHSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIG +CisGAQQBgjcKAwMGCWCGSAGG+EIEATBMBgNVHSAERTBDMEEGCysGAQQBgOU3AgQB +MDIwMAYIKwYBBQUHAgEWJGh0dHBzOi8vd3d3LnRicy1pbnRlcm5ldC5jb20vQ0Ev +Q1BTNDBtBgNVHR8EZjBkMDKgMKAuhixodHRwOi8vY3JsLnRicy1pbnRlcm5ldC5j +b20vVEJTWDUwOUNBU0dDLmNybDAuoCygKoYoaHR0cDovL2NybC50YnMteDUwOS5j +b20vVEJTWDUwOUNBU0dDLmNybDCBpgYIKwYBBQUHAQEEgZkwgZYwOAYIKwYBBQUH +MAKGLGh0dHA6Ly9jcnQudGJzLWludGVybmV0LmNvbS9UQlNYNTA5Q0FTR0MuY3J0 +MDQGCCsGAQUFBzAChihodHRwOi8vY3J0LnRicy14NTA5LmNvbS9UQlNYNTA5Q0FT +R0MuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC50YnMteDUwOS5jb20wPwYD +VR0RBDgwNoIXc2hhMjU2LnRicy1pbnRlcm5ldC5jb22CG3d3dy5zaGEyNTYudGJz +LWludGVybmV0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAA5NL0D4QSqhErhlkdPmz +XtiMvdGL+ZehM4coTRIpasM/Agt36Rc0NzCvnQwKE+wkngg1Gy2qe7Q0E/ziqBtB +fZYzdVgu1zdiL4kTaf+wFKYAFGsFbyeEmXysy+CMwaNoF2vpSjCU1UD56bEnTX/W +fxVZYxtBQUpnu2wOsm8cDZuZRv9XrYgAhGj9Tt6F0aVHSDGn59uwShG1+BVF/uju +SCyPTTjL1oc7YElJUzR/x4mQJYvtQI8gDIDAGEOs7v3R/gKa5EMfbUQUI4C84UbI +Yz09Jdnws/MkC/Hm1BZEqk89u7Hvfv+oHqEb0XaUo0TDfsxE0M1sMdnLb91QNQBm +UQ== +-----END CERTIFICATE----- + 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC + i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQXpDZ0ETJMV02WTx3GTnhhTANBgkqhkiG9w0BAQUFADBv +MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk +ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF +eHRlcm5hbCBDQSBSb290MB4XDTA1MTIwMTAwMDAwMFoXDTE5MDYyNDE5MDYzMFow +gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl +bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u +ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv +cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg +Q0EgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsgOkO3f7wzN6 +rOjg45tR5vjBfzK7qmV9IBxb/QW9EEXxG+E7FNhZqQLtwGBKoSsHTnQqV75wWMk0 +9tinWvftBkSpj5sTi/8cbzJfUvTSVYh3Qxv6AVVjMMH/ruLjE6y+4PoaPs8WoYAQ +ts5R4Z1g8c/WnTepLst2x0/Wv7GmuoQi+gXvHU6YrBiu7XkeYhzc95QdviWSJRDk +owhb5K43qhcvjRmBfO/paGlCliDGZp8mHwrI21mwobWpVjTxZRwYO3bd4+TGcI4G +Ie5wmHwE8F7SK1tgSqbBacKjDa93j7txKkfz/Yd2n7TGqOXiHPsJpG655vrKtnXk +9vs1zoDeJQIDAQABo4IBljCCAZIwHQYDVR0OBBYEFAdEdoWTKLx/bXjSCuv6TEvf +2YIfMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMCAGA1UdJQQZ +MBcGCisGAQQBgjcKAwMGCWCGSAGG+EIEATAYBgNVHSAEETAPMA0GCysGAQQBgOU3 +AgQBMHsGA1UdHwR0MHIwOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0Fk +ZFRydXN0RXh0ZXJuYWxDQVJvb3QuY3JsMDagNKAyhjBodHRwOi8vY3JsLmNvbW9k +by5uZXQvQWRkVHJ1c3RFeHRlcm5hbENBUm9vdC5jcmwwgYAGCCsGAQUFBwEBBHQw +cjA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5jb21vZG9jYS5jb20vQWRkVHJ1c3RV +VE5TR0NDQS5jcnQwNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvLm5ldC9B +ZGRUcnVzdFVUTlNHQ0NBLmNydDARBglghkgBhvhCAQEEBAMCAgQwDQYJKoZIhvcN +AQEFBQADggEBAK2zEzs+jcIrVK9oDkdDZNvhuBYTdCfpxfFs+OAujW0bIfJAy232 +euVsnJm6u/+OrqKudD2tad2BbejLLXhMZViaCmK7D9nrXHx4te5EP8rL19SUVqLY +1pTnv5dhNgEgvA7n5lIzDSYs7yRLsr7HJsYPr6SeYSuZizyX1SNz7ooJ32/F3X98 +RB0Mlc/E0OyOrkQ9/y5IrnpnaSora8CnUrV5XNOg+kyCz9edCyx4D5wXYcwZPVWz +8aDqquESrezPyjtfi4WRO4s/VD3HLZvOxzMrWAVYCDG9FxaOhF0QGuuG1F7F3GKV +v6prNyCl016kRl2j1UT+a7gLd8fA25A4C9E= +-----END CERTIFICATE----- + 2 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root + i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC +-----BEGIN CERTIFICATE----- +MIIEZjCCA06gAwIBAgIQUSYKkxzif5zDpV954HKugjANBgkqhkiG9w0BAQUFADCB +kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw +IFNHQzAeFw0wNTA2MDcwODA5MTBaFw0xOTA2MjQxOTA2MzBaMG8xCzAJBgNVBAYT +AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0 +ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB +IFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC39xoz5vIABC05 +4E5b7R+8bA/Ntfojts7emxEzl6QpTH2Tn71KvJPtAxrjj8/lbVBa1pcplFqAsEl6 +2y6V/bjKvzc4LR4+kUGtcFbH8E8/6DKedMrIkFTpxl8PeJ2aQDwOrGGqXhSPnoeh +alDc15pOrwWzpnGUnHGzUGAKxxOdOAeGAqjpqGkmGJCrTLBPI6s6T4TY386f4Wlv +u9dC12tE5Met7m1BX3JacQg3s3llpFmglDf3AC8NwpJy2tA4ctsUqEXEXSp9t7TW +xO6szRNEt8kr3UMAJfphuWlqWCMRt6czj1Z1WfXNKddGtworZbbTQm8Vsrh7++/p +XVPVNFonAgMBAAGjgdgwgdUwHwYDVR0jBBgwFoAUUzLRs89/+uDxoF2FTpLSnkUd +tE8wHQYDVR0OBBYEFK29mHo0tCb3+sQmVO8DveAky1QaMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MBEGCWCGSAGG+EIBAQQEAwIBAjAgBgNVHSUEGTAX +BgorBgEEAYI3CgMDBglghkgBhvhCBAEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDov +L2NybC51c2VydHJ1c3QuY29tL1VUTi1EQVRBQ29ycFNHQy5jcmwwDQYJKoZIhvcN +AQEFBQADggEBAMbuUxdoFLJRIh6QWA2U/b3xcOWGLcM2MY9USEbnLQg3vGwKYOEO +rVE04BKT6b64q7gmtOmWPSiPrmQH/uAB7MXjkesYoPF1ftsK5p+R26+udd8jkWjd +FwBaS/9kbHDrARrQkNnHptZt9hPk/7XJ0h4qy7ElQyZ42TCbTg0evmnv3+r+LbPM ++bDdtRTKkdSytaX7ARmjR3mfnYyVhzT4HziS2jamEfpr62vp3EV4FTkG101B5CHI +3C+H0be/SGB1pWLLJN47YaApIKa+xWycxOkKaSLvkTr6Jq/RW0GnOuL4OAdCq8Fb ++M5tug8EPzI0rNwEKNdwMBQmBsTkm5jVz3g= +-----END CERTIFICATE----- + 3 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC + i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB +kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw +IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG +EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD +VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu +dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 +E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ +D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK +4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq +lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW +bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB +o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT +MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js +LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr +BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB +AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj +j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH +KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv +2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 +mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- Modified: python/branches/release31-maint/Lib/test/support.py ============================================================================== --- python/branches/release31-maint/Lib/test/support.py (original) +++ python/branches/release31-maint/Lib/test/support.py Sat Jan 8 11:31:09 2011 @@ -623,6 +623,7 @@ default_errnos = [ ('ECONNREFUSED', 111), ('ECONNRESET', 104), + ('EHOSTUNREACH', 113), ('ENETUNREACH', 101), ('ETIMEDOUT', 110), ] Modified: python/branches/release31-maint/Lib/test/test_ssl.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_ssl.py (original) +++ python/branches/release31-maint/Lib/test/test_ssl.py Sat Jan 8 11:31:09 2011 @@ -228,7 +228,7 @@ # NOTE: https://sha256.tbs-internet.com is another possible test host remote = ("sha2.hboeck.de", 443) sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem") - with support.transient_internet("sha2.hboeck.de"): + with support.transient_internet("sha256.tbs-internet.com"): s = ssl.wrap_socket(socket.socket(socket.AF_INET), cert_reqs=ssl.CERT_REQUIRED, ca_certs=sha256_cert,) From python-checkins at python.org Sat Jan 8 11:32:31 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 8 Jan 2011 11:32:31 +0100 (CET) Subject: [Python-checkins] r87865 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110108103231.A5EF6EEA56@mail.python.org> Author: raymond.hettinger Date: Sat Jan 8 11:32:31 2011 New Revision: 87865 Log: Markup fix Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Sat Jan 8 11:32:31 2011 @@ -618,8 +618,8 @@ * Given bytes input to the model, :class:`~email.generator.Generator` will convert message bodies that have a :mailheader:`Content-Transfer-Encoding` of *8bit* to instead have a *7bit* :mailheader:`Content-Transfer-Encoding`. - XXX: Headers with Un-encoded non-ASCII bytes will be :rfc:`2047`\ -encoded - using the charset `unknown-8bit`. + +.. XXX: Headers with Un-encoded non-ASCII bytes will be :rfc:`2047`\ -encoded using the charset `unknown-8bit`. * A new class :class:`~email.generator.BytesGenerator` produces bytes as output, preserving any unchanged non-ASCII data that was present in the input used to From python-checkins at python.org Sat Jan 8 11:32:51 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 8 Jan 2011 11:32:51 +0100 (CET) Subject: [Python-checkins] r87866 - in python/branches/release27-maint: Lib/test/sha256.pem Lib/test/test_ssl.py Lib/test/test_support.py Message-ID: <20110108103251.AC45AEEA56@mail.python.org> Author: antoine.pitrou Date: Sat Jan 8 11:32:51 2011 New Revision: 87866 Log: Merged revisions 87861,87863 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87861 | antoine.pitrou | 2011-01-08 11:23:29 +0100 (sam., 08 janv. 2011) | 3 lines Fix test_ssl after r87849 ........ r87863 | antoine.pitrou | 2011-01-08 11:28:11 +0100 (sam., 08 janv. 2011) | 3 lines Add EHOSTUNREACH ('No route to host') to the errnos trapped by transient_internet(). ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/test/sha256.pem python/branches/release27-maint/Lib/test/test_ssl.py python/branches/release27-maint/Lib/test/test_support.py Modified: python/branches/release27-maint/Lib/test/sha256.pem ============================================================================== --- python/branches/release27-maint/Lib/test/sha256.pem (original) +++ python/branches/release27-maint/Lib/test/sha256.pem Sat Jan 8 11:32:51 2011 @@ -1,33 +1,129 @@ +# Certificate chain for https://sha256.tbs-internet.com + 0 s:/C=FR/postalCode=14000/ST=Calvados/L=CAEN/street=22 rue de Bretagne/O=TBS INTERNET/OU=0002 440443810/OU=sha-256 production/CN=sha256.tbs-internet.com + i:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC -----BEGIN CERTIFICATE----- -MIIFxzCCA6+gAwIBAgIJALnlnf5uzTkIMA0GCSqGSIb3DQEBCwUAMEsxCzAJBgNV -BAYTAkRFMRcwFQYDVQQKEw5zY2hva29rZWtzLm9yZzEjMCEGCSqGSIb3DQEJARYU -aGFubm9Ac2Nob2tva2Vrcy5vcmcwHhcNMTAwMTI3MDAyMTI1WhcNMjAwMTI1MDAy -MTI1WjBLMQswCQYDVQQGEwJERTEXMBUGA1UEChMOc2Nob2tva2Vrcy5vcmcxIzAh -BgkqhkiG9w0BCQEWFGhhbm5vQHNjaG9rb2tla3Mub3JnMIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEApJ4ODPwEooMW35dQPlBqdvcfkEvjhcsA7jmJfFqN -e/1T34zT44X9+KnMBSG2InacbD7eyFgjfaENFsZ87YkEBDIFZ/SHotLJZORQ8PUj -YoxPG4mjKN+yL2WthNcYbRyJreTbbDroNMuw6tkTSxeSXyYFQrKMCUfErVbZa/d5 -RvfFVk+Au9dVUFhed/Stn5cv+a0ffvpyA7ygihm1kMFICbvPeI0846tmC2Ph7rM5 -pYQyNBDOVpULODTk5Wu6jiiJJygvJWCZ1FdpsdBs5aKWHWdRhX++quGuflTTjH5d -qaIka4op9H7XksYphTDXmV+qHnva5jbPogwutDQcVsGBQcJaLmQqhsQK13bf4khE -iWJvfBLfHn8OOpY25ZwwuigJIwifNCxQeeT1FrLmyuYNhz2phPpzx065kqSUSR+A -Iw8DPE6e65UqMDKqZnID3dQeiQaFrHEV+Ibo0U/tD0YSBw5p33TMh0Es33IBWMac -m7x4hIFWdhl8W522u6qOrTswY3s8vB7blNWqMc9n7oWH8ybFf7EgKeDVtEN9AyBE -0WotXIEZWI+WvDbU1ACJXau9sQhYP/eerg7Zwr3iGUy4IQ5oUJibnjtcE+z8zmDN -pE6YcMCLJyLjXiQ3iHG9mNXzw7wPnslTbEEEukrfSlHGgW8Dm+VrNyW0JUM1bntx -vbMCAwEAAaOBrTCBqjAdBgNVHQ4EFgQUCedv7pDTuXtCxm4HTw9hUtrTvsowewYD -VR0jBHQwcoAUCedv7pDTuXtCxm4HTw9hUtrTvsqhT6RNMEsxCzAJBgNVBAYTAkRF -MRcwFQYDVQQKEw5zY2hva29rZWtzLm9yZzEjMCEGCSqGSIb3DQEJARYUaGFubm9A -c2Nob2tva2Vrcy5vcmeCCQC55Z3+bs05CDAMBgNVHRMEBTADAQH/MA0GCSqGSIb3 -DQEBCwUAA4ICAQBHKAxA7WA/MEFjet03K8ouzEOr6Jrk2fZOuRhoDZ+9gr4FtaJB -P3Hh5D00kuSOvDnwsvCohxeNd1KTMAwVmVoH+NZkHERn3UXniUENlp18koI1ehlr -CZbXbzzE9Te9BelliSFA63q0cq0yJN1x9GyabU34XkAouCAmOqfSpKNZWZHGBHPF -bbYnZrHEMcsye6vKeTOcg1GqUHGrQM2WK0QaOwnCQv2RblI9VN+SeRoUJ44qTXdW -TwIYStsIPesacNcAQTStnHgKqIPx4zCwdx5xo8zONbXJfocqwyFqiAofvb9dN1nW -g1noVBcXB+oRBZW5CjFw87U88itq39i9+BWl835DWLBW2pVmx1QTLGv0RNgs/xVx -mWnjH4nNHvrjn6pRmqHZTk/SS0Hkl2qtDsynVxIl8EiMTfWSU3DBTuD2J/RSzuOE -eKtAbaoXkXE31jCl4FEZLITIZd8UkXacb9rN304tAK92L76JOAV+xOZxFRipmvx4 -+A9qQXgLhtP4VaDajb44V/kCKPSA0Vm3apehke9Wl8dDtagfos1e6MxSu3EVLXRF -SP2U777V77pdMSd0f/7cerKn5FjrxW1v1FaP1oIGniMk4qQNTgA/jvvhjybsPlVA -jsfnhWGbh1voJa0RQcMiRMsxpw2P1KNOEu37W2eq/vFghVztZJQUmb5iNw== +MIIGXTCCBUWgAwIBAgIRAMmag+ygSAdxZsbyzYjhuW0wDQYJKoZIhvcNAQELBQAw +gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl +bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u +ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv +cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg +Q0EgU0dDMB4XDTEwMDIxODAwMDAwMFoXDTEyMDIxOTIzNTk1OVowgcsxCzAJBgNV +BAYTAkZSMQ4wDAYDVQQREwUxNDAwMDERMA8GA1UECBMIQ2FsdmFkb3MxDTALBgNV +BAcTBENBRU4xGzAZBgNVBAkTEjIyIHJ1ZSBkZSBCcmV0YWduZTEVMBMGA1UEChMM +VEJTIElOVEVSTkVUMRcwFQYDVQQLEw4wMDAyIDQ0MDQ0MzgxMDEbMBkGA1UECxMS +c2hhLTI1NiBwcm9kdWN0aW9uMSAwHgYDVQQDExdzaGEyNTYudGJzLWludGVybmV0 +LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKbuM8VT7f0nntwu +N3F7v9KIBlhKNAxqCrziOXU5iqUt8HrQB3DtHbdmII+CpVUlwlmepsx6G+srEZ9a +MIGAy0nxi5aLb7watkyIdPjJTMvTUBQ/+RPWzt5JtYbbY9BlJ+yci0dctP74f4NU +ISLtlrEjUbf2gTohLrcE01TfmOF6PDEbB5PKDi38cB3NzKfizWfrOaJW6Q1C1qOJ +y4/4jkUREX1UFUIxzx7v62VfjXSGlcjGpBX1fvtABQOSLeE0a6gciDZs1REqroFf +5eXtqYphpTa14Z83ITXMfgg5Nze1VtMnzI9Qx4blYBw4dgQVEuIsYr7FDBOITDzc +VEVXZx0CAwEAAaOCAj8wggI7MB8GA1UdIwQYMBaAFAdEdoWTKLx/bXjSCuv6TEvf +2YIfMB0GA1UdDgQWBBSJKI/AYVI9RQNY0QPIqc8ej2QivTAOBgNVHQ8BAf8EBAMC +BaAwDAYDVR0TAQH/BAIwADA0BgNVHSUELTArBggrBgEFBQcDAQYIKwYBBQUHAwIG +CisGAQQBgjcKAwMGCWCGSAGG+EIEATBMBgNVHSAERTBDMEEGCysGAQQBgOU3AgQB +MDIwMAYIKwYBBQUHAgEWJGh0dHBzOi8vd3d3LnRicy1pbnRlcm5ldC5jb20vQ0Ev +Q1BTNDBtBgNVHR8EZjBkMDKgMKAuhixodHRwOi8vY3JsLnRicy1pbnRlcm5ldC5j +b20vVEJTWDUwOUNBU0dDLmNybDAuoCygKoYoaHR0cDovL2NybC50YnMteDUwOS5j +b20vVEJTWDUwOUNBU0dDLmNybDCBpgYIKwYBBQUHAQEEgZkwgZYwOAYIKwYBBQUH +MAKGLGh0dHA6Ly9jcnQudGJzLWludGVybmV0LmNvbS9UQlNYNTA5Q0FTR0MuY3J0 +MDQGCCsGAQUFBzAChihodHRwOi8vY3J0LnRicy14NTA5LmNvbS9UQlNYNTA5Q0FT +R0MuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC50YnMteDUwOS5jb20wPwYD +VR0RBDgwNoIXc2hhMjU2LnRicy1pbnRlcm5ldC5jb22CG3d3dy5zaGEyNTYudGJz +LWludGVybmV0LmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAA5NL0D4QSqhErhlkdPmz +XtiMvdGL+ZehM4coTRIpasM/Agt36Rc0NzCvnQwKE+wkngg1Gy2qe7Q0E/ziqBtB +fZYzdVgu1zdiL4kTaf+wFKYAFGsFbyeEmXysy+CMwaNoF2vpSjCU1UD56bEnTX/W +fxVZYxtBQUpnu2wOsm8cDZuZRv9XrYgAhGj9Tt6F0aVHSDGn59uwShG1+BVF/uju +SCyPTTjL1oc7YElJUzR/x4mQJYvtQI8gDIDAGEOs7v3R/gKa5EMfbUQUI4C84UbI +Yz09Jdnws/MkC/Hm1BZEqk89u7Hvfv+oHqEb0XaUo0TDfsxE0M1sMdnLb91QNQBm +UQ== +-----END CERTIFICATE----- + 1 s:/C=FR/ST=Calvados/L=Caen/O=TBS INTERNET/OU=Terms and Conditions: http://www.tbs-internet.com/CA/repository/OU=TBS INTERNET CA/CN=TBS X509 CA SGC + i:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQXpDZ0ETJMV02WTx3GTnhhTANBgkqhkiG9w0BAQUFADBv +MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk +ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF +eHRlcm5hbCBDQSBSb290MB4XDTA1MTIwMTAwMDAwMFoXDTE5MDYyNDE5MDYzMFow +gcQxCzAJBgNVBAYTAkZSMREwDwYDVQQIEwhDYWx2YWRvczENMAsGA1UEBxMEQ2Fl +bjEVMBMGA1UEChMMVEJTIElOVEVSTkVUMUgwRgYDVQQLEz9UZXJtcyBhbmQgQ29u +ZGl0aW9uczogaHR0cDovL3d3dy50YnMtaW50ZXJuZXQuY29tL0NBL3JlcG9zaXRv +cnkxGDAWBgNVBAsTD1RCUyBJTlRFUk5FVCBDQTEYMBYGA1UEAxMPVEJTIFg1MDkg +Q0EgU0dDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsgOkO3f7wzN6 +rOjg45tR5vjBfzK7qmV9IBxb/QW9EEXxG+E7FNhZqQLtwGBKoSsHTnQqV75wWMk0 +9tinWvftBkSpj5sTi/8cbzJfUvTSVYh3Qxv6AVVjMMH/ruLjE6y+4PoaPs8WoYAQ +ts5R4Z1g8c/WnTepLst2x0/Wv7GmuoQi+gXvHU6YrBiu7XkeYhzc95QdviWSJRDk +owhb5K43qhcvjRmBfO/paGlCliDGZp8mHwrI21mwobWpVjTxZRwYO3bd4+TGcI4G +Ie5wmHwE8F7SK1tgSqbBacKjDa93j7txKkfz/Yd2n7TGqOXiHPsJpG655vrKtnXk +9vs1zoDeJQIDAQABo4IBljCCAZIwHQYDVR0OBBYEFAdEdoWTKLx/bXjSCuv6TEvf +2YIfMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMCAGA1UdJQQZ +MBcGCisGAQQBgjcKAwMGCWCGSAGG+EIEATAYBgNVHSAEETAPMA0GCysGAQQBgOU3 +AgQBMHsGA1UdHwR0MHIwOKA2oDSGMmh0dHA6Ly9jcmwuY29tb2RvY2EuY29tL0Fk +ZFRydXN0RXh0ZXJuYWxDQVJvb3QuY3JsMDagNKAyhjBodHRwOi8vY3JsLmNvbW9k +by5uZXQvQWRkVHJ1c3RFeHRlcm5hbENBUm9vdC5jcmwwgYAGCCsGAQUFBwEBBHQw +cjA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5jb21vZG9jYS5jb20vQWRkVHJ1c3RV +VE5TR0NDQS5jcnQwNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvLm5ldC9B +ZGRUcnVzdFVUTlNHQ0NBLmNydDARBglghkgBhvhCAQEEBAMCAgQwDQYJKoZIhvcN +AQEFBQADggEBAK2zEzs+jcIrVK9oDkdDZNvhuBYTdCfpxfFs+OAujW0bIfJAy232 +euVsnJm6u/+OrqKudD2tad2BbejLLXhMZViaCmK7D9nrXHx4te5EP8rL19SUVqLY +1pTnv5dhNgEgvA7n5lIzDSYs7yRLsr7HJsYPr6SeYSuZizyX1SNz7ooJ32/F3X98 +RB0Mlc/E0OyOrkQ9/y5IrnpnaSora8CnUrV5XNOg+kyCz9edCyx4D5wXYcwZPVWz +8aDqquESrezPyjtfi4WRO4s/VD3HLZvOxzMrWAVYCDG9FxaOhF0QGuuG1F7F3GKV +v6prNyCl016kRl2j1UT+a7gLd8fA25A4C9E= +-----END CERTIFICATE----- + 2 s:/C=SE/O=AddTrust AB/OU=AddTrust External TTP Network/CN=AddTrust External CA Root + i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC +-----BEGIN CERTIFICATE----- +MIIEZjCCA06gAwIBAgIQUSYKkxzif5zDpV954HKugjANBgkqhkiG9w0BAQUFADCB +kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw +IFNHQzAeFw0wNTA2MDcwODA5MTBaFw0xOTA2MjQxOTA2MzBaMG8xCzAJBgNVBAYT +AlNFMRQwEgYDVQQKEwtBZGRUcnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0 +ZXJuYWwgVFRQIE5ldHdvcmsxIjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENB +IFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC39xoz5vIABC05 +4E5b7R+8bA/Ntfojts7emxEzl6QpTH2Tn71KvJPtAxrjj8/lbVBa1pcplFqAsEl6 +2y6V/bjKvzc4LR4+kUGtcFbH8E8/6DKedMrIkFTpxl8PeJ2aQDwOrGGqXhSPnoeh +alDc15pOrwWzpnGUnHGzUGAKxxOdOAeGAqjpqGkmGJCrTLBPI6s6T4TY386f4Wlv +u9dC12tE5Met7m1BX3JacQg3s3llpFmglDf3AC8NwpJy2tA4ctsUqEXEXSp9t7TW +xO6szRNEt8kr3UMAJfphuWlqWCMRt6czj1Z1WfXNKddGtworZbbTQm8Vsrh7++/p +XVPVNFonAgMBAAGjgdgwgdUwHwYDVR0jBBgwFoAUUzLRs89/+uDxoF2FTpLSnkUd +tE8wHQYDVR0OBBYEFK29mHo0tCb3+sQmVO8DveAky1QaMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MBEGCWCGSAGG+EIBAQQEAwIBAjAgBgNVHSUEGTAX +BgorBgEEAYI3CgMDBglghkgBhvhCBAEwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDov +L2NybC51c2VydHJ1c3QuY29tL1VUTi1EQVRBQ29ycFNHQy5jcmwwDQYJKoZIhvcN +AQEFBQADggEBAMbuUxdoFLJRIh6QWA2U/b3xcOWGLcM2MY9USEbnLQg3vGwKYOEO +rVE04BKT6b64q7gmtOmWPSiPrmQH/uAB7MXjkesYoPF1ftsK5p+R26+udd8jkWjd +FwBaS/9kbHDrARrQkNnHptZt9hPk/7XJ0h4qy7ElQyZ42TCbTg0evmnv3+r+LbPM ++bDdtRTKkdSytaX7ARmjR3mfnYyVhzT4HziS2jamEfpr62vp3EV4FTkG101B5CHI +3C+H0be/SGB1pWLLJN47YaApIKa+xWycxOkKaSLvkTr6Jq/RW0GnOuL4OAdCq8Fb ++M5tug8EPzI0rNwEKNdwMBQmBsTkm5jVz3g= +-----END CERTIFICATE----- + 3 s:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC + i:/C=US/ST=UT/L=Salt Lake City/O=The USERTRUST Network/OU=http://www.usertrust.com/CN=UTN - DATACorp SGC +-----BEGIN CERTIFICATE----- +MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB +kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug +Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho +dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw +IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG +EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD +VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu +dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6 +E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ +D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK +4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq +lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW +bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB +o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT +MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js +LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr +BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB +AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft +Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj +j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH +KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv +2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3 +mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- Modified: python/branches/release27-maint/Lib/test/test_ssl.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_ssl.py (original) +++ python/branches/release27-maint/Lib/test/test_ssl.py Sat Jan 8 11:32:51 2011 @@ -297,9 +297,9 @@ if ssl.OPENSSL_VERSION_INFO < (0, 9, 8, 0, 15): self.skipTest("SHA256 not available on %r" % ssl.OPENSSL_VERSION) # NOTE: https://sha256.tbs-internet.com is another possible test host - remote = ("sha2.hboeck.de", 443) + remote = ("sha256.tbs-internet.com", 443) sha256_cert = os.path.join(os.path.dirname(__file__), "sha256.pem") - with test_support.transient_internet("sha2.hboeck.de"): + with test_support.transient_internet("sha256.tbs-internet.com"): s = ssl.wrap_socket(socket.socket(socket.AF_INET), cert_reqs=ssl.CERT_REQUIRED, ca_certs=sha256_cert,) Modified: python/branches/release27-maint/Lib/test/test_support.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_support.py (original) +++ python/branches/release27-maint/Lib/test/test_support.py Sat Jan 8 11:32:51 2011 @@ -757,6 +757,7 @@ default_errnos = [ ('ECONNREFUSED', 111), ('ECONNRESET', 104), + ('EHOSTUNREACH', 113), ('ENETUNREACH', 101), ('ETIMEDOUT', 110), ] From python-checkins at python.org Sat Jan 8 17:31:25 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 8 Jan 2011 17:31:25 +0100 (CET) Subject: [Python-checkins] r87867 - python/branches/py3k/Misc/NEWS Message-ID: <20110108163125.233A2EE9AC@mail.python.org> Author: victor.stinner Date: Sat Jan 8 17:31:24 2011 New Revision: 87867 Log: Issue #1777412: document the change in the NEWS file Modified: python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 8 17:31:24 2011 @@ -40,6 +40,11 @@ Library ------- +- Issue #1777412: minimum year for time.asctime(), time.ctime() and + time.strftime() is now: 1000 instead of 1900 by default (accept2dyear=0) and + not limited instead of 1900 if accept2dyear=1. With Visual Studio or on + Solaris, the year is limited to the range [1; 9999]. + - Issue #10859: Make ``contextlib.GeneratorContextManager`` officially private by renaming it to ``_GeneratorContextManager``. From python-checkins at python.org Sat Jan 8 17:37:47 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 8 Jan 2011 17:37:47 +0100 (CET) Subject: [Python-checkins] r87868 - python/branches/py3k/Misc/NEWS Message-ID: <20110108163747.46676EEA95@mail.python.org> Author: victor.stinner Date: Sat Jan 8 17:37:47 2011 New Revision: 87868 Log: NEWS: merge #1777412 and #10827 entries Modified: python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 8 17:37:47 2011 @@ -40,11 +40,6 @@ Library ------- -- Issue #1777412: minimum year for time.asctime(), time.ctime() and - time.strftime() is now: 1000 instead of 1900 by default (accept2dyear=0) and - not limited instead of 1900 if accept2dyear=1. With Visual Studio or on - Solaris, the year is limited to the range [1; 9999]. - - Issue #10859: Make ``contextlib.GeneratorContextManager`` officially private by renaming it to ``_GeneratorContextManager``. @@ -60,12 +55,12 @@ without folding whitespace. It now uses the continuation_ws, as it does for continuation lines that it creates itself. -- Issue #10827: Changed the rules for 2-digit years. The time.asctime - function will now format any year when ``time.accept2dyear`` is - false and will accept years >= 1000 otherwise. The year range - accepted by ``time.mktime`` and ``time.strftime`` is still system - dependent, but ``time.mktime`` will now accept full range supported - by the OS. Conversion of 2-digit years to 4-digit is deprecated. +- Issue #1777412, #10827: Changed the rules for 2-digit years. The + time.asctime(), time.ctime() and time.strftime() functions will now format + any year when ``time.accept2dyear`` is False and will accept years >= 1000 + otherwise. ``time.mktime`` and ``time.strftime`` now accept full range + supported by the OS. With Visual Studio or on Solaris, the year is limited to + the range [1; 9999]. Conversion of 2-digit years to 4-digit is deprecated. - Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. From python-checkins at python.org Sat Jan 8 20:57:12 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 08 Jan 2011 20:57:12 +0100 Subject: [Python-checkins] devguide: Remove the unittest discoverability task to a todo. Message-ID: brett.cannon pushed 6e995c8113aa to devguide: http://hg.python.org/devguide/rev/6e995c8113aa changeset: 47:6e995c8113aa user: Brett Cannon date: Sat Jan 08 11:44:09 2011 -0800 summary: Remove the unittest discoverability task to a todo. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -30,7 +30,6 @@ * :ref:`runtests` * Projects to get familiar with the development process * :ref:`coverage` - * `Make all unit tests discoverable by unittest `_ * `Fixing documentation bugs `_ * Projects for once you are comfortable * `Helping triage issues `_ @@ -94,6 +93,10 @@ .. todo:: Think about suggesting going through stagnant issues (rather advanced) +.. todo:: + Could have people help make tests discoverable by unittest, but it requires + some upfront work (e.g., how to handle ResourceDenied) + .. _buildbots: http://python.org/dev/buildbot/ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 8 20:57:14 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 08 Jan 2011 20:57:14 +0100 Subject: [Python-checkins] devguide: Fix a typo found by Eli Bendersky. Message-ID: brett.cannon pushed 5d3526219102 to devguide: http://hg.python.org/devguide/rev/5d3526219102 changeset: 48:5d3526219102 user: Brett Cannon date: Sat Jan 08 11:50:37 2011 -0800 summary: Fix a typo found by Eli Bendersky. files: patch.rst diff --git a/patch.rst b/patch.rst --- a/patch.rst +++ b/patch.rst @@ -108,7 +108,7 @@ Once your patch has reached an acceptable state (and thus considered "accepted"), it will either be committed or rejected. If it is rejected, please do not take it personally! Your work is still appreciated regardless of whether -your patch is committed. Balancing what *does* and *`does not* go into Python +your patch is committed. Balancing what *does* and *does not* go into Python is tricky and we simply cannot accept everyone's contributions. But if your patch is committed it will then go into Python's VCS to be released -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 8 20:57:14 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 08 Jan 2011 20:57:14 +0100 Subject: [Python-checkins] devguide: Tweak the wording on what 'make patchcheck' does. Message-ID: brett.cannon pushed c7e539bf49e8 to devguide: http://hg.python.org/devguide/rev/c7e539bf49e8 changeset: 49:c7e539bf49e8 user: Brett Cannon date: Sat Jan 08 11:53:16 2011 -0800 summary: Tweak the wording on what 'make patchcheck' does. files: patch.rst diff --git a/patch.rst b/patch.rst --- a/patch.rst +++ b/patch.rst @@ -58,8 +58,8 @@ make patchcheck -This will make sure extraneous whitespace has been removed from your patch, -etc. +This will check and/or fix various common things people forget to do for +patches. To create your patch, you should generate a unified diff from your checkout's top-level directory:: -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 8 20:57:15 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 08 Jan 2011 20:57:15 +0100 Subject: [Python-checkins] devguide: Explicitly mention where to run the test suite from. Message-ID: brett.cannon pushed bf097b9526dc to devguide: http://hg.python.org/devguide/rev/bf097b9526dc changeset: 50:bf097b9526dc tag: tip user: Brett Cannon date: Sat Jan 08 11:54:57 2011 -0800 summary: Explicitly mention where to run the test suite from. files: runtests.rst diff --git a/runtests.rst b/runtests.rst --- a/runtests.rst +++ b/runtests.rst @@ -11,7 +11,8 @@ Running ------- -The shortest, simplest way of running the test suite is:: +The shortest, simplest way of running the test suite is the following command +from the root directory of your checkout (after you have built Python):: ./python -m test -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 8 21:14:09 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 08 Jan 2011 21:14:09 +0100 Subject: [Python-checkins] devguide: Add an intro task to help with the docs. Message-ID: brett.cannon pushed c57af2c759cb to devguide: http://hg.python.org/devguide/rev/c57af2c759cb changeset: 51:c57af2c759cb tag: tip user: Brett Cannon date: Sat Jan 08 12:13:59 2011 -0800 summary: Add an intro task to help with the docs. files: docquality.rst index.rst diff --git a/docquality.rst b/docquality.rst new file mode 100644 --- /dev/null +++ b/docquality.rst @@ -0,0 +1,50 @@ +.. _docquality: + +Helping with Documentation +========================== + +Python is known for having good documentation. But maintaining all of it and +keeping a high level of quality takes a lot of effort. Help is always +appreciated with the documentation, and it requires little programming +experience (with or without Python). + +`Documenting Python`_ covers the details of how Python's documentation works. +It includes an explanation of the markup used (although you can figure a lot +out simply by looking at pre-existing documentation) and how to build the +documentation (which allows you to see how your changes will look along with +validating your new markup is correct). + +.. _Documenting Python: http://docs.python.org/py3k/documenting/index.html + + +Helping with issues filed on the issue tracker +---------------------------------------------- + +If you look at `issues assigned to docs at python`_ on the `issue tracker`_, you +will find various documentation problems that need work. Issues vary from +typos, to unclear documentation, to something completely lacking documentation. + +If you decide to tackle a documentation issue, you simply create a patch for +the issue and upload it. If you are worried that someone else might be working +simultaneously on the issue, simply leave a comment on the issue saying you are +going to try and create a patch and roughly how long you think you will take to +do it (this allows others to take on the issue if you happen to forget or lose +interest). + +.. _issue tracker: http://bugs.python.org +.. _issues assigned to docs at python: http://bugs.python.org/issue?%40search_text=&ignore=file%3Acontent&title=&%40columns=title&id=&%40columns=id&stage=&creation=&creator=&activity=&%40columns=activity&%40sort=activity&actor=&nosy=&type=&components=&versions=&dependencies=&assignee=docs%40python&keywords=&priority=&%40group=priority&status=1&%40columns=status&resolution=&nosy_count=&message_count=&%40pagesize=50&%40startwith=0&%40action=search + + +Proofreading +------------ + +While an issue filed on the `issue tracker`_ means there is a known issue +somewhere, that does not mean there are not other issues lurking about in the +documentation. Simply proofreading parts of the documentation are enough to +uncover problems (e.g., documentation that needs to be updated for Python 3 +from Python 2). + +If you decide to proofread, then read a section of the documentation from start +to finish, filing issues in the issue tracker for each problem you find. Don't +file a single issue for an entire section containing multiple problems as that +makes it harder to break the work up for multiple people to help with. diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -8,6 +8,7 @@ patch runtests coverage + docquality .. todolist:: @@ -30,7 +31,7 @@ * :ref:`runtests` * Projects to get familiar with the development process * :ref:`coverage` - * `Fixing documentation bugs `_ + * :ref:`docquality` * Projects for once you are comfortable * `Helping triage issues `_ * `Fixing issues considered "easy" `_ (and beyond) -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 8 21:47:22 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Sat, 8 Jan 2011 21:47:22 +0100 (CET) Subject: [Python-checkins] r87869 - in python/branches/py3k/Doc/library: datetime.rst time.rst Message-ID: <20110108204722.20D00EE9A4@mail.python.org> Author: alexander.belopolsky Date: Sat Jan 8 21:47:21 2011 New Revision: 87869 Log: Fixed documentation to reflect recent changes for years < 1900. Modified: python/branches/py3k/Doc/library/datetime.rst python/branches/py3k/Doc/library/time.rst Modified: python/branches/py3k/Doc/library/datetime.rst ============================================================================== --- python/branches/py3k/Doc/library/datetime.rst (original) +++ python/branches/py3k/Doc/library/datetime.rst Sat Jan 8 21:47:21 2011 @@ -1661,8 +1661,12 @@ implementation. Note that the 1999 version of the C standard added additional format codes. -The exact range of years for which :meth:`strftime` works also varies across -platforms. Regardless of platform, years before 1900 cannot be used. +The exact range of years for which :meth:`strftime` works also varies +across platforms. Regardless of platform, years before 1000 cannot be +used with ``datetime`` module ``strftime()`` methods. The ``time`` +module ``strftime()`` function exibit different behavior depending on +the value of ``time.accept2dyear`` variable. See :ref:`Year 2000 +(Y2K) issues ` for details. +-----------+--------------------------------+-------+ | Directive | Meaning | Notes | Modified: python/branches/py3k/Doc/library/time.rst ============================================================================== --- python/branches/py3k/Doc/library/time.rst (original) +++ python/branches/py3k/Doc/library/time.rst Sat Jan 8 21:47:21 2011 @@ -120,10 +120,19 @@ .. data:: accept2dyear - Boolean value indicating whether two-digit year values will be accepted. This - is true by default, but will be set to false if the environment variable - :envvar:`PYTHONY2K` has been set to a non-empty string. It may also be modified - at run time. + Boolean value indicating whether two-digit year values will be + mapped to 1969--2068 range by :func:`asctime`, :func:`mktime`, and + :func:`strftime` functions. This is true by default, but will be + set to false if the environment variable :envvar:`PYTHONY2K` has + been set to a non-empty string. It may also be modified at run + time. + + .. deprecated:: 3.2 + Mapping of 2-digit year values by :func:`asctime`, + :func:`mktime`, and :func:`strftime` functions to 1969--2068 + range is deprecated. Programs that need to process 2-digit + years should use ``%y`` code available in :func:`strptime` + function or convert 2-digit year values to 4-digit themselves. .. data:: altzone From python-checkins at python.org Sat Jan 8 22:04:25 2011 From: python-checkins at python.org (georg.brandl) Date: Sat, 8 Jan 2011 22:04:25 +0100 (CET) Subject: [Python-checkins] r87870 - python/branches/py3k/Doc/library/zlib.rst Message-ID: <20110108210425.DE9CBEE9CD@mail.python.org> Author: georg.brandl Date: Sat Jan 8 22:04:25 2011 New Revision: 87870 Log: zlib only works with bytes objects. Modified: python/branches/py3k/Doc/library/zlib.rst Modified: python/branches/py3k/Doc/library/zlib.rst ============================================================================== --- python/branches/py3k/Doc/library/zlib.rst (original) +++ python/branches/py3k/Doc/library/zlib.rst Sat Jan 8 22:04:25 2011 @@ -51,9 +51,9 @@ regardless of sign. -.. function:: compress(string[, level]) +.. function:: compress(data[, level]) - Compresses the data in *string*, returning a string contained compressed data. + Compresses the bytes in *data*, returning a bytes object containing compressed data. *level* is an integer from ``1`` to ``9`` controlling the level of compression; ``1`` is fastest and produces the least compression, ``9`` is slowest and produces the most. The default value is ``6``. Raises the :exc:`error` @@ -92,9 +92,9 @@ regardless of sign. -.. function:: decompress(string[, wbits[, bufsize]]) +.. function:: decompress(data[, wbits[, bufsize]]) - Decompresses the data in *string*, returning a string containing the + Decompresses the bytes in *data*, returning a bytes object containing the uncompressed data. The *wbits* parameter controls the size of the window buffer, and is discussed further below. If *bufsize* is given, it is used as the initial size of the output @@ -125,21 +125,21 @@ Compression objects support the following methods: -.. method:: Compress.compress(string) +.. method:: Compress.compress(data) - Compress *string*, returning a string containing compressed data for at least - part of the data in *string*. This data should be concatenated to the output + Compress *data*, returning a bytes object containing compressed data for at least + part of the data in *data*. This data should be concatenated to the output produced by any preceding calls to the :meth:`compress` method. Some input may be kept in internal buffers for later processing. .. method:: Compress.flush([mode]) - All pending input is processed, and a string containing the remaining compressed + All pending input is processed, and a bytes object containing the remaining compressed output is returned. *mode* can be selected from the constants :const:`Z_SYNC_FLUSH`, :const:`Z_FULL_FLUSH`, or :const:`Z_FINISH`, defaulting to :const:`Z_FINISH`. :const:`Z_SYNC_FLUSH` and - :const:`Z_FULL_FLUSH` allow compressing further strings of data, while + :const:`Z_FULL_FLUSH` allow compressing further bytestrings of data, while :const:`Z_FINISH` finishes the compressed stream and prevents compressing any more data. After calling :meth:`flush` with *mode* set to :const:`Z_FINISH`, the :meth:`compress` method cannot be called again; the only realistic action is @@ -157,31 +157,31 @@ .. attribute:: Decompress.unused_data - A string which contains any bytes past the end of the compressed data. That is, + A bytes object which contains any bytes past the end of the compressed data. That is, this remains ``""`` until the last byte that contains compression data is - available. If the whole string turned out to contain compressed data, this is - ``""``, the empty string. + available. If the whole bytestring turned out to contain compressed data, this is + ``b""``, an empty bytes object. - The only way to determine where a string of compressed data ends is by actually + The only way to determine where a bytestring of compressed data ends is by actually decompressing it. This means that when compressed data is contained part of a larger file, you can only find the end of it by reading data and feeding it - followed by some non-empty string into a decompression object's + followed by some non-empty bytestring into a decompression object's :meth:`decompress` method until the :attr:`unused_data` attribute is no longer - the empty string. + empty. .. attribute:: Decompress.unconsumed_tail - A string that contains any data that was not consumed by the last + A bytes object that contains any data that was not consumed by the last :meth:`decompress` call because it exceeded the limit for the uncompressed data buffer. This data has not yet been seen by the zlib machinery, so you must feed it (possibly with further data concatenated to it) back to a subsequent :meth:`decompress` method call in order to get correct output. -.. method:: Decompress.decompress(string[, max_length]) +.. method:: Decompress.decompress(data[, max_length]) - Decompress *string*, returning a string containing the uncompressed data + Decompress *data*, returning a bytes object containing the uncompressed data corresponding to at least part of the data in *string*. This data should be concatenated to the output produced by any preceding calls to the :meth:`decompress` method. Some of the input data may be preserved in internal @@ -190,15 +190,15 @@ If the optional parameter *max_length* is supplied then the return value will be no longer than *max_length*. This may mean that not all of the compressed input can be processed; and unconsumed data will be stored in the attribute - :attr:`unconsumed_tail`. This string must be passed to a subsequent call to + :attr:`unconsumed_tail`. This bytestring must be passed to a subsequent call to :meth:`decompress` if decompression is to continue. If *max_length* is not - supplied then the whole input is decompressed, and :attr:`unconsumed_tail` is an - empty string. + supplied then the whole input is decompressed, and :attr:`unconsumed_tail` is + empty. .. method:: Decompress.flush([length]) - All pending input is processed, and a string containing the remaining + All pending input is processed, and a bytes object containing the remaining uncompressed output is returned. After calling :meth:`flush`, the :meth:`decompress` method cannot be called again; the only realistic action is to delete the object. From python-checkins at python.org Sat Jan 8 23:05:05 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 08 Jan 2011 23:05:05 +0100 Subject: [Python-checkins] devguide: Clarify when python.exe is used on OS X. Message-ID: brett.cannon pushed 6ce8d65a13e5 to devguide: http://hg.python.org/devguide/rev/6ce8d65a13e5 changeset: 52:6ce8d65a13e5 user: Brett Cannon date: Sat Jan 08 12:38:50 2011 -0800 summary: Clarify when python.exe is used on OS X. files: setup.rst diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -113,9 +113,9 @@ passed into the ``-j`` flag to match the number of cores you have. Once Python is done building you will then have a working build of Python -that can be run in-place; ``./python`` on most machines, ``./python.exe`` -on OS X (all examples throughout this documentation say ``./python`` but -implies you choose the proper name based on your OS). +that can be run in-place; ``./python`` on most machines (and what is used in +all examples), ``./python.exe`` on OS X (when on a case-insensitive filesystem, +which is the default). Windows -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 8 23:05:06 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 08 Jan 2011 23:05:06 +0100 Subject: [Python-checkins] devguide: Add an intermediate task of helping triage issues (not to be confused with the Message-ID: brett.cannon pushed fb5fbe8f921a to devguide: http://hg.python.org/devguide/rev/fb5fbe8f921a changeset: 53:fb5fbe8f921a tag: tip user: Brett Cannon date: Sat Jan 08 14:04:58 2011 -0800 summary: Add an intermediate task of helping triage issues (not to be confused with the advanced task of doing the actual triage). files: helptriage.rst index.rst diff --git a/helptriage.rst b/helptriage.rst new file mode 100644 --- /dev/null +++ b/helptriage.rst @@ -0,0 +1,55 @@ +.. _helptriage: + +Helping Triage Issues +===================== + +Once you know your way a little bit around how Python's source files are +structured and you are comfortable working with patches, a great way to +participate is to help triage issues. + +On a daily basis, issues get reported on the `issue tracker`_. Each and every +issue needs to be triaged to make sure various things are in proper order. Even +without special privileges you can help with this process. + + +Bugs +---- + +For bugs, an issue needs to: + +* Clearly explain the bug so it can be reproduced +* All relevant platform details are included +* What version(s) of Python are affected by the bug are fully known +* Is there a proper unit test that can reproduce the bug? + +These are things anyone can help with. For instance, if a bug is not clearly +explained enough for you to reproduce it then there is a good chance a core +developer won't be able to either. And it is always helpful to know if a bug +not only affects the in-development version of Python, but whether it also +affects other versions in maintenance mode. And if the bug lacks a unit test +that should end up in Python's test suite, having that written can be very +helpful. + +This is all helpful as it allows triagers to properly classify an issue so it +can be handled by the right people in a timely fashion. + + +Patches +------- + +If an issue has a patch attached that has not been reviewed, you can help by +making sure the patch: + +* Follows the style guides +* Applies cleanly to an up-to-date checkout +* Is a good solution to the problem it is trying to solve +* There are proper tests +* The proper documentation changes are included +* The person is listed in ``Misc/ACKS``, either already or the patches add them + +Doing all of this allows core developers and triagers to more quickly look for +subtle issues that only people with extensive experience working on Python's +code base will notice. + + +.. _issue tracker: http://bugs.python.org diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -9,6 +9,7 @@ runtests coverage docquality + helptriage .. todolist:: @@ -33,7 +34,7 @@ * :ref:`coverage` * :ref:`docquality` * Projects for once you are comfortable - * `Helping triage issues `_ + * :ref:`helptriage` * `Fixing issues considered "easy" `_ (and beyond) * `Fix all warnings raised when running the test suite w/ -uall `_ * Watching the buildbots_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 8 23:24:07 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 08 Jan 2011 23:24:07 +0100 Subject: [Python-checkins] devguide: Clarify some things about how to find out what modules need some coverage help. Message-ID: brett.cannon pushed 0ed7176efa98 to devguide: http://hg.python.org/devguide/rev/0ed7176efa98 changeset: 54:0ed7176efa98 tag: tip user: Brett Cannon date: Sat Jan 08 14:23:58 2011 -0800 summary: Clarify some things about how to find out what modules need some coverage help. files: coverage.rst diff --git a/coverage.rst b/coverage.rst --- a/coverage.rst +++ b/coverage.rst @@ -23,12 +23,17 @@ overall view of how good coverage is for various modules (you will want to focus on those in the ``Lib`` directory as those are the pure Python modules from Python's stdlib, and thus easier to work with than the C extension -modules). Another is to follow the examples below and simply see what kind of +modules). But since this is a third-party site we cannot promise that it will +always be accessible or have useful information (i.e., be working properly). + +Another is to follow the examples below and simply see what kind of coverage your favorite module has. This is "stabbing in the dark", though, and -so it might take some time to find a module that needs coverage help. Finally, -you can simply run the test suite yourself with coverage turned on and see what -modules need help. This has the drawback as the test suite takes some time to -complete when run under coverage measuring. +so it might take some time to find a module that needs coverage help. + +Finally, you can simply run the entire test suite yourself with coverage turned +on and see what modules need help. This has the drawback as the test suite +takes some time to complete when run under coverage measuring, but you will +have an accurate, up-to-date notion of what modules need the most work. Using coverage.py -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 8 23:59:58 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 08 Jan 2011 23:59:58 +0100 Subject: [Python-checkins] devguide: Link to 'issues with patches' link. Message-ID: brett.cannon pushed 3a6213ef9865 to devguide: http://hg.python.org/devguide/rev/3a6213ef9865 changeset: 55:3a6213ef9865 user: Brett Cannon date: Sat Jan 08 14:58:45 2011 -0800 summary: Link to 'issues with patches' link. files: helptriage.rst diff --git a/helptriage.rst b/helptriage.rst --- a/helptriage.rst +++ b/helptriage.rst @@ -51,5 +51,10 @@ subtle issues that only people with extensive experience working on Python's code base will notice. +There is a complete list of `open issues with patches`_, although to make sure +that someone has not already done the checklist above as it is possible the +issue is still open for reasons other than needing help being triaged. + .. _issue tracker: http://bugs.python.org +.. _open issues with patches: http://bugs.python.org/issue?status=1&@sort=-activity&@columns=id,activity,title,creator,status&@dispname=Issues%20with%20patch&@startwith=0&@group=priority&@filter=&keywords=2&@action=search&@pagesize=50 -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Jan 9 00:00:00 2011 From: python-checkins at python.org (brett.cannon) Date: Sun, 09 Jan 2011 00:00:00 +0100 Subject: [Python-checkins] devguide: Intermediate task of looking for bugs needing a patch. Message-ID: brett.cannon pushed 34afdff0c1c0 to devguide: http://hg.python.org/devguide/rev/34afdff0c1c0 changeset: 56:34afdff0c1c0 tag: tip user: Brett Cannon date: Sat Jan 08 14:59:09 2011 -0800 summary: Intermediate task of looking for bugs needing a patch. files: fixingissues.rst index.rst diff --git a/fixingissues.rst b/fixingissues.rst new file mode 100644 --- /dev/null +++ b/fixingissues.rst @@ -0,0 +1,23 @@ +.. _fixingissues: + +Fixing "easy" Issues (and Beyond) +================================= + +When you feel comfortable enough to want to help tackle issues by trying to +create a patch to fix an issue, you can start by looking at the `"easy" +issues`_. These issues *should* be ones where it should take no longer than a day +or weekend to fix. But because the "easy" classification is typically done at +triage time it can turn out to be inaccurate, so do feel free to leave a +comment if you think the classification no longer applies. + +For the truly adventurous looking for a challenge, you can look for issues that +are not considered easy and try to fix those. It must be warned, though, that +it is quite possible that a bug that has been left open has been left into that +state because of the difficulty compared to the benefit of the fix. It could +also still be open because no consensus has been reached on how to fix the +issue (although having a patch the proposes a fix can turn the tides of the +discussion to help bring it to a close). Regardless of why the issue is open, +you can also always provide useful comments if you do attempt a fix, successful +or not. + +.. _"easy" issues: http://bugs.python.org/issue?status=1&@sort=-activity&@dispname=Easy%20issues&@startwith=0&@filter=&@group=priority&@columns=id,activity,title,creator,status&keywords=6&@action=search&@pagesize=50 diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -10,6 +10,7 @@ coverage docquality helptriage + fixingissues .. todolist:: @@ -35,9 +36,9 @@ * :ref:`docquality` * Projects for once you are comfortable * :ref:`helptriage` - * `Fixing issues considered "easy" `_ (and beyond) + * :ref:`fixingissues` * `Fix all warnings raised when running the test suite w/ -uall `_ - * Watching the buildbots_ + * Fixing issues found by the buildbots_ * `Gaining 'Developer' privileges for the issue tracker `_ * `Triaging issues `_ * `Reviewing patches `_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Jan 9 00:15:38 2011 From: python-checkins at python.org (brett.cannon) Date: Sun, 09 Jan 2011 00:15:38 +0100 Subject: [Python-checkins] devguide: Tweak the list to have beginner/intermediate/advanced tasks breakdown. Message-ID: brett.cannon pushed 380f91eb73a8 to devguide: http://hg.python.org/devguide/rev/380f91eb73a8 changeset: 57:380f91eb73a8 tag: tip user: Brett Cannon date: Sat Jan 08 15:15:33 2011 -0800 summary: Tweak the list to have beginner/intermediate/advanced tasks breakdown. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -11,6 +11,7 @@ docquality helptriage fixingissues + silencewarnings .. todolist:: @@ -31,14 +32,15 @@ * `PEP 8`_ * :ref:`patch` * :ref:`runtests` -* Projects to get familiar with the development process +* Beginner tasks to become familiar with the development process * :ref:`coverage` * :ref:`docquality` -* Projects for once you are comfortable +* Intermediate tasks for once you are comfortable * :ref:`helptriage` +* Advanced tasks + * Fixing issues found by the buildbots_ + * :ref:`silencewarnings` * :ref:`fixingissues` - * `Fix all warnings raised when running the test suite w/ -uall `_ - * Fixing issues found by the buildbots_ * `Gaining 'Developer' privileges for the issue tracker `_ * `Triaging issues `_ * `Reviewing patches `_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Jan 9 00:24:43 2011 From: python-checkins at python.org (brett.cannon) Date: Sun, 09 Jan 2011 00:24:43 +0100 Subject: [Python-checkins] devguide: Re-order tasks. Message-ID: brett.cannon pushed a36c7bd36438 to devguide: http://hg.python.org/devguide/rev/a36c7bd36438 changeset: 58:a36c7bd36438 user: Brett Cannon date: Sat Jan 08 15:24:28 2011 -0800 summary: Re-order tasks. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -37,14 +37,14 @@ * :ref:`docquality` * Intermediate tasks for once you are comfortable * :ref:`helptriage` +* `Gaining 'Developer' privileges for the issue tracker `_ + * `Triaging issues `_ + * `Reviewing patches `_ +* `Following Python's development `_ * Advanced tasks * Fixing issues found by the buildbots_ * :ref:`silencewarnings` * :ref:`fixingissues` -* `Gaining 'Developer' privileges for the issue tracker `_ - * `Triaging issues `_ - * `Reviewing patches `_ -* `Following Python's development `_ * `Gaining commit privileges `_ * `Committing patches `_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Jan 9 00:24:44 2011 From: python-checkins at python.org (brett.cannon) Date: Sun, 09 Jan 2011 00:24:44 +0100 Subject: [Python-checkins] devguide: Silence warnings as an advanced task. Message-ID: brett.cannon pushed 06153bf9044e to devguide: http://hg.python.org/devguide/rev/06153bf9044e changeset: 59:06153bf9044e tag: tip user: Brett Cannon date: Sat Jan 08 15:24:37 2011 -0800 summary: Silence warnings as an advanced task. files: silencewarnings.rst diff --git a/silencewarnings.rst b/silencewarnings.rst new file mode 100644 --- /dev/null +++ b/silencewarnings.rst @@ -0,0 +1,19 @@ +.. _silencewarnings: + +Silence Warnings From the Test Suite +==================================== + +When running Python's test suite, no warnings should result:: + + ./python -m -W error test -uall + +Unfortunately new warnings are added to Python on occasion which take some time +to eliminate (e.g., ``ResourceWarning``). Typically the easy warnings are dealt +with quickly, but the more difficult ones that require some thought and work do +not get fixed immediately. + +If you decide to tackle a warning you have found, open an issue on the `issue +tracker`_ (if one has not already been opened) and say you are going to try and +tackle the issue, and then proceed to fix the issue. + +.. _issue tracker: http://bugs.python.org -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Jan 9 00:44:37 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 9 Jan 2011 00:44:37 +0100 (CET) Subject: [Python-checkins] r87871 - python/branches/py3k/Doc/glossary.rst Message-ID: <20110108234437.7C0DBEE997@mail.python.org> Author: raymond.hettinger Date: Sun Jan 9 00:44:37 2011 New Revision: 87871 Log: Issue #10357: Clarify what it means to be a mapping. Modified: python/branches/py3k/Doc/glossary.rst Modified: python/branches/py3k/Doc/glossary.rst ============================================================================== --- python/branches/py3k/Doc/glossary.rst (original) +++ python/branches/py3k/Doc/glossary.rst Sun Jan 9 00:44:37 2011 @@ -428,9 +428,11 @@ :class:`importlib.abc.Loader` for an :term:`abstract base class`. mapping - A container object (such as :class:`dict`) which supports arbitrary key - lookups using the special method :meth:`__getitem__`. Mappings also - support :meth:`__len__`, :meth:`__iter__`, and :meth:`__contains__`. + A container object that supports arbitrary key lookups and implements the + methods specified in the :class:`Mapping` or :class:`MutableMapping` + :ref:`abstract base classes `. Examples include + :class:`dict`, :class:`collections.defaultdict`, + :class:`collections.OrderedDict` and :class:`collections.Counter`. metaclass The class of a class. Class definitions create a class name, a class From python-checkins at python.org Sun Jan 9 00:50:39 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 9 Jan 2011 00:50:39 +0100 (CET) Subject: [Python-checkins] r87872 - python/branches/release27-maint/Doc/glossary.rst Message-ID: <20110108235039.2C25BEE999@mail.python.org> Author: raymond.hettinger Date: Sun Jan 9 00:50:39 2011 New Revision: 87872 Log: Issue 10357: Clarify what it means to be a mapping. Modified: python/branches/release27-maint/Doc/glossary.rst Modified: python/branches/release27-maint/Doc/glossary.rst ============================================================================== --- python/branches/release27-maint/Doc/glossary.rst (original) +++ python/branches/release27-maint/Doc/glossary.rst Sun Jan 9 00:50:39 2011 @@ -442,9 +442,11 @@ :term:`finder`. See :pep:`302` for details. mapping - A container object (such as :class:`dict`) which supports arbitrary key - lookups using the special method :meth:`__getitem__`. Mappings also - support :meth:`__len__`, :meth:`__iter__`, and :meth:`__contains__`. + A container object that supports arbitrary key lookups and implements the + methods specified in the :class:`Mapping` or :class:`MutableMapping` + :ref:`abstract base classes `. Examples include + :class:`dict`, :class:`collections.defaultdict`, + :class:`collections.OrderedDict` and :class:`collections.Counter`. metaclass The class of a class. Class definitions create a class name, a class From python-checkins at python.org Sun Jan 9 03:35:24 2011 From: python-checkins at python.org (r.david.murray) Date: Sun, 9 Jan 2011 03:35:24 +0100 (CET) Subject: [Python-checkins] r87873 - in python/branches/py3k: Lib/email/header.py Lib/email/test/test_email.py Misc/NEWS Message-ID: <20110109023524.6D2FCEE98A@mail.python.org> Author: r.david.murray Date: Sun Jan 9 03:35:24 2011 New Revision: 87873 Log: #5871: protect against header injection attacks. This makes Header.encode throw a HeaderParseError if it winds up formatting a header such that a continuation line has no leading whitespace and looks like a header. Since Header accepts values containing newlines and preserves them (and this is by design), without this fix any program that took user input (say, a subject in a web form) and passed it to the email package as a header was vulnerable to header injection attacks. (As far as we know this has never been exploited.) Thanks to Jakub Wilk for reporting this vulnerability. Modified: python/branches/py3k/Lib/email/header.py python/branches/py3k/Lib/email/test/test_email.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/email/header.py ============================================================================== --- python/branches/py3k/Lib/email/header.py (original) +++ python/branches/py3k/Lib/email/header.py Sun Jan 9 03:35:24 2011 @@ -47,6 +47,10 @@ # For use with .match() fcre = re.compile(r'[\041-\176]+:$') +# Find a header embeded in a putative header value. Used to check for +# header injection attack. +_embeded_header = re.compile(r'\n[^ \t]+:') + # Helpers @@ -320,7 +324,11 @@ if len(lines) > 1: formatter.newline() formatter.add_transition() - return formatter._str(linesep) + value = formatter._str(linesep) + if _embeded_header.search(value): + raise HeaderParseError("header value appears to contain " + "an embedded header: {!r}".format(value)) + return value def _normalize(self): # Step 1: Normalize the chunks so that all runs of identical charsets Modified: python/branches/py3k/Lib/email/test/test_email.py ============================================================================== --- python/branches/py3k/Lib/email/test/test_email.py (original) +++ python/branches/py3k/Lib/email/test/test_email.py Sun Jan 9 03:35:24 2011 @@ -561,6 +561,18 @@ "attachment; filename*=utf-8''Fu%C3%9Fballer%20%5Bfilename%5D.ppt", msg['Content-Disposition']) + # Issue 5871: reject an attempt to embed a header inside a header value + # (header injection attack). + def test_embeded_header_via_Header_rejected(self): + msg = Message() + msg['Dummy'] = Header('dummy\nX-Injected-Header: test') + self.assertRaises(errors.HeaderParseError, msg.as_string) + + def test_embeded_header_via_string_rejected(self): + msg = Message() + msg['Dummy'] = 'dummy\nX-Injected-Header: test' + self.assertRaises(errors.HeaderParseError, msg.as_string) + # Test the email.encoders module class TestEncoders(unittest.TestCase): Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sun Jan 9 03:35:24 2011 @@ -40,6 +40,13 @@ Library ------- +- Issue #5871: email.header.Header.encode now raises an error if any + continuation line in the formatted value has no leading white space + and looks like a header. Since Generator uses Header to format all + headers, this check is made for all headers in any serialized message + at serialization time. This provides protection against header + injection attacks. + - Issue #10859: Make ``contextlib.GeneratorContextManager`` officially private by renaming it to ``_GeneratorContextManager``. From python-checkins at python.org Sun Jan 9 03:48:04 2011 From: python-checkins at python.org (r.david.murray) Date: Sun, 9 Jan 2011 03:48:04 +0100 (CET) Subject: [Python-checkins] r87874 - in python/branches/release31-maint: Lib/email/header.py Lib/email/test/test_email.py Misc/NEWS Message-ID: <20110109024804.66853EE98A@mail.python.org> Author: r.david.murray Date: Sun Jan 9 03:48:04 2011 New Revision: 87874 Log: Merged revisions 87873 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87873 | r.david.murray | 2011-01-08 21:35:24 -0500 (Sat, 08 Jan 2011) | 12 lines #5871: protect against header injection attacks. This makes Header.encode throw a HeaderParseError if it winds up formatting a header such that a continuation line has no leading whitespace and looks like a header. Since Header accepts values containing newlines and preserves them (and this is by design), without this fix any program that took user input (say, a subject in a web form) and passed it to the email package as a header was vulnerable to header injection attacks. (As far as we know this has never been exploited.) Thanks to Jakub Wilk for reporting this vulnerability. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/email/header.py python/branches/release31-maint/Lib/email/test/test_email.py python/branches/release31-maint/Misc/NEWS Modified: python/branches/release31-maint/Lib/email/header.py ============================================================================== --- python/branches/release31-maint/Lib/email/header.py (original) +++ python/branches/release31-maint/Lib/email/header.py Sun Jan 9 03:48:04 2011 @@ -46,6 +46,10 @@ # For use with .match() fcre = re.compile(r'[\041-\176]+:$') +# Find a header embeded in a putative header value. Used to check for +# header injection attack. +_embeded_header = re.compile(r'\n[^ \t]+:') + # Helpers @@ -305,7 +309,11 @@ if len(lines) > 1: formatter.newline() formatter.add_transition() - return str(formatter) + value = str(formatter) + if _embeded_header.search(value): + raise HeaderParseError("header value appears to contain " + "an embedded header: {!r}".format(value)) + return value def _normalize(self): # Step 1: Normalize the chunks so that all runs of identical charsets Modified: python/branches/release31-maint/Lib/email/test/test_email.py ============================================================================== --- python/branches/release31-maint/Lib/email/test/test_email.py (original) +++ python/branches/release31-maint/Lib/email/test/test_email.py Sun Jan 9 03:48:04 2011 @@ -540,6 +540,19 @@ msg['Content-Disposition']) + # Issue 5871: reject an attempt to embed a header inside a header value + # (header injection attack). + def test_embeded_header_via_Header_rejected(self): + msg = Message() + msg['Dummy'] = Header('dummy\nX-Injected-Header: test') + self.assertRaises(errors.HeaderParseError, msg.as_string) + + def test_embeded_header_via_string_rejected(self): + msg = Message() + msg['Dummy'] = 'dummy\nX-Injected-Header: test' + self.assertRaises(errors.HeaderParseError, msg.as_string) + + # Test the email.encoders module class TestEncoders(unittest.TestCase): def test_encode_empty_payload(self): Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Sun Jan 9 03:48:04 2011 @@ -31,6 +31,13 @@ Library ------- +- Issue #5871: email.header.Header.encode now raises an error if any + continuation line in the formatted value has no leading white space + and looks like a header. Since Generator uses Header to format all + headers, this check is made for all headers in any serialized message + at serialization time. This provides protection against header + injection attacks. + - Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. From python-checkins at python.org Sun Jan 9 04:02:04 2011 From: python-checkins at python.org (r.david.murray) Date: Sun, 9 Jan 2011 04:02:04 +0100 (CET) Subject: [Python-checkins] r87875 - in python/branches/release27-maint: Lib/email/header.py Lib/email/test/test_email.py Misc/NEWS Message-ID: <20110109030204.44C60EE98A@mail.python.org> Author: r.david.murray Date: Sun Jan 9 04:02:04 2011 New Revision: 87875 Log: Merged revisions 87873 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87873 | r.david.murray | 2011-01-08 21:35:24 -0500 (Sat, 08 Jan 2011) | 12 lines #5871: protect against header injection attacks. This makes Header.encode throw a HeaderParseError if it winds up formatting a header such that a continuation line has no leading whitespace and looks like a header. Since Header accepts values containing newlines and preserves them (and this is by design), without this fix any program that took user input (say, a subject in a web form) and passed it to the email package as a header was vulnerable to header injection attacks. (As far as we know this has never been exploited.) Thanks to Jakub Wilk for reporting this vulnerability. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/email/header.py python/branches/release27-maint/Lib/email/test/test_email.py python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Lib/email/header.py ============================================================================== --- python/branches/release27-maint/Lib/email/header.py (original) +++ python/branches/release27-maint/Lib/email/header.py Sun Jan 9 04:02:04 2011 @@ -47,6 +47,10 @@ # For use with .match() fcre = re.compile(r'[\041-\176]+:$') +# Find a header embeded in a putative header value. Used to check for +# header injection attack. +_embeded_header = re.compile(r'\n[^ \t]+:') + # Helpers @@ -403,7 +407,11 @@ newchunks += self._split(s, charset, targetlen, splitchars) lastchunk, lastcharset = newchunks[-1] lastlen = lastcharset.encoded_header_len(lastchunk) - return self._encode_chunks(newchunks, maxlinelen) + value = self._encode_chunks(newchunks, maxlinelen) + if _embeded_header.search(value): + raise HeaderParseError("header value appears to contain " + "an embedded header: {!r}".format(value)) + return value Modified: python/branches/release27-maint/Lib/email/test/test_email.py ============================================================================== --- python/branches/release27-maint/Lib/email/test/test_email.py (original) +++ python/branches/release27-maint/Lib/email/test/test_email.py Sun Jan 9 04:02:04 2011 @@ -553,6 +553,17 @@ msg.set_charset(u'us-ascii') self.assertEqual('us-ascii', msg.get_content_charset()) + # Issue 5871: reject an attempt to embed a header inside a header value + # (header injection attack). + def test_embeded_header_via_Header_rejected(self): + msg = Message() + msg['Dummy'] = Header('dummy\nX-Injected-Header: test') + self.assertRaises(Errors.HeaderParseError, msg.as_string) + + def test_embeded_header_via_string_rejected(self): + msg = Message() + msg['Dummy'] = 'dummy\nX-Injected-Header: test' + self.assertRaises(Errors.HeaderParseError, msg.as_string) # Test the email.Encoders module Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Sun Jan 9 04:02:04 2011 @@ -36,6 +36,13 @@ dependent, but ``time.mktime`` will now accept full range supported by the OS. Conversion of 2-digit years to 4-digit is deprecated. +- Issue #10827: Changed the rules for 2-digit years. The time.asctime + function will now format any year when ``time.accept2dyear`` is + false and will accept years >= 1000 otherwise. The year range + accepted by ``time.mktime`` and ``time.strftime`` is still system + dependent, but ``time.mktime`` will now accept full range supported + by the OS. Conversion of 2-digit years to 4-digit is deprecated. + - Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. From solipsis at pitrou.net Sun Jan 9 05:05:23 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 09 Jan 2011 05:05:23 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r87871): sum=0 Message-ID: py3k results for svn r87871 (hg cset 87d1871a77c7) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflogOrKkHI', '-x'] From python-checkins at python.org Sun Jan 9 08:38:52 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 08:38:52 +0100 (CET) Subject: [Python-checkins] r87876 - in python/branches/py3k: Doc/library/ast.rst Lib/ast.py Lib/test/test_ast.py Misc/ACKS Misc/NEWS Message-ID: <20110109073852.1AB02EE996@mail.python.org> Author: georg.brandl Date: Sun Jan 9 08:38:51 2011 New Revision: 87876 Log: #10869: do not visit root node twice in ast.increment_lineno(). Modified: python/branches/py3k/Doc/library/ast.rst python/branches/py3k/Lib/ast.py python/branches/py3k/Lib/test/test_ast.py python/branches/py3k/Misc/ACKS python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Doc/library/ast.rst ============================================================================== --- python/branches/py3k/Doc/library/ast.rst (original) +++ python/branches/py3k/Doc/library/ast.rst Sun Jan 9 08:38:51 2011 @@ -173,9 +173,9 @@ .. function:: walk(node) - Recursively yield all child nodes of *node*, in no specified order. This is - useful if you only want to modify nodes in place and don't care about the - context. + Recursively yield all descendant nodes in the tree starting at *node* + (including *node* itself), in no specified order. This is useful if you only + want to modify nodes in place and don't care about the context. .. class:: NodeVisitor() Modified: python/branches/py3k/Lib/ast.py ============================================================================== --- python/branches/py3k/Lib/ast.py (original) +++ python/branches/py3k/Lib/ast.py Sun Jan 9 08:38:51 2011 @@ -159,8 +159,6 @@ Increment the line number of each node in the tree starting at *node* by *n*. This is useful to "move code" to a different location in a file. """ - if 'lineno' in node._attributes: - node.lineno = getattr(node, 'lineno', 0) + n for child in walk(node): if 'lineno' in child._attributes: child.lineno = getattr(child, 'lineno', 0) + n @@ -211,9 +209,9 @@ def walk(node): """ - Recursively yield all child nodes of *node*, in no specified order. This is - useful if you only want to modify nodes in place and don't care about the - context. + Recursively yield all descendant nodes in the tree starting at *node* + (including *node* itself), in no specified order. This is useful if you + only want to modify nodes in place and don't care about the context. """ from collections import deque todo = deque([node]) Modified: python/branches/py3k/Lib/test/test_ast.py ============================================================================== --- python/branches/py3k/Lib/test/test_ast.py (original) +++ python/branches/py3k/Lib/test/test_ast.py Sun Jan 9 08:38:51 2011 @@ -264,6 +264,13 @@ 'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, ' 'col_offset=0))' ) + # issue10869: do not increment lineno of root twice + self.assertEqual(ast.increment_lineno(src.body, n=3), src.body) + self.assertEqual(ast.dump(src, include_attributes=True), + 'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), ' + 'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, ' + 'col_offset=0))' + ) def test_iter_fields(self): node = ast.parse('foo()', mode='eval') Modified: python/branches/py3k/Misc/ACKS ============================================================================== --- python/branches/py3k/Misc/ACKS (original) +++ python/branches/py3k/Misc/ACKS Sun Jan 9 08:38:51 2011 @@ -905,6 +905,7 @@ Rickard Westman Jeff Wheeler Christopher White +David White Mats Wichmann Truida Wiedijk Felix Wiemann Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sun Jan 9 08:38:51 2011 @@ -40,6 +40,9 @@ Library ------- +- Issue #10869: Fixed bug where ast.increment_lineno modified the root + node twice. + - Issue #5871: email.header.Header.encode now raises an error if any continuation line in the formatted value has no leading white space and looks like a header. Since Generator uses Header to format all From python-checkins at python.org Sun Jan 9 08:50:49 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 08:50:49 +0100 (CET) Subject: [Python-checkins] r87877 - python/branches/py3k/Lib/test/test_ast.py Message-ID: <20110109075049.1F643EE99F@mail.python.org> Author: georg.brandl Date: Sun Jan 9 08:50:48 2011 New Revision: 87877 Log: Add missing line. Modified: python/branches/py3k/Lib/test/test_ast.py Modified: python/branches/py3k/Lib/test/test_ast.py ============================================================================== --- python/branches/py3k/Lib/test/test_ast.py (original) +++ python/branches/py3k/Lib/test/test_ast.py Sun Jan 9 08:50:48 2011 @@ -265,6 +265,7 @@ 'col_offset=0))' ) # issue10869: do not increment lineno of root twice + src = ast.parse('1 + 1', mode='eval') self.assertEqual(ast.increment_lineno(src.body, n=3), src.body) self.assertEqual(ast.dump(src, include_attributes=True), 'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), ' From python-checkins at python.org Sun Jan 9 08:51:15 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 08:51:15 +0100 (CET) Subject: [Python-checkins] r87878 - python/branches/release27-maint/Misc/NEWS Message-ID: <20110109075115.5DFE0EE99F@mail.python.org> Author: georg.brandl Date: Sun Jan 9 08:51:15 2011 New Revision: 87878 Log: Remove duplicate entry. Modified: python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Sun Jan 9 08:51:15 2011 @@ -36,13 +36,6 @@ dependent, but ``time.mktime`` will now accept full range supported by the OS. Conversion of 2-digit years to 4-digit is deprecated. -- Issue #10827: Changed the rules for 2-digit years. The time.asctime - function will now format any year when ``time.accept2dyear`` is - false and will accept years >= 1000 otherwise. The year range - accepted by ``time.mktime`` and ``time.strftime`` is still system - dependent, but ``time.mktime`` will now accept full range supported - by the OS. Conversion of 2-digit years to 4-digit is deprecated. - - Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. From python-checkins at python.org Sun Jan 9 08:53:14 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 08:53:14 +0100 (CET) Subject: [Python-checkins] r87879 - in python/branches/release27-maint: Doc/library/ast.rst Lib/ast.py Lib/test/test_ast.py Misc/ACKS Misc/NEWS Message-ID: <20110109075314.632F1EE9B7@mail.python.org> Author: georg.brandl Date: Sun Jan 9 08:53:14 2011 New Revision: 87879 Log: Merged revisions 87876-87877 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87876 | georg.brandl | 2011-01-09 08:38:51 +0100 (So, 09 Jan 2011) | 1 line #10869: do not visit root node twice in ast.increment_lineno(). ........ r87877 | georg.brandl | 2011-01-09 08:50:48 +0100 (So, 09 Jan 2011) | 1 line Add missing line. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Doc/library/ast.rst python/branches/release27-maint/Lib/ast.py python/branches/release27-maint/Lib/test/test_ast.py python/branches/release27-maint/Misc/ACKS python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Doc/library/ast.rst ============================================================================== --- python/branches/release27-maint/Doc/library/ast.rst (original) +++ python/branches/release27-maint/Doc/library/ast.rst Sun Jan 9 08:53:14 2011 @@ -187,9 +187,9 @@ .. function:: walk(node) - Recursively yield all child nodes of *node*, in no specified order. This is - useful if you only want to modify nodes in place and don't care about the - context. + Recursively yield all descendant nodes in the tree starting at *node* + (including *node* itself), in no specified order. This is useful if you only + want to modify nodes in place and don't care about the context. .. class:: NodeVisitor() Modified: python/branches/release27-maint/Lib/ast.py ============================================================================== --- python/branches/release27-maint/Lib/ast.py (original) +++ python/branches/release27-maint/Lib/ast.py Sun Jan 9 08:53:14 2011 @@ -152,8 +152,6 @@ Increment the line number of each node in the tree starting at *node* by *n*. This is useful to "move code" to a different location in a file. """ - if 'lineno' in node._attributes: - node.lineno = getattr(node, 'lineno', 0) + n for child in walk(node): if 'lineno' in child._attributes: child.lineno = getattr(child, 'lineno', 0) + n @@ -204,9 +202,9 @@ def walk(node): """ - Recursively yield all child nodes of *node*, in no specified order. This is - useful if you only want to modify nodes in place and don't care about the - context. + Recursively yield all descendant nodes in the tree starting at *node* + (including *node* itself), in no specified order. This is useful if you + only want to modify nodes in place and don't care about the context. """ from collections import deque todo = deque([node]) Modified: python/branches/release27-maint/Lib/test/test_ast.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_ast.py (original) +++ python/branches/release27-maint/Lib/test/test_ast.py Sun Jan 9 08:53:14 2011 @@ -264,6 +264,14 @@ 'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, ' 'col_offset=0))' ) + # issue10869: do not increment lineno of root twice + src = ast.parse('1 + 1', mode='eval') + self.assertEqual(ast.increment_lineno(src.body, n=3), src.body) + self.assertEqual(ast.dump(src, include_attributes=True), + 'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), ' + 'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, ' + 'col_offset=0))' + ) def test_iter_fields(self): node = ast.parse('foo()', mode='eval') Modified: python/branches/release27-maint/Misc/ACKS ============================================================================== --- python/branches/release27-maint/Misc/ACKS (original) +++ python/branches/release27-maint/Misc/ACKS Sun Jan 9 08:53:14 2011 @@ -848,6 +848,7 @@ Rickard Westman Jeff Wheeler Christopher White +David White Mats Wichmann Truida Wiedijk Felix Wiemann Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Sun Jan 9 08:53:14 2011 @@ -36,6 +36,9 @@ dependent, but ``time.mktime`` will now accept full range supported by the OS. Conversion of 2-digit years to 4-digit is deprecated. +- Issue #10869: Fixed bug where ast.increment_lineno modified the root + node twice. + - Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. From python-checkins at python.org Sun Jan 9 08:54:53 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 08:54:53 +0100 (CET) Subject: [Python-checkins] r87880 - python/branches/release27-maint Message-ID: <20110109075453.10572EEA9C@mail.python.org> Author: georg.brandl Date: Sun Jan 9 08:54:52 2011 New Revision: 87880 Log: Blocked revisions 87870 via svnmerge ........ r87870 | georg.brandl | 2011-01-08 22:04:25 +0100 (Sa, 08 Jan 2011) | 1 line zlib only works with bytes objects. ........ Modified: python/branches/release27-maint/ (props changed) From python-checkins at python.org Sun Jan 9 08:55:46 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 08:55:46 +0100 (CET) Subject: [Python-checkins] r87881 - in python/branches/release31-maint: Doc/library/ast.rst Lib/ast.py Lib/test/test_ast.py Misc/ACKS Misc/NEWS Message-ID: <20110109075546.EEED3EEA92@mail.python.org> Author: georg.brandl Date: Sun Jan 9 08:55:46 2011 New Revision: 87881 Log: Merged revisions 87876-87877 via svnmerge from svn+ssh://svn.python.org/python/branches/py3k ........ r87876 | georg.brandl | 2011-01-09 08:38:51 +0100 (So, 09 Jan 2011) | 1 line #10869: do not visit root node twice in ast.increment_lineno(). ........ r87877 | georg.brandl | 2011-01-09 08:50:48 +0100 (So, 09 Jan 2011) | 1 line Add missing line. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Doc/library/ast.rst python/branches/release31-maint/Lib/ast.py python/branches/release31-maint/Lib/test/test_ast.py python/branches/release31-maint/Misc/ACKS python/branches/release31-maint/Misc/NEWS Modified: python/branches/release31-maint/Doc/library/ast.rst ============================================================================== --- python/branches/release31-maint/Doc/library/ast.rst (original) +++ python/branches/release31-maint/Doc/library/ast.rst Sun Jan 9 08:55:46 2011 @@ -167,9 +167,9 @@ .. function:: walk(node) - Recursively yield all child nodes of *node*, in no specified order. This is - useful if you only want to modify nodes in place and don't care about the - context. + Recursively yield all descendant nodes in the tree starting at *node* + (including *node* itself), in no specified order. This is useful if you only + want to modify nodes in place and don't care about the context. .. class:: NodeVisitor() Modified: python/branches/release31-maint/Lib/ast.py ============================================================================== --- python/branches/release31-maint/Lib/ast.py (original) +++ python/branches/release31-maint/Lib/ast.py Sun Jan 9 08:55:46 2011 @@ -152,8 +152,6 @@ Increment the line number of each node in the tree starting at *node* by *n*. This is useful to "move code" to a different location in a file. """ - if 'lineno' in node._attributes: - node.lineno = getattr(node, 'lineno', 0) + n for child in walk(node): if 'lineno' in child._attributes: child.lineno = getattr(child, 'lineno', 0) + n @@ -204,9 +202,9 @@ def walk(node): """ - Recursively yield all child nodes of *node*, in no specified order. This is - useful if you only want to modify nodes in place and don't care about the - context. + Recursively yield all descendant nodes in the tree starting at *node* + (including *node* itself), in no specified order. This is useful if you + only want to modify nodes in place and don't care about the context. """ from collections import deque todo = deque([node]) Modified: python/branches/release31-maint/Lib/test/test_ast.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_ast.py (original) +++ python/branches/release31-maint/Lib/test/test_ast.py Sun Jan 9 08:55:46 2011 @@ -253,6 +253,14 @@ 'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, ' 'col_offset=0))' ) + # issue10869: do not increment lineno of root twice + src = ast.parse('1 + 1', mode='eval') + self.assertEqual(ast.increment_lineno(src.body, n=3), src.body) + self.assertEqual(ast.dump(src, include_attributes=True), + 'Expression(body=BinOp(left=Num(n=1, lineno=4, col_offset=0), ' + 'op=Add(), right=Num(n=1, lineno=4, col_offset=4), lineno=4, ' + 'col_offset=0))' + ) def test_iter_fields(self): node = ast.parse('foo()', mode='eval') Modified: python/branches/release31-maint/Misc/ACKS ============================================================================== --- python/branches/release31-maint/Misc/ACKS (original) +++ python/branches/release31-maint/Misc/ACKS Sun Jan 9 08:55:46 2011 @@ -841,6 +841,7 @@ Rickard Westman Jeff Wheeler Christopher White +David White Mats Wichmann Truida Wiedijk Felix Wiemann Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Sun Jan 9 08:55:46 2011 @@ -31,6 +31,9 @@ Library ------- +- Issue #10869: Fixed bug where ast.increment_lineno modified the root + node twice. + - Issue #5871: email.header.Header.encode now raises an error if any continuation line in the formatted value has no leading white space and looks like a header. Since Generator uses Header to format all From python-checkins at python.org Sun Jan 9 08:55:47 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 08:55:47 +0100 (CET) Subject: [Python-checkins] r87882 - python/branches/release27-maint Message-ID: <20110109075547.DCC6AEEA90@mail.python.org> Author: georg.brandl Date: Sun Jan 9 08:55:47 2011 New Revision: 87882 Log: Blocked revisions 86882 via svnmerge ........ r86882 | georg.brandl | 2010-11-30 09:20:16 +0100 (Di, 30 Nov 2010) | 1 line Fix input type for zlib. ........ Modified: python/branches/release27-maint/ (props changed) From python-checkins at python.org Sun Jan 9 08:58:45 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 08:58:45 +0100 (CET) Subject: [Python-checkins] r87883 - in python/branches/release27-maint: Doc/library/exceptions.rst Doc/library/threading.rst Doc/library/wave.rst Message-ID: <20110109075845.A6C36EE9B7@mail.python.org> Author: georg.brandl Date: Sun Jan 9 08:58:45 2011 New Revision: 87883 Log: Merged revisions 87807,87820,87831,87859 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87807 | georg.brandl | 2011-01-06 20:28:18 +0100 (Do, 06 Jan 2011) | 1 line #10846: fix typo. ........ r87820 | georg.brandl | 2011-01-07 19:28:45 +0100 (Fr, 07 Jan 2011) | 1 line #10856: document (Base)Exception.args better. ........ r87831 | georg.brandl | 2011-01-07 21:58:25 +0100 (Fr, 07 Jan 2011) | 1 line Fix indent. ........ r87859 | georg.brandl | 2011-01-08 10:45:43 +0100 (Sa, 08 Jan 2011) | 1 line #10855: document close() semantics of wave objects. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Doc/library/exceptions.rst python/branches/release27-maint/Doc/library/threading.rst python/branches/release27-maint/Doc/library/wave.rst Modified: python/branches/release27-maint/Doc/library/exceptions.rst ============================================================================== --- python/branches/release27-maint/Doc/library/exceptions.rst (original) +++ python/branches/release27-maint/Doc/library/exceptions.rst Sun Jan 9 08:58:45 2011 @@ -26,7 +26,7 @@ The built-in exceptions listed below can be generated by the interpreter or built-in functions. Except where mentioned, they have an "associated value" -indicating the detailed cause of the error. This may be a string or a tuple +indicating the detailed cause of the error. This may be a string or a tuple containing several items of information (e.g., an error code and a string explaining the code). The associated value is the second argument to the :keyword:`raise` statement. If the exception class is derived from the standard @@ -46,18 +46,35 @@ The following exceptions are only used as base classes for other exceptions. - .. exception:: BaseException The base class for all built-in exceptions. It is not meant to be directly - inherited by user-defined classes (for that use :exc:`Exception`). If + inherited by user-defined classes (for that, use :exc:`Exception`). If :func:`str` or :func:`unicode` is called on an instance of this class, the - representation of the argument(s) to the instance are returned or the empty - string when there were no arguments. All arguments are stored in :attr:`args` - as a tuple. + representation of the argument(s) to the instance are returned, or the empty + string when there were no arguments. .. versionadded:: 2.5 + .. attribute:: args + + The tuple of arguments given to the exception constructor. Some built-in + exceptions (like :exc:`IOError`) expect a certain number of arguments and + assign a special meaning to the elements of this tuple, while others are + usually called only with a single string giving an error message. + + .. method:: with_traceback(tb) + + This method sets *tb* as the new traceback for the exception and returns + the exception object. It is usually used in exception handling code like + this:: + + try: + ... + except SomeException: + tb = sys.exc_info()[2] + raise OtherException(...).with_traceback(tb) + .. exception:: Exception Modified: python/branches/release27-maint/Doc/library/threading.rst ============================================================================== --- python/branches/release27-maint/Doc/library/threading.rst (original) +++ python/branches/release27-maint/Doc/library/threading.rst Sun Jan 9 08:58:45 2011 @@ -655,9 +655,9 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Semaphores are often used to guard resources with limited capacity, for example, -a database server. In any situation where the size of the resource size is -fixed, you should use a bounded semaphore. Before spawning any worker threads, -your main thread would initialize the semaphore:: +a database server. In any situation where the size of the resource is fixed, +you should use a bounded semaphore. Before spawning any worker threads, your +main thread would initialize the semaphore:: maxconnections = 5 ... Modified: python/branches/release27-maint/Doc/library/wave.rst ============================================================================== --- python/branches/release27-maint/Doc/library/wave.rst (original) +++ python/branches/release27-maint/Doc/library/wave.rst Sun Jan 9 08:58:45 2011 @@ -14,8 +14,8 @@ .. function:: open(file[, mode]) - If *file* is a string, open the file by that name, other treat it as a seekable - file-like object. *mode* can be any of + If *file* is a string, open the file by that name, otherwise treat it as a + seekable file-like object. *mode* can be any of ``'r'``, ``'rb'`` Read only mode. @@ -26,9 +26,14 @@ Note that it does not allow read/write WAV files. A *mode* of ``'r'`` or ``'rb'`` returns a :class:`Wave_read` object, while a - *mode* of ``'w'`` or ``'wb'`` returns a :class:`Wave_write` object. If *mode* - is omitted and a file-like object is passed as *file*, ``file.mode`` is used as - the default value for *mode* (the ``'b'`` flag is still added if necessary). + *mode* of ``'w'`` or ``'wb'`` returns a :class:`Wave_write` object. If + *mode* is omitted and a file-like object is passed as *file*, ``file.mode`` + is used as the default value for *mode* (the ``'b'`` flag is still added if + necessary). + + If you pass in a file-like object, the wave object will not close it when its + :meth:`close` method is called; it is the caller's responsibility to close + the file object. .. function:: openfp(file, mode) @@ -52,8 +57,8 @@ .. method:: Wave_read.close() - Close the stream, and make the instance unusable. This is called automatically - on object collection. + Close the stream if it was opened by :mod:`wave`, and make the instance + unusable. This is called automatically on object collection. .. method:: Wave_read.getnchannels() @@ -139,8 +144,8 @@ .. method:: Wave_write.close() - Make sure *nframes* is correct, and close the file. This method is called upon - deletion. + Make sure *nframes* is correct, and close the file if it was opened by + :mod:`wave`. This method is called upon object collection. .. method:: Wave_write.setnchannels(n) @@ -192,6 +197,7 @@ Write audio frames and make sure *nframes* is correct. + Note that it is invalid to set any parameters after calling :meth:`writeframes` or :meth:`writeframesraw`, and any attempt to do so will raise :exc:`wave.Error`. From python-checkins at python.org Sun Jan 9 08:59:03 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 08:59:03 +0100 (CET) Subject: [Python-checkins] r87884 - in python/branches/release31-maint: Doc/library/exceptions.rst Doc/library/threading.rst Doc/library/wave.rst Doc/library/zlib.rst Message-ID: <20110109075903.2E343EE9B7@mail.python.org> Author: georg.brandl Date: Sun Jan 9 08:59:02 2011 New Revision: 87884 Log: Merged revisions 87807,87820,87831,87859,87870 via svnmerge from svn+ssh://svn.python.org/python/branches/py3k ........ r87807 | georg.brandl | 2011-01-06 20:28:18 +0100 (Do, 06 Jan 2011) | 1 line #10846: fix typo. ........ r87820 | georg.brandl | 2011-01-07 19:28:45 +0100 (Fr, 07 Jan 2011) | 1 line #10856: document (Base)Exception.args better. ........ r87831 | georg.brandl | 2011-01-07 21:58:25 +0100 (Fr, 07 Jan 2011) | 1 line Fix indent. ........ r87859 | georg.brandl | 2011-01-08 10:45:43 +0100 (Sa, 08 Jan 2011) | 1 line #10855: document close() semantics of wave objects. ........ r87870 | georg.brandl | 2011-01-08 22:04:25 +0100 (Sa, 08 Jan 2011) | 1 line zlib only works with bytes objects. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Doc/library/exceptions.rst python/branches/release31-maint/Doc/library/threading.rst python/branches/release31-maint/Doc/library/wave.rst python/branches/release31-maint/Doc/library/zlib.rst Modified: python/branches/release31-maint/Doc/library/exceptions.rst ============================================================================== --- python/branches/release31-maint/Doc/library/exceptions.rst (original) +++ python/branches/release31-maint/Doc/library/exceptions.rst Sun Jan 9 08:59:02 2011 @@ -18,12 +18,10 @@ The built-in exceptions listed below can be generated by the interpreter or built-in functions. Except where mentioned, they have an "associated value" -indicating the detailed cause of the error. This may be a string or a tuple -containing several items of information (e.g., an error code and a string -explaining the code). The associated value is usually passed to the exception -class's constructor. If the exception class is derived from the standard root -class :exc:`BaseException`, the associated value is present as the exception -instance's :attr:`args` attribute. +indicating the detailed cause of the error. This may be a string or a tuple of +several items of information (e.g., an error code and a string explaining the +code). The associated value is usually passed as arguments to the exception +class's constructor. User code can raise built-in exceptions. This can be used to test an exception handler or to report an error condition "just like" the situation in which the @@ -38,16 +36,32 @@ The following exceptions are used mostly as base classes for other exceptions. -.. XXX document with_traceback() - .. exception:: BaseException The base class for all built-in exceptions. It is not meant to be directly - inherited by user-defined classes (for that use :exc:`Exception`). If + inherited by user-defined classes (for that, use :exc:`Exception`). If :func:`bytes` or :func:`str` is called on an instance of this class, the - representation of the argument(s) to the instance are returned or the empty - string when there were no arguments. All arguments are stored in :attr:`args` - as a tuple. + representation of the argument(s) to the instance are returned, or the empty + string when there were no arguments. + + .. attribute:: args + + The tuple of arguments given to the exception constructor. Some built-in + exceptions (like :exc:`IOError`) expect a certain number of arguments and + assign a special meaning to the elements of this tuple, while others are + usually called only with a single string giving an error message. + + .. method:: with_traceback(tb) + + This method sets *tb* as the new traceback for the exception and returns + the exception object. It is usually used in exception handling code like + this:: + + try: + ... + except SomeException: + tb = sys.exc_info()[2] + raise OtherException(...).with_traceback(tb) .. exception:: Exception Modified: python/branches/release31-maint/Doc/library/threading.rst ============================================================================== --- python/branches/release31-maint/Doc/library/threading.rst (original) +++ python/branches/release31-maint/Doc/library/threading.rst Sun Jan 9 08:59:02 2011 @@ -632,9 +632,9 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Semaphores are often used to guard resources with limited capacity, for example, -a database server. In any situation where the size of the resource size is -fixed, you should use a bounded semaphore. Before spawning any worker threads, -your main thread would initialize the semaphore:: +a database server. In any situation where the size of the resource is fixed, +you should use a bounded semaphore. Before spawning any worker threads, your +main thread would initialize the semaphore:: maxconnections = 5 ... Modified: python/branches/release31-maint/Doc/library/wave.rst ============================================================================== --- python/branches/release31-maint/Doc/library/wave.rst (original) +++ python/branches/release31-maint/Doc/library/wave.rst Sun Jan 9 08:59:02 2011 @@ -14,8 +14,8 @@ .. function:: open(file, mode=None) - If *file* is a string, open the file by that name, other treat it as a seekable - file-like object. *mode* can be any of + If *file* is a string, open the file by that name, otherwise treat it as a + seekable file-like object. *mode* can be any of ``'r'``, ``'rb'`` Read only mode. @@ -26,9 +26,14 @@ Note that it does not allow read/write WAV files. A *mode* of ``'r'`` or ``'rb'`` returns a :class:`Wave_read` object, while a - *mode* of ``'w'`` or ``'wb'`` returns a :class:`Wave_write` object. If *mode* - is omitted and a file-like object is passed as *file*, ``file.mode`` is used as - the default value for *mode* (the ``'b'`` flag is still added if necessary). + *mode* of ``'w'`` or ``'wb'`` returns a :class:`Wave_write` object. If + *mode* is omitted and a file-like object is passed as *file*, ``file.mode`` + is used as the default value for *mode* (the ``'b'`` flag is still added if + necessary). + + If you pass in a file-like object, the wave object will not close it when its + :meth:`close` method is called; it is the caller's responsibility to close + the file object. .. function:: openfp(file, mode) @@ -52,8 +57,8 @@ .. method:: Wave_read.close() - Close the stream, and make the instance unusable. This is called automatically - on object collection. + Close the stream if it was opened by :mod:`wave`, and make the instance + unusable. This is called automatically on object collection. .. method:: Wave_read.getnchannels() @@ -139,8 +144,8 @@ .. method:: Wave_write.close() - Make sure *nframes* is correct, and close the file. This method is called upon - deletion. + Make sure *nframes* is correct, and close the file if it was opened by + :mod:`wave`. This method is called upon object collection. .. method:: Wave_write.setnchannels(n) @@ -192,6 +197,7 @@ Write audio frames and make sure *nframes* is correct. + Note that it is invalid to set any parameters after calling :meth:`writeframes` or :meth:`writeframesraw`, and any attempt to do so will raise :exc:`wave.Error`. Modified: python/branches/release31-maint/Doc/library/zlib.rst ============================================================================== --- python/branches/release31-maint/Doc/library/zlib.rst (original) +++ python/branches/release31-maint/Doc/library/zlib.rst Sun Jan 9 08:59:02 2011 @@ -51,9 +51,9 @@ regardless of sign. -.. function:: compress(string[, level]) +.. function:: compress(data[, level]) - Compresses the data in *string*, returning a string contained compressed data. + Compresses the bytes in *data*, returning a bytes object containing compressed data. *level* is an integer from ``1`` to ``9`` controlling the level of compression; ``1`` is fastest and produces the least compression, ``9`` is slowest and produces the most. The default value is ``6``. Raises the :exc:`error` @@ -92,9 +92,9 @@ regardless of sign. -.. function:: decompress(string[, wbits[, bufsize]]) +.. function:: decompress(data[, wbits[, bufsize]]) - Decompresses the data in *string*, returning a string containing the + Decompresses the bytes in *data*, returning a bytes object containing the uncompressed data. The *wbits* parameter controls the size of the window buffer. If *bufsize* is given, it is used as the initial size of the output buffer. Raises the :exc:`error` exception if any error occurs. @@ -121,21 +121,21 @@ Compression objects support the following methods: -.. method:: Compress.compress(string) +.. method:: Compress.compress(data) - Compress *string*, returning a string containing compressed data for at least - part of the data in *string*. This data should be concatenated to the output + Compress *data*, returning a bytes object containing compressed data for at least + part of the data in *data*. This data should be concatenated to the output produced by any preceding calls to the :meth:`compress` method. Some input may be kept in internal buffers for later processing. .. method:: Compress.flush([mode]) - All pending input is processed, and a string containing the remaining compressed + All pending input is processed, and a bytes object containing the remaining compressed output is returned. *mode* can be selected from the constants :const:`Z_SYNC_FLUSH`, :const:`Z_FULL_FLUSH`, or :const:`Z_FINISH`, defaulting to :const:`Z_FINISH`. :const:`Z_SYNC_FLUSH` and - :const:`Z_FULL_FLUSH` allow compressing further strings of data, while + :const:`Z_FULL_FLUSH` allow compressing further bytestrings of data, while :const:`Z_FINISH` finishes the compressed stream and prevents compressing any more data. After calling :meth:`flush` with *mode* set to :const:`Z_FINISH`, the :meth:`compress` method cannot be called again; the only realistic action is @@ -153,31 +153,31 @@ .. attribute:: Decompress.unused_data - A string which contains any bytes past the end of the compressed data. That is, + A bytes object which contains any bytes past the end of the compressed data. That is, this remains ``""`` until the last byte that contains compression data is - available. If the whole string turned out to contain compressed data, this is - ``""``, the empty string. + available. If the whole bytestring turned out to contain compressed data, this is + ``b""``, an empty bytes object. - The only way to determine where a string of compressed data ends is by actually + The only way to determine where a bytestring of compressed data ends is by actually decompressing it. This means that when compressed data is contained part of a larger file, you can only find the end of it by reading data and feeding it - followed by some non-empty string into a decompression object's + followed by some non-empty bytestring into a decompression object's :meth:`decompress` method until the :attr:`unused_data` attribute is no longer - the empty string. + empty. .. attribute:: Decompress.unconsumed_tail - A string that contains any data that was not consumed by the last + A bytes object that contains any data that was not consumed by the last :meth:`decompress` call because it exceeded the limit for the uncompressed data buffer. This data has not yet been seen by the zlib machinery, so you must feed it (possibly with further data concatenated to it) back to a subsequent :meth:`decompress` method call in order to get correct output. -.. method:: Decompress.decompress(string[, max_length]) +.. method:: Decompress.decompress(data[, max_length]) - Decompress *string*, returning a string containing the uncompressed data + Decompress *data*, returning a bytes object containing the uncompressed data corresponding to at least part of the data in *string*. This data should be concatenated to the output produced by any preceding calls to the :meth:`decompress` method. Some of the input data may be preserved in internal @@ -186,15 +186,15 @@ If the optional parameter *max_length* is supplied then the return value will be no longer than *max_length*. This may mean that not all of the compressed input can be processed; and unconsumed data will be stored in the attribute - :attr:`unconsumed_tail`. This string must be passed to a subsequent call to + :attr:`unconsumed_tail`. This bytestring must be passed to a subsequent call to :meth:`decompress` if decompression is to continue. If *max_length* is not - supplied then the whole input is decompressed, and :attr:`unconsumed_tail` is an - empty string. + supplied then the whole input is decompressed, and :attr:`unconsumed_tail` is + empty. .. method:: Decompress.flush([length]) - All pending input is processed, and a string containing the remaining + All pending input is processed, and a bytes object containing the remaining uncompressed output is returned. After calling :meth:`flush`, the :meth:`decompress` method cannot be called again; the only realistic action is to delete the object. From python-checkins at python.org Sun Jan 9 08:59:59 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 08:59:59 +0100 (CET) Subject: [Python-checkins] r87885 - in python/branches/release31-maint: Mac/IDLE/IDLE.app/Contents/Info.plist Mac/PythonLauncher/Info.plist.in Mac/Resources/app/Info.plist.in Mac/Resources/framework/Info.plist.in Message-ID: <20110109075959.74C69EE9B7@mail.python.org> Author: georg.brandl Date: Sun Jan 9 08:59:59 2011 New Revision: 87885 Log: Merged revisions 87791 via svnmerge from svn+ssh://svn.python.org/python/branches/py3k ........ r87791 | georg.brandl | 2011-01-06 11:05:26 +0100 (Do, 06 Jan 2011) | 1 line #10844: update copyright years in Mac plists. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Mac/IDLE/IDLE.app/Contents/Info.plist python/branches/release31-maint/Mac/PythonLauncher/Info.plist.in python/branches/release31-maint/Mac/Resources/app/Info.plist.in python/branches/release31-maint/Mac/Resources/framework/Info.plist.in Modified: python/branches/release31-maint/Mac/IDLE/IDLE.app/Contents/Info.plist ============================================================================== --- python/branches/release31-maint/Mac/IDLE/IDLE.app/Contents/Info.plist (original) +++ python/branches/release31-maint/Mac/IDLE/IDLE.app/Contents/Info.plist Sun Jan 9 08:59:59 2011 @@ -36,7 +36,7 @@ CFBundleExecutable IDLE CFBundleGetInfoString - %version%, ? 2001-2008 Python Software Foundation + %version%, ? 2001-2011 Python Software Foundation CFBundleIconFile IDLE.icns CFBundleIdentifier Modified: python/branches/release31-maint/Mac/PythonLauncher/Info.plist.in ============================================================================== --- python/branches/release31-maint/Mac/PythonLauncher/Info.plist.in (original) +++ python/branches/release31-maint/Mac/PythonLauncher/Info.plist.in Sun Jan 9 08:59:59 2011 @@ -40,7 +40,7 @@ CFBundleExecutable PythonLauncher CFBundleGetInfoString - %VERSION%, ? 2001-2008 Python Software Foundation + %VERSION%, ? 2001-2011 Python Software Foundation CFBundleIconFile PythonLauncher.icns CFBundleIdentifier Modified: python/branches/release31-maint/Mac/Resources/app/Info.plist.in ============================================================================== --- python/branches/release31-maint/Mac/Resources/app/Info.plist.in (original) +++ python/branches/release31-maint/Mac/Resources/app/Info.plist.in Sun Jan 9 08:59:59 2011 @@ -20,7 +20,7 @@ CFBundleExecutable Python CFBundleGetInfoString - %version%, (c) 2004-2010 Python Software Foundation. + %version%, (c) 2004-2011 Python Software Foundation. CFBundleHelpBookFolder Documentation @@ -37,7 +37,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - %version%, (c) 2004-2010 Python Software Foundation. + %version%, (c) 2004-2011 Python Software Foundation. CFBundleName Python CFBundlePackageType @@ -55,6 +55,6 @@ NSAppleScriptEnabled NSHumanReadableCopyright - (c) 2004 Python Software Foundation. + (c) 2011 Python Software Foundation. Modified: python/branches/release31-maint/Mac/Resources/framework/Info.plist.in ============================================================================== --- python/branches/release31-maint/Mac/Resources/framework/Info.plist.in (original) +++ python/branches/release31-maint/Mac/Resources/framework/Info.plist.in Sun Jan 9 08:59:59 2011 @@ -17,9 +17,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - %VERSION%, (c) 2004-2008 Python Software Foundation. + %VERSION%, (c) 2004-2011 Python Software Foundation. CFBundleLongVersionString - %VERSION%, (c) 2004-2008 Python Software Foundation. + %VERSION%, (c) 2004-2011 Python Software Foundation. CFBundleSignature ???? CFBundleVersion From python-checkins at python.org Sun Jan 9 09:00:33 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 09:00:33 +0100 (CET) Subject: [Python-checkins] r87886 - in python/branches/release27-maint: Mac/IDLE/Info.plist.in Mac/PythonLauncher/Info.plist.in Mac/Resources/app/Info.plist.in Mac/Resources/framework/Info.plist.in Message-ID: <20110109080033.C2F00EE9E3@mail.python.org> Author: georg.brandl Date: Sun Jan 9 09:00:33 2011 New Revision: 87886 Log: Merged revisions 87791 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87791 | georg.brandl | 2011-01-06 11:05:26 +0100 (Do, 06 Jan 2011) | 1 line #10844: update copyright years in Mac plists. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Mac/IDLE/Info.plist.in python/branches/release27-maint/Mac/PythonLauncher/Info.plist.in python/branches/release27-maint/Mac/Resources/app/Info.plist.in python/branches/release27-maint/Mac/Resources/framework/Info.plist.in Modified: python/branches/release27-maint/Mac/IDLE/Info.plist.in ============================================================================== --- python/branches/release27-maint/Mac/IDLE/Info.plist.in (original) +++ python/branches/release27-maint/Mac/IDLE/Info.plist.in Sun Jan 9 09:00:33 2011 @@ -36,7 +36,7 @@ CFBundleExecutable IDLE CFBundleGetInfoString - %VERSION%, ? 001-2006 Python Software Foundation + %VERSION%, ? 2001-2011 Python Software Foundation CFBundleIconFile IDLE.icns CFBundleIdentifier Modified: python/branches/release27-maint/Mac/PythonLauncher/Info.plist.in ============================================================================== --- python/branches/release27-maint/Mac/PythonLauncher/Info.plist.in (original) +++ python/branches/release27-maint/Mac/PythonLauncher/Info.plist.in Sun Jan 9 09:00:33 2011 @@ -40,7 +40,7 @@ CFBundleExecutable PythonLauncher CFBundleGetInfoString - %VERSION%, ? 001-2006 Python Software Foundation + %VERSION%, ? 2001-2011 Python Software Foundation CFBundleIconFile PythonLauncher.icns CFBundleIdentifier Modified: python/branches/release27-maint/Mac/Resources/app/Info.plist.in ============================================================================== --- python/branches/release27-maint/Mac/Resources/app/Info.plist.in (original) +++ python/branches/release27-maint/Mac/Resources/app/Info.plist.in Sun Jan 9 09:00:33 2011 @@ -20,7 +20,7 @@ CFBundleExecutable Python CFBundleGetInfoString - %version%, (c) 2004-2010 Python Software Foundation. + %version%, (c) 2004-2011 Python Software Foundation. CFBundleHelpBookFolder Documentation @@ -37,7 +37,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleLongVersionString - %version%, (c) 2004-2010 Python Software Foundation. + %version%, (c) 2004-2011 Python Software Foundation. CFBundleName Python CFBundlePackageType @@ -55,6 +55,6 @@ NSAppleScriptEnabled NSHumanReadableCopyright - (c) 2004 Python Software Foundation. + (c) 2011 Python Software Foundation. Modified: python/branches/release27-maint/Mac/Resources/framework/Info.plist.in ============================================================================== --- python/branches/release27-maint/Mac/Resources/framework/Info.plist.in (original) +++ python/branches/release27-maint/Mac/Resources/framework/Info.plist.in Sun Jan 9 09:00:33 2011 @@ -17,9 +17,9 @@ CFBundlePackageType FMWK CFBundleShortVersionString - %VERSION%, (c) 2004-2008 Python Software Foundation. + %VERSION%, (c) 2004-2011 Python Software Foundation. CFBundleLongVersionString - %VERSION%, (c) 2004-2008 Python Software Foundation. + %VERSION%, (c) 2004-2011 Python Software Foundation. CFBundleSignature ???? CFBundleVersion From python-checkins at python.org Sun Jan 9 09:01:46 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 09:01:46 +0100 (CET) Subject: [Python-checkins] r87887 - in python/branches/release31-maint: Doc/ACKS.txt Doc/glossary.rst Doc/library/csv.rst Doc/library/email.charset.rst Doc/library/email.header.rst Doc/library/inspect.rst Doc/library/operator.rst Doc/library/string.rst Doc/reference/compound_stmts.rst Doc/reference/executionmodel.rst Message-ID: <20110109080146.A40BBEEA15@mail.python.org> Author: georg.brandl Date: Sun Jan 9 09:01:46 2011 New Revision: 87887 Log: Merged revisions 87789-87790 via svnmerge from svn+ssh://svn.python.org/python/branches/py3k ........ r87789 | georg.brandl | 2011-01-06 10:23:56 +0100 (Do, 06 Jan 2011) | 1 line Fix various issues (mostly Python 2 relics) found by Jacques Ducasse. ........ r87790 | georg.brandl | 2011-01-06 10:25:27 +0100 (Do, 06 Jan 2011) | 1 line Add acks where acks are due. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Doc/ACKS.txt python/branches/release31-maint/Doc/glossary.rst python/branches/release31-maint/Doc/library/csv.rst python/branches/release31-maint/Doc/library/email.charset.rst python/branches/release31-maint/Doc/library/email.header.rst python/branches/release31-maint/Doc/library/inspect.rst python/branches/release31-maint/Doc/library/operator.rst python/branches/release31-maint/Doc/library/string.rst python/branches/release31-maint/Doc/reference/compound_stmts.rst python/branches/release31-maint/Doc/reference/executionmodel.rst Modified: python/branches/release31-maint/Doc/ACKS.txt ============================================================================== --- python/branches/release31-maint/Doc/ACKS.txt (original) +++ python/branches/release31-maint/Doc/ACKS.txt Sun Jan 9 09:01:46 2011 @@ -47,6 +47,7 @@ * L. Peter Deutsch * Robert Donohue * Fred L. Drake, Jr. + * Jacques Ducasse * Josip Dzolonga * Jeff Epler * Michael Ernst Modified: python/branches/release31-maint/Doc/glossary.rst ============================================================================== --- python/branches/release31-maint/Doc/glossary.rst (original) +++ python/branches/release31-maint/Doc/glossary.rst Sun Jan 9 09:01:46 2011 @@ -344,12 +344,12 @@ iterator An object representing a stream of data. Repeated calls to the iterator's - :meth:`__next__` (or passing it to the built-in function :func:`next`) - method return successive items in the stream. When no more data are - available a :exc:`StopIteration` exception is raised instead. At this + :meth:`__next__` method (or passing it to the built-in function + :func:`next`) return successive items in the stream. When no more data + are available a :exc:`StopIteration` exception is raised instead. At this point, the iterator object is exhausted and any further calls to its - :meth:`next` method just raise :exc:`StopIteration` again. Iterators are - required to have an :meth:`__iter__` method that returns the iterator + :meth:`__next__` method just raise :exc:`StopIteration` again. Iterators + are required to have an :meth:`__iter__` method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a Modified: python/branches/release31-maint/Doc/library/csv.rst ============================================================================== --- python/branches/release31-maint/Doc/library/csv.rst (original) +++ python/branches/release31-maint/Doc/library/csv.rst Sun Jan 9 09:01:46 2011 @@ -50,7 +50,7 @@ Return a reader object which will iterate over lines in the given *csvfile*. *csvfile* can be any object which supports the :term:`iterator` protocol and returns a - string each time its :meth:`!next` method is called --- :term:`file objects + string each time its :meth:`!__next__` method is called --- :term:`file objects ` and list objects are both suitable. If *csvfile* is a file object, it should be opened with ``newline=''``. [#]_ An optional *dialect* parameter can be given which is used to define a set of parameters Modified: python/branches/release31-maint/Doc/library/email.charset.rst ============================================================================== --- python/branches/release31-maint/Doc/library/email.charset.rst (original) +++ python/branches/release31-maint/Doc/library/email.charset.rst Sun Jan 9 09:01:46 2011 @@ -142,12 +142,6 @@ it is *input_charset*. - .. method:: encoded_header_len() - - Return the length of the encoded header string, properly calculating for - quoted-printable or base64 encoding. - - .. method:: header_encode(string) Header-encode the string *string*. @@ -156,6 +150,16 @@ *header_encoding* attribute. + .. method:: header_encode_lines(string, maxlengths) + + Header-encode a *string* by converting it first to bytes. + + This is similar to :meth:`header_encode` except that the string is fit + into maximum line lengths as given by the argument *maxlengths*, which + must be an iterator: each element returned from this iterator will provide + the next maximum line length. + + .. method:: body_encode(string) Body-encode the string *string*. Modified: python/branches/release31-maint/Doc/library/email.header.rst ============================================================================== --- python/branches/release31-maint/Doc/library/email.header.rst (original) +++ python/branches/release31-maint/Doc/library/email.header.rst Sun Jan 9 09:01:46 2011 @@ -121,14 +121,10 @@ .. method:: __str__() - A synonym for :meth:`Header.encode`. Useful for ``str(aHeader)``. - - - .. method:: __unicode__() - A helper for :class:`str`'s :func:`encode` method. Returns the header as a Unicode string. + .. method:: __eq__(other) This method allows you to compare two :class:`Header` instances for Modified: python/branches/release31-maint/Doc/library/inspect.rst ============================================================================== --- python/branches/release31-maint/Doc/library/inspect.rst (original) +++ python/branches/release31-maint/Doc/library/inspect.rst Sun Jan 9 09:01:46 2011 @@ -176,17 +176,16 @@ .. function:: getmoduleinfo(path) - Returns a :term:`named tuple` ``ModuleInfo(name, suffix, mode, - module_type)`` of values that describe how Python will interpret the file - identified by *path* if it is a module, or ``None`` if it would not be - identified as a module. The return tuple is ``(name, suffix, mode, mtype)``, - where *name* is the name of the module without the name of any enclosing - package, *suffix* is the trailing part of the file name (which may not be a - dot-delimited extension), *mode* is the :func:`open` mode that would be used - (``'r'`` or ``'rb'``), and *mtype* is an integer giving the type of the - module. *mtype* will have a value which can be compared to the constants - defined in the :mod:`imp` module; see the documentation for that module for - more information on module types. + Returns a :term:`named tuple` ``ModuleInfo(name, suffix, mode, module_type)`` + of values that describe how Python will interpret the file identified by + *path* if it is a module, or ``None`` if it would not be identified as a + module. In that tuple, *name* is the name of the module without the name of + any enclosing package, *suffix* is the trailing part of the file name (which + may not be a dot-delimited extension), *mode* is the :func:`open` mode that + would be used (``'r'`` or ``'rb'``), and *module_type* is an integer giving + the type of the module. *module_type* will have a value which can be + compared to the constants defined in the :mod:`imp` module; see the + documentation for that module for more information on module types. .. function:: getmodulename(path) @@ -391,12 +390,12 @@ .. function:: getargspec(func) Get the names and default values of a Python function's arguments. A - :term:`named tuple` ``ArgSpec(args, varargs, keywords, - defaults)`` is returned. *args* is a list of - the argument names. *varargs* and *varkw* are the names of the ``*`` and - ``**`` arguments or ``None``. *defaults* is a tuple of default argument - values or None if there are no default arguments; if this tuple has *n* - elements, they correspond to the last *n* elements listed in *args*. + :term:`named tuple` ``ArgSpec(args, varargs, keywords, defaults)`` is + returned. *args* is a list of the argument names. *varargs* and *keywords* + are the names of the ``*`` and ``**`` arguments or ``None``. *defaults* is a + tuple of default argument values or None if there are no default arguments; + if this tuple has *n* elements, they correspond to the last *n* elements + listed in *args*. .. deprecated:: 3.0 Use :func:`getfullargspec` instead, which provides information about @@ -425,8 +424,8 @@ Get information about arguments passed into a particular frame. A :term:`named tuple` ``ArgInfo(args, varargs, keywords, locals)`` is - returned. *args* is a list of the argument names. *varargs* and *varkw* are - the names of the ``*`` and ``**`` arguments or ``None``. *locals* is the + returned. *args* is a list of the argument names. *varargs* and *keywords* + are the names of the ``*`` and ``**`` arguments or ``None``. *locals* is the locals dictionary of the given frame. Modified: python/branches/release31-maint/Doc/library/operator.rst ============================================================================== --- python/branches/release31-maint/Doc/library/operator.rst (original) +++ python/branches/release31-maint/Doc/library/operator.rst Sun Jan 9 09:01:46 2011 @@ -19,8 +19,7 @@ trailing ``__`` are also provided for convenience. The functions fall into categories that perform object comparisons, logical -operations, mathematical operations, sequence operations, and abstract type -tests. +operations, mathematical operations and sequence operations. The object comparison functions are useful for all objects, and are named after the rich comparison operators they support: Modified: python/branches/release31-maint/Doc/library/string.rst ============================================================================== --- python/branches/release31-maint/Doc/library/string.rst (original) +++ python/branches/release31-maint/Doc/library/string.rst Sun Jan 9 09:01:46 2011 @@ -5,16 +5,11 @@ :synopsis: Common string operations. -.. index:: module: re +.. seealso:: -The :mod:`string` module contains a number of useful constants and classes -for string formatting. In addition, Python's built-in string classes -support the sequence type methods described in the :ref:`typesseq` -section, and also the string-specific methods described in the -:ref:`string-methods` section. To output formatted strings, see the -:ref:`string-formatting` section. Also, see the :mod:`re` module for -string functions based on regular expressions. + :ref:`typesseq` + :ref:`string-methods` String constants ---------------- Modified: python/branches/release31-maint/Doc/reference/compound_stmts.rst ============================================================================== --- python/branches/release31-maint/Doc/reference/compound_stmts.rst (original) +++ python/branches/release31-maint/Doc/reference/compound_stmts.rst Sun Jan 9 09:01:46 2011 @@ -285,12 +285,11 @@ Before an except clause's suite is executed, details about the exception are stored in the :mod:`sys` module and can be access via :func:`sys.exc_info`. -:func:`sys.exc_info` returns a 3-tuple consisting of: ``exc_type``, the -exception class; ``exc_value``, the exception instance; ``exc_traceback``, a -traceback object (see section :ref:`types`) identifying the point in the program -where the exception occurred. :func:`sys.exc_info` values are restored to their -previous values (before the call) when returning from a function that handled an -exception. +:func:`sys.exc_info` returns a 3-tuple consisting of the exception class, the +exception instance and a traceback object (see section :ref:`types`) identifying +the point in the program where the exception occurred. :func:`sys.exc_info` +values are restored to their previous values (before the call) when returning +from a function that handled an exception. .. index:: keyword: else Modified: python/branches/release31-maint/Doc/reference/executionmodel.rst ============================================================================== --- python/branches/release31-maint/Doc/reference/executionmodel.rst (original) +++ python/branches/release31-maint/Doc/reference/executionmodel.rst Sun Jan 9 09:01:46 2011 @@ -141,9 +141,9 @@ The namespace for a module is automatically created the first time a module is imported. The main module for a script is always called :mod:`__main__`. -The global statement has the same scope as a name binding operation in the same -block. If the nearest enclosing scope for a free variable contains a global -statement, the free variable is treated as a global. +The :keyword:`global` statement has the same scope as a name binding operation +in the same block. If the nearest enclosing scope for a free variable contains +a global statement, the free variable is treated as a global. A class definition is an executable statement that may use and define names. These references follow the normal rules for name resolution. The namespace of From python-checkins at python.org Sun Jan 9 09:01:47 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 09:01:47 +0100 (CET) Subject: [Python-checkins] r87888 - python/branches/release27-maint Message-ID: <20110109080147.99228EEA15@mail.python.org> Author: georg.brandl Date: Sun Jan 9 09:01:47 2011 New Revision: 87888 Log: Blocked revisions 87789-87790 via svnmerge ........ r87789 | georg.brandl | 2011-01-06 10:23:56 +0100 (Do, 06 Jan 2011) | 1 line Fix various issues (mostly Python 2 relics) found by Jacques Ducasse. ........ r87790 | georg.brandl | 2011-01-06 10:25:27 +0100 (Do, 06 Jan 2011) | 1 line Add acks where acks are due. ........ Modified: python/branches/release27-maint/ (props changed) From python-checkins at python.org Sun Jan 9 09:04:38 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 09:04:38 +0100 (CET) Subject: [Python-checkins] r87889 - in python/branches/release27-maint/Doc: library/inspect.rst reference/executionmodel.rst Message-ID: <20110109080438.1929FEEA19@mail.python.org> Author: georg.brandl Date: Sun Jan 9 09:04:37 2011 New Revision: 87889 Log: Hand-port parts of r87789. Modified: python/branches/release27-maint/Doc/library/inspect.rst python/branches/release27-maint/Doc/reference/executionmodel.rst Modified: python/branches/release27-maint/Doc/library/inspect.rst ============================================================================== --- python/branches/release27-maint/Doc/library/inspect.rst (original) +++ python/branches/release27-maint/Doc/library/inspect.rst Sun Jan 9 09:04:37 2011 @@ -234,14 +234,14 @@ Return a tuple of values that describe how Python will interpret the file identified by *path* if it is a module, or ``None`` if it would not be - identified as a module. The return tuple is ``(name, suffix, mode, mtype)``, - where *name* is the name of the module without the name of any enclosing - package, *suffix* is the trailing part of the file name (which may not be a - dot-delimited extension), *mode* is the :func:`open` mode that would be used - (``'r'`` or ``'rb'``), and *mtype* is an integer giving the type of the - module. *mtype* will have a value which can be compared to the constants - defined in the :mod:`imp` module; see the documentation for that module for - more information on module types. + identified as a module. The return tuple is ``(name, suffix, mode, + module_type)``, where *name* is the name of the module without the name of + any enclosing package, *suffix* is the trailing part of the file name (which + may not be a dot-delimited extension), *mode* is the :func:`open` mode that + would be used (``'r'`` or ``'rb'``), and *module_type* is an integer giving + the type of the module. *module_type* will have a value which can be + compared to the constants defined in the :mod:`imp` module; see the + documentation for that module for more information on module types. .. versionchanged:: 2.6 Returns a :term:`named tuple` ``ModuleInfo(name, suffix, mode, @@ -464,12 +464,13 @@ .. function:: getargspec(func) - Get the names and default values of a Python function's arguments. A tuple of four - things is returned: ``(args, varargs, varkw, defaults)``. *args* is a list of - the argument names (it may contain nested lists). *varargs* and *varkw* are the - names of the ``*`` and ``**`` arguments or ``None``. *defaults* is a tuple of - default argument values or None if there are no default arguments; if this tuple - has *n* elements, they correspond to the last *n* elements listed in *args*. + Get the names and default values of a Python function's arguments. A tuple of + four things is returned: ``(args, varargs, keywords, defaults)``. *args* is a + list of the argument names (it may contain nested lists). *varargs* and + *keywords* are the names of the ``*`` and ``**`` arguments or + ``None``. *defaults* is a tuple of default argument values or None if there + are no default arguments; if this tuple has *n* elements, they correspond to + the last *n* elements listed in *args*. .. versionchanged:: 2.6 Returns a :term:`named tuple` ``ArgSpec(args, varargs, keywords, @@ -478,11 +479,11 @@ .. function:: getargvalues(frame) - Get information about arguments passed into a particular frame. A tuple of four - things is returned: ``(args, varargs, varkw, locals)``. *args* is a list of the - argument names (it may contain nested lists). *varargs* and *varkw* are the - names of the ``*`` and ``**`` arguments or ``None``. *locals* is the locals - dictionary of the given frame. + Get information about arguments passed into a particular frame. A tuple of + four things is returned: ``(args, varargs, keywords, locals)``. *args* is a + list of the argument names (it may contain nested lists). *varargs* and + *keywords* are the names of the ``*`` and ``**`` arguments or ``None``. + *locals* is the locals dictionary of the given frame. .. versionchanged:: 2.6 Returns a :term:`named tuple` ``ArgInfo(args, varargs, keywords, Modified: python/branches/release27-maint/Doc/reference/executionmodel.rst ============================================================================== --- python/branches/release27-maint/Doc/reference/executionmodel.rst (original) +++ python/branches/release27-maint/Doc/reference/executionmodel.rst Sun Jan 9 09:04:37 2011 @@ -140,9 +140,9 @@ The namespace for a module is automatically created the first time a module is imported. The main module for a script is always called :mod:`__main__`. -The global statement has the same scope as a name binding operation in the same -block. If the nearest enclosing scope for a free variable contains a global -statement, the free variable is treated as a global. +The :keyword:`global` statement has the same scope as a name binding operation +in the same block. If the nearest enclosing scope for a free variable contains +a global statement, the free variable is treated as a global. A class definition is an executable statement that may use and define names. These references follow the normal rules for name resolution. The namespace of From python-checkins at python.org Sun Jan 9 10:04:08 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 10:04:08 +0100 (CET) Subject: [Python-checkins] r87890 - python/branches/py3k/Doc/library/argparse.rst Message-ID: <20110109090408.8FB81EE9D8@mail.python.org> Author: georg.brandl Date: Sun Jan 9 10:04:08 2011 New Revision: 87890 Log: Wrap some long examples and signatures. Modified: python/branches/py3k/Doc/library/argparse.rst Modified: python/branches/py3k/Doc/library/argparse.rst ============================================================================== --- python/branches/py3k/Doc/library/argparse.rst (original) +++ python/branches/py3k/Doc/library/argparse.rst Sun Jan 9 10:04:08 2011 @@ -120,7 +120,9 @@ ArgumentParser objects ---------------------- -.. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], [argument_default], [parents], [prefix_chars], [conflict_handler], [formatter_class]) +.. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], \ + [argument_default], [parents], [prefix_chars], \ + [conflict_handler], [formatter_class]) Create a new :class:`ArgumentParser` object. Each parameter has its own more detailed description below, but in short they are: @@ -563,7 +565,9 @@ The add_argument() method ------------------------- -.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], [const], [default], [type], [choices], [required], [help], [metavar], [dest]) +.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], \ + [const], [default], [type], [choices], [required], \ + [help], [metavar], [dest]) Define how a single command line argument should be parsed. Each parameter has its own more detailed description below, but in short they are: @@ -777,9 +781,11 @@ >>> parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'), ... default=sys.stdout) >>> parser.parse_args(['input.txt', 'output.txt']) - Namespace(infile=, outfile=) + Namespace(infile=, + outfile=) >>> parser.parse_args([]) - Namespace(infile=', mode 'r' at 0x...>, outfile=', mode 'w' at 0x...>) + Namespace(infile=', mode 'r' at 0x...>, + outfile=', mode 'w' at 0x...>) * ``'*'``. All command-line args present are gathered into a list. Note that it generally doesn't make much sense to have more than one positional argument @@ -1753,11 +1759,12 @@ A partial upgrade path from optparse to argparse: -* Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` calls. +* Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` + calls. * Replace ``options, args = parser.parse_args()`` with ``args = - parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` calls for the - positional arguments. + parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` + calls for the positional arguments. * Replace callback actions and the ``callback_*`` keyword arguments with ``type`` or ``action`` arguments. From python-checkins at python.org Sun Jan 9 10:31:01 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 10:31:01 +0100 (CET) Subject: [Python-checkins] r87891 - python/branches/py3k/Doc/library/argparse.rst Message-ID: <20110109093101.D92ADEE98A@mail.python.org> Author: georg.brandl Date: Sun Jan 9 10:31:01 2011 New Revision: 87891 Log: #10871: "file" does not exist anymore in Python 3. Also adapt the reprs of opened file objects. Modified: python/branches/py3k/Doc/library/argparse.rst Modified: python/branches/py3k/Doc/library/argparse.rst ============================================================================== --- python/branches/py3k/Doc/library/argparse.rst (original) +++ python/branches/py3k/Doc/library/argparse.rst Sun Jan 9 10:31:01 2011 @@ -781,11 +781,11 @@ >>> parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'), ... default=sys.stdout) >>> parser.parse_args(['input.txt', 'output.txt']) - Namespace(infile=, - outfile=) + Namespace(infile=<_io.TextIOWrapper name='input.txt' encoding='UTF-8'>, + outfile=<_io.TextIOWrapper name='output.txt' encoding='UTF-8'>) >>> parser.parse_args([]) - Namespace(infile=', mode 'r' at 0x...>, - outfile=', mode 'w' at 0x...>) + Namespace(infile=<_io.TextIOWrapper name='' encoding='UTF-8'>, + outfile=<_io.TextIOWrapper name='' encoding='UTF-8'>) * ``'*'``. All command-line args present are gathered into a list. Note that it generally doesn't make much sense to have more than one positional argument @@ -881,26 +881,26 @@ By default, ArgumentParser objects read command-line args in as simple strings. However, quite often the command-line string should instead be interpreted as -another type, like a :class:`float`, :class:`int` or :class:`file`. The -``type`` keyword argument of :meth:`add_argument` allows any necessary -type-checking and type-conversions to be performed. Many common built-in types -can be used directly as the value of the ``type`` argument:: +another type, like a :class:`float` or :class:`int`. The ``type`` keyword +argument of :meth:`add_argument` allows any necessary type-checking and +type-conversions to be performed. Common built-in types and functions can be +used directly as the value of the ``type`` argument:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('foo', type=int) - >>> parser.add_argument('bar', type=file) + >>> parser.add_argument('bar', type=open) >>> parser.parse_args('2 temp.txt'.split()) - Namespace(bar=, foo=2) + Namespace(bar=<_io.TextIOWrapper name='temp.txt' encoding='UTF-8'>, foo=2) To ease the use of various types of files, the argparse module provides the factory FileType which takes the ``mode=`` and ``bufsize=`` arguments of the -``file`` object. For example, ``FileType('w')`` can be used to create a +:func:`open` function. For example, ``FileType('w')`` can be used to create a writable file:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('bar', type=argparse.FileType('w')) >>> parser.parse_args(['out.txt']) - Namespace(bar=) + Namespace(bar=<_io.TextIOWrapper name='out.txt' encoding='UTF-8'>) ``type=`` can take any callable that takes a single string argument and returns the type-converted value:: @@ -1512,7 +1512,7 @@ >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--output', type=argparse.FileType('wb', 0)) >>> parser.parse_args(['--output', 'out']) - Namespace(output=) + Namespace(output=<_io.BufferedWriter name='out'>) FileType objects understand the pseudo-argument ``'-'`` and automatically convert this into ``sys.stdin`` for readable :class:`FileType` objects and @@ -1521,7 +1521,7 @@ >>> parser = argparse.ArgumentParser() >>> parser.add_argument('infile', type=argparse.FileType('r')) >>> parser.parse_args(['-']) - Namespace(infile=', mode 'r' at 0x...>) + Namespace(infile=<_io.TextIOWrapper name='' encoding='UTF-8'>) Argument groups From python-checkins at python.org Sun Jan 9 10:33:09 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 10:33:09 +0100 (CET) Subject: [Python-checkins] r87892 - in python/branches/release27-maint: Doc/library/argparse.rst Message-ID: <20110109093309.ED5FFEE98A@mail.python.org> Author: georg.brandl Date: Sun Jan 9 10:33:09 2011 New Revision: 87892 Log: Merged revisions 87890 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87890 | georg.brandl | 2011-01-09 10:04:08 +0100 (So, 09 Jan 2011) | 1 line Wrap some long examples and signatures. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Doc/library/argparse.rst Modified: python/branches/release27-maint/Doc/library/argparse.rst ============================================================================== --- python/branches/release27-maint/Doc/library/argparse.rst (original) +++ python/branches/release27-maint/Doc/library/argparse.rst Sun Jan 9 10:33:09 2011 @@ -120,7 +120,9 @@ ArgumentParser objects ---------------------- -.. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], [argument_default], [parents], [prefix_chars], [conflict_handler], [formatter_class]) +.. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], \ + [argument_default], [parents], [prefix_chars], \ + [conflict_handler], [formatter_class]) Create a new :class:`ArgumentParser` object. Each parameter has its own more detailed description below, but in short they are: @@ -563,7 +565,9 @@ The add_argument() method ------------------------- -.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], [const], [default], [type], [choices], [required], [help], [metavar], [dest]) +.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], \ + [const], [default], [type], [choices], [required], \ + [help], [metavar], [dest]) Define how a single command line argument should be parsed. Each parameter has its own more detailed description below, but in short they are: @@ -777,9 +781,11 @@ >>> parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'), ... default=sys.stdout) >>> parser.parse_args(['input.txt', 'output.txt']) - Namespace(infile=, outfile=) + Namespace(infile=, + outfile=) >>> parser.parse_args([]) - Namespace(infile=', mode 'r' at 0x...>, outfile=', mode 'w' at 0x...>) + Namespace(infile=', mode 'r' at 0x...>, + outfile=', mode 'w' at 0x...>) * ``'*'``. All command-line args present are gathered into a list. Note that it generally doesn't make much sense to have more than one positional argument @@ -1744,11 +1750,12 @@ A partial upgrade path from optparse to argparse: -* Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` calls. +* Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` + calls. * Replace ``options, args = parser.parse_args()`` with ``args = - parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` calls for the - positional arguments. + parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` + calls for the positional arguments. * Replace callback actions and the ``callback_*`` keyword arguments with ``type`` or ``action`` arguments. From python-checkins at python.org Sun Jan 9 10:33:18 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 10:33:18 +0100 (CET) Subject: [Python-checkins] r87893 - python/branches/release31-maint Message-ID: <20110109093318.C7A0BEEA83@mail.python.org> Author: georg.brandl Date: Sun Jan 9 10:33:18 2011 New Revision: 87893 Log: Blocked revisions 87890-87891 via svnmerge ........ r87890 | georg.brandl | 2011-01-09 10:04:08 +0100 (So, 09 Jan 2011) | 1 line Wrap some long examples and signatures. ........ r87891 | georg.brandl | 2011-01-09 10:31:01 +0100 (So, 09 Jan 2011) | 1 line #10871: "file" does not exist anymore in Python 3. Also adapt the reprs of opened file objects. ........ Modified: python/branches/release31-maint/ (props changed) From python-checkins at python.org Sun Jan 9 10:33:24 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 9 Jan 2011 10:33:24 +0100 (CET) Subject: [Python-checkins] r87894 - python/branches/release27-maint Message-ID: <20110109093324.5B7E7EEAB4@mail.python.org> Author: georg.brandl Date: Sun Jan 9 10:33:24 2011 New Revision: 87894 Log: Blocked revisions 87891 via svnmerge ........ r87891 | georg.brandl | 2011-01-09 10:31:01 +0100 (So, 09 Jan 2011) | 1 line #10871: "file" does not exist anymore in Python 3. Also adapt the reprs of opened file objects. ........ Modified: python/branches/release27-maint/ (props changed) From python-checkins at python.org Sun Jan 9 19:18:53 2011 From: python-checkins at python.org (lukasz.langa) Date: Sun, 9 Jan 2011 19:18:53 +0100 (CET) Subject: [Python-checkins] r87895 - python/branches/py3k/Lib/test/test_urllib2.py Message-ID: <20110109181853.CE9FFEE9A0@mail.python.org> Author: lukasz.langa Date: Sun Jan 9 19:18:53 2011 New Revision: 87895 Log: #10874: test_urllib2 shouldn't use `is` operator for comparing strings Patch by Adreas St?hrk. Modified: python/branches/py3k/Lib/test/test_urllib2.py Modified: python/branches/py3k/Lib/test/test_urllib2.py ============================================================================== --- python/branches/py3k/Lib/test/test_urllib2.py (original) +++ python/branches/py3k/Lib/test/test_urllib2.py Sun Jan 9 19:18:53 2011 @@ -758,7 +758,7 @@ else: self.assertIs(o.req, req) self.assertEqual(req.type, "ftp") - self.assertEqual(req.type is "ftp", ftp) + self.assertEqual(req.type == "ftp", ftp) def test_http(self): From python-checkins at python.org Sun Jan 9 19:28:07 2011 From: python-checkins at python.org (martin.v.loewis) Date: Sun, 9 Jan 2011 19:28:07 +0100 (CET) Subject: [Python-checkins] r87896 - python/branches/py3k/Misc/developers.txt Message-ID: <20110109182807.64660EFBC@mail.python.org> Author: martin.v.loewis Date: Sun Jan 9 19:28:07 2011 New Revision: 87896 Log: Add Ned Deily. Modified: python/branches/py3k/Misc/developers.txt Modified: python/branches/py3k/Misc/developers.txt ============================================================================== --- python/branches/py3k/Misc/developers.txt (original) +++ python/branches/py3k/Misc/developers.txt Sun Jan 9 19:28:07 2011 @@ -23,6 +23,9 @@ Permissions History ------------------- +- Ned Deily was given commit access on Jan 9 2011 by MvL, + on recommendation by Antoine Pitrou. + - David Malcolm was given commit access on Oct 27 2010 by GFB, at recommendation by Antoine Pitrou and Raymond Hettinger. From python-checkins at python.org Sun Jan 9 21:38:15 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sun, 9 Jan 2011 21:38:15 +0100 (CET) Subject: [Python-checkins] r87897 - in python/branches/py3k: Lib/_pyio.py Lib/test/test_io.py Misc/NEWS Modules/_io/textio.c Message-ID: <20110109203815.AD832EE98B@mail.python.org> Author: antoine.pitrou Date: Sun Jan 9 21:38:15 2011 New Revision: 87897 Log: Issue #10872: The repr() of TextIOWrapper objects now includes the mode if available. (at Georg's request) Modified: python/branches/py3k/Lib/_pyio.py python/branches/py3k/Lib/test/test_io.py python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/_io/textio.c Modified: python/branches/py3k/Lib/_pyio.py ============================================================================== --- python/branches/py3k/Lib/_pyio.py (original) +++ python/branches/py3k/Lib/_pyio.py Sun Jan 9 21:38:15 2011 @@ -1504,13 +1504,20 @@ # - "chars_..." for integer variables that count decoded characters def __repr__(self): + result = "<_pyio.TextIOWrapper" try: name = self.name except AttributeError: - return "<_pyio.TextIOWrapper encoding={0!r}>".format(self.encoding) + pass + else: + result += " name={0!r}".format(name) + try: + mode = self.mode + except AttributeError: + pass else: - return "<_pyio.TextIOWrapper name={0!r} encoding={1!r}>".format( - name, self.encoding) + result += " mode={0!r}".format(mode) + return result + " encoding={0!r}>".format(self.encoding) @property def encoding(self): Modified: python/branches/py3k/Lib/test/test_io.py ============================================================================== --- python/branches/py3k/Lib/test/test_io.py (original) +++ python/branches/py3k/Lib/test/test_io.py Sun Jan 9 21:38:15 2011 @@ -1717,9 +1717,12 @@ raw.name = "dummy" self.assertEqual(repr(t), "<%s.TextIOWrapper name='dummy' encoding='utf-8'>" % modname) + t.mode = "r" + self.assertEqual(repr(t), + "<%s.TextIOWrapper name='dummy' mode='r' encoding='utf-8'>" % modname) raw.name = b"dummy" self.assertEqual(repr(t), - "<%s.TextIOWrapper name=b'dummy' encoding='utf-8'>" % modname) + "<%s.TextIOWrapper name=b'dummy' mode='r' encoding='utf-8'>" % modname) def test_line_buffering(self): r = self.BytesIO() Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sun Jan 9 21:38:15 2011 @@ -40,6 +40,9 @@ Library ------- +- Issue #10872: The repr() of TextIOWrapper objects now includes the mode + if available. + - Issue #10869: Fixed bug where ast.increment_lineno modified the root node twice. Modified: python/branches/py3k/Modules/_io/textio.c ============================================================================== --- python/branches/py3k/Modules/_io/textio.c (original) +++ python/branches/py3k/Modules/_io/textio.c Sun Jan 9 21:38:15 2011 @@ -2323,25 +2323,52 @@ static PyObject * textiowrapper_repr(textio *self) { - PyObject *nameobj, *res; + PyObject *nameobj, *modeobj, *res, *s; CHECK_INITIALIZED(self); + res = PyUnicode_FromString("<_io.TextIOWrapper"); + if (res == NULL) + return NULL; nameobj = PyObject_GetAttrString((PyObject *) self, "name"); if (nameobj == NULL) { if (PyErr_ExceptionMatches(PyExc_AttributeError)) PyErr_Clear(); else - return NULL; - res = PyUnicode_FromFormat("<_io.TextIOWrapper encoding=%R>", - self->encoding); + goto error; } else { - res = PyUnicode_FromFormat("<_io.TextIOWrapper name=%R encoding=%R>", - nameobj, self->encoding); + s = PyUnicode_FromFormat(" name=%R", nameobj); Py_DECREF(nameobj); + if (s == NULL) + goto error; + PyUnicode_AppendAndDel(&res, s); + if (res == NULL) + return NULL; } - return res; + modeobj = PyObject_GetAttrString((PyObject *) self, "mode"); + if (modeobj == NULL) { + if (PyErr_ExceptionMatches(PyExc_AttributeError)) + PyErr_Clear(); + else + goto error; + } + else { + s = PyUnicode_FromFormat(" mode=%R", modeobj); + Py_DECREF(modeobj); + if (s == NULL) + goto error; + PyUnicode_AppendAndDel(&res, s); + if (res == NULL) + return NULL; + } + s = PyUnicode_FromFormat("%U encoding=%R>", + res, self->encoding); + Py_DECREF(res); + return s; +error: + Py_XDECREF(res); + return NULL; } From python-checkins at python.org Mon Jan 10 02:03:55 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 02:03:55 +0100 Subject: [Python-checkins] devguide: Merge intermediate and advanced issues into a single advanced one. Message-ID: brett.cannon pushed dd5a2f58ba52 to devguide: http://hg.python.org/devguide/rev/dd5a2f58ba52 changeset: 60:dd5a2f58ba52 user: Brett Cannon date: Sun Jan 09 16:57:45 2011 -0800 summary: Merge intermediate and advanced issues into a single advanced one. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -35,16 +35,15 @@ * Beginner tasks to become familiar with the development process * :ref:`coverage` * :ref:`docquality` -* Intermediate tasks for once you are comfortable +* Advanced tasks for once you are comfortable + * Fixing issues found by the buildbots_ + * :ref:`silencewarnings` + * :ref:`fixingissues` * :ref:`helptriage` * `Gaining 'Developer' privileges for the issue tracker `_ * `Triaging issues `_ * `Reviewing patches `_ * `Following Python's development `_ -* Advanced tasks - * Fixing issues found by the buildbots_ - * :ref:`silencewarnings` - * :ref:`fixingissues` * `Gaining commit privileges `_ * `Committing patches `_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 02:03:56 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 02:03:56 +0100 Subject: [Python-checkins] devguide: Remove some redundant planned docs. Message-ID: brett.cannon pushed ffd1ba047da4 to devguide: http://hg.python.org/devguide/rev/ffd1ba047da4 changeset: 61:ffd1ba047da4 tag: tip user: Brett Cannon date: Sun Jan 09 17:03:47 2011 -0800 summary: Remove some redundant planned docs. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -41,8 +41,6 @@ * :ref:`fixingissues` * :ref:`helptriage` * `Gaining 'Developer' privileges for the issue tracker `_ - * `Triaging issues `_ - * `Reviewing patches `_ * `Following Python's development `_ * `Gaining commit privileges `_ * `Committing patches `_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 02:24:12 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 02:24:12 +0100 Subject: [Python-checkins] devguide: Tweak the order of the chapters. Message-ID: brett.cannon pushed b5cdd1c14c8f to devguide: http://hg.python.org/devguide/rev/b5cdd1c14c8f changeset: 62:b5cdd1c14c8f user: Brett Cannon date: Sun Jan 09 17:04:24 2011 -0800 summary: Tweak the order of the chapters. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -9,9 +9,9 @@ runtests coverage docquality + silencewarnings + fixingissues helptriage - fixingissues - silencewarnings .. todolist:: -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 02:24:13 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 02:24:13 +0100 Subject: [Python-checkins] devguide: Clarify what is needed to help triage. Message-ID: brett.cannon pushed 4574f0385eb2 to devguide: http://hg.python.org/devguide/rev/4574f0385eb2 changeset: 63:4574f0385eb2 user: Brett Cannon date: Sun Jan 09 17:08:05 2011 -0800 summary: Clarify what is needed to help triage. files: helptriage.rst diff --git a/helptriage.rst b/helptriage.rst --- a/helptriage.rst +++ b/helptriage.rst @@ -3,9 +3,10 @@ Helping Triage Issues ===================== -Once you know your way a little bit around how Python's source files are +Once you know your way around how Python's source files are structured and you are comfortable working with patches, a great way to -participate is to help triage issues. +participate is to help triage issues. Do realize, though, that experience +working on Python is needed in order to affectively help triage. On a daily basis, issues get reported on the `issue tracker`_. Each and every issue needs to be triaged to make sure various things are in proper order. Even @@ -22,16 +23,17 @@ * What version(s) of Python are affected by the bug are fully known * Is there a proper unit test that can reproduce the bug? -These are things anyone can help with. For instance, if a bug is not clearly -explained enough for you to reproduce it then there is a good chance a core -developer won't be able to either. And it is always helpful to know if a bug -not only affects the in-development version of Python, but whether it also -affects other versions in maintenance mode. And if the bug lacks a unit test -that should end up in Python's test suite, having that written can be very -helpful. +These are things you can help with once you have experience developing for +Python. For instance, if a bug is not clearly explained enough for you to +reproduce it then there is a good chance a core developer won't be able to +either. And it is always helpful to know if a bug not only affects the +in-development version of Python, but whether it also affects other versions in +maintenance mode. And if the bug lacks a unit test that should end up in +Python's test suite, having that written can be very helpful. -This is all helpful as it allows triagers to properly classify an issue so it -can be handled by the right people in a timely fashion. +This is all helpful as it allows triagers (i.e., people with Developer +privileges on the issue tracker) to properly classify an issue so it +can be handled by the right core developers in a timely fashion. Patches -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 02:24:14 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 02:24:14 +0100 Subject: [Python-checkins] devguide: Possible item about helping marking issues as languishing. Message-ID: brett.cannon pushed 8d54904007f9 to devguide: http://hg.python.org/devguide/rev/8d54904007f9 changeset: 64:8d54904007f9 user: Brett Cannon date: Sun Jan 09 17:09:33 2011 -0800 summary: Possible item about helping marking issues as languishing. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -41,6 +41,7 @@ * :ref:`fixingissues` * :ref:`helptriage` * `Gaining 'Developer' privileges for the issue tracker `_ + * `Marking issues as languishing `_ * `Following Python's development `_ * `Gaining commit privileges `_ * `Committing patches `_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 02:24:14 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 02:24:14 +0100 Subject: [Python-checkins] devguide: Placeholder for docs covering how to gain the Developer role on the tracker. Message-ID: brett.cannon pushed 250a8a8e79e6 to devguide: http://hg.python.org/devguide/rev/250a8a8e79e6 changeset: 65:250a8a8e79e6 user: Brett Cannon date: Sun Jan 09 17:14:36 2011 -0800 summary: Placeholder for docs covering how to gain the Developer role on the tracker. files: devrole.rst helptriage.rst index.rst triage.rst diff --git a/devrole.rst b/devrole.rst new file mode 100644 --- /dev/null +++ b/devrole.rst @@ -0,0 +1,6 @@ +.. _devrole: + +Gaining the 'Developer' Role on the Issue Tracker +================================================= + +XXX diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -11,7 +11,8 @@ docquality silencewarnings fixingissues - helptriage + triage + devrole .. todolist:: @@ -39,8 +40,8 @@ * Fixing issues found by the buildbots_ * :ref:`silencewarnings` * :ref:`fixingissues` - * :ref:`helptriage` -* `Gaining 'Developer' privileges for the issue tracker `_ + * :ref:`triage` +* :ref:`devrole` * `Marking issues as languishing `_ * `Following Python's development `_ * `Gaining commit privileges `_ diff --git a/helptriage.rst b/triage.rst rename from helptriage.rst rename to triage.rst --- a/helptriage.rst +++ b/triage.rst @@ -1,4 +1,4 @@ -.. _helptriage: +.. _triage: Helping Triage Issues ===================== @@ -31,9 +31,10 @@ maintenance mode. And if the bug lacks a unit test that should end up in Python's test suite, having that written can be very helpful. -This is all helpful as it allows triagers (i.e., people with Developer -privileges on the issue tracker) to properly classify an issue so it -can be handled by the right core developers in a timely fashion. +This is all helpful as it allows triagers (i.e., +:ref:`people with the Developer role on the issue tracker `) to +properly classify an issue so it can be handled by the right core developers in +a timely fashion. Patches @@ -49,9 +50,9 @@ * The proper documentation changes are included * The person is listed in ``Misc/ACKS``, either already or the patches add them -Doing all of this allows core developers and triagers to more quickly look for -subtle issues that only people with extensive experience working on Python's -code base will notice. +Doing all of this allows core developers and :ref:`triagers ` to more +quickly look for subtle issues that only people with extensive experience +working on Python's code base will notice. There is a complete list of `open issues with patches`_, although to make sure that someone has not already done the checklist above as it is possible the -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 02:24:15 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 02:24:15 +0100 Subject: [Python-checkins] devguide: Explain what the Developer role is. Message-ID: brett.cannon pushed b20c907554f6 to devguide: http://hg.python.org/devguide/rev/b20c907554f6 changeset: 66:b20c907554f6 tag: tip user: Brett Cannon date: Sun Jan 09 17:24:06 2011 -0800 summary: Explain what the Developer role is. files: devrole.rst diff --git a/devrole.rst b/devrole.rst --- a/devrole.rst +++ b/devrole.rst @@ -1,6 +1,24 @@ .. _devrole: -Gaining the 'Developer' Role on the Issue Tracker +Gaining the "Developer" Role on the Issue Tracker ================================================= -XXX +When you have consistently shown the ability to properly +:ref:`help triage issues ` without guidance, you may request that you +be given the "Developer" role on the `issue tracker`_. You can make the request +of any person who already has the Developer role. If they decide you are ready +to gain the extra privileges on the tracker they will then act as a mentor to +you until you are ready to do things entirely on your own. There is no set rule +as to how many issues you need to have helped with before or how long you have +been participating. The key requirements are that you show the desire to +help, you are able to work well with others (especially those already with the +Developer role), and that have a firm grasp of how to do things on the issue +tracker properly on your own. + +Gaining the Developer role will allow you to set any value on any issue in the +tracker, releasing you from the burden of having to ask others to set values on +an issue for you in order to properly triage something. This will not only help +speed up and simplify your work in helping out, but also help lesson the +workload for everyone by gaining your help. + +.. _issue tracker: http://bugs.python.org -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 02:28:01 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 02:28:01 +0100 Subject: [Python-checkins] devguide: Add some resource links that were originally in the dev FAQ. Message-ID: brett.cannon pushed 758d7636be04 to devguide: http://hg.python.org/devguide/rev/758d7636be04 changeset: 67:758d7636be04 user: Brett Cannon date: Sun Jan 09 17:27:37 2011 -0800 summary: Add some resource links that were originally in the dev FAQ. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -67,6 +67,9 @@ * `Meta tracker `_ (issue tracker for the issue tracker) * Buildbots_ +* Source code + * `Browse online `_ + * `Daily snapshot `_ .. todo:: move various files out of Misc to here (e.g., README.valgrind, -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 02:28:03 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 02:28:03 +0100 Subject: [Python-checkins] devguide: Remove some more from my tracking copy of the dev FAQ. Message-ID: brett.cannon pushed 3140263cbf1f to devguide: http://hg.python.org/devguide/rev/3140263cbf1f changeset: 68:3140263cbf1f tag: tip user: Brett Cannon date: Sun Jan 09 17:27:56 2011 -0800 summary: Remove some more from my tracking copy of the dev FAQ. files: faq.rst diff --git a/faq.rst b/faq.rst --- a/faq.rst +++ b/faq.rst @@ -105,20 +105,6 @@ =========== ============================================================== ========================================================================== - -How do I browse the source code through a web browser? -------------------------------------------------------------------------------- - -Visit http://svn.python.org/view/ to browse the Subversion repository. - - -Where can I find a downloadable snapshot of the source code? -------------------------------------------------------------------------------- - -Visit http://svn.python.org/snapshots/ to download a tarball containing a daily -snapshot of the repository. - - Who has commit privileges on the Subversion repository? ------------------------------------------------------------------------------- @@ -319,19 +305,6 @@ Patches ===================================================================== -How to make a patch? -------------------------- - - -If you are using subversion (anonymous or developer) you can use -subversion to make the patches for you. Just edit your local copy and -enter the following command:: - - svn diff | tee ~/name_of_the_patch.diff - -Else you can use the diff util which comes with most operating systems (a -Windows version is available as part of the cygwin tools). - How do I apply a patch? ------------------------- @@ -358,79 +331,3 @@ use. -How to submit a patch? ---------------------------- - -Please consult the patch submission guidelines at -http://www.python.org/patches/ . - - -How to test a patch? ------------------------------- - -Firstly, you'll need to get a checkout of the source tree you wish to -test the patch against and then build python from this source tree. - -Once you've done that, you can use Python's extensive regression test -suite to check that the patch hasn't broken anything. - -In general, for thorough testing, use:: - - python -m test.regrtest -uall - -For typical testing use:: - - python -m test.regrtest - -For running specific test modules:: - - python -m test.regrtest test_mod1 test_mod2 - -NB: Enabling the relevant test resources via ``-uall`` or something more -specific is especially important when working on things like the -networking code or the audio support - many of the relevant tests are -skipped by default. - -For more thorough documentation, -read the documentation for the ``test`` package at -http://docs.python.org/library/test.html. - -If you suspect the patch may impact other operating systems, test as -many as you have easy access to. You can get help on alternate -platforms by contacting the people listed on -http://www.python.org/moin/PythonTesters, who have -volunteered to support a particular operating system. - - -How to change the status of a patch? ------------------------------------------ - - -To change the status of a patch or assign it to somebody else you have to -have the Developer role in the bug tracker. Contact one of the project -administrators if the following does not work for you. - -Click on the patch itself. In the screen that comes up, there is a drop-box -for "Assigned To:" and a drop-box for "Status:" where you can select a new -responsible developer or a new status respectively. After selecting the -appropriate victim and status, hit the "Submit Changes" button at the bottom -of the page. - -Note: If you are sure that you have the right permissions and a drop-box -does not appear, check that you are actually logged in to Roundup! - - -Bugs -===================================================================== - -Where can I submit/view bugs for Python? ---------------------------------------------- - - -The Python project uses Roundup for bug tracking. Go to -http://bugs.python.org/ for all bug management needs. You will need to -create a Roundup account for yourself before submitting the first bug -report; anonymous reports have been disabled since it was too -difficult to get in contact with submitters. If you previously -had used SourceForge to report Python bugs, you can use Roundup's -"Lost your login?" link to obtain your Roundup password. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 03:14:11 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 03:14:11 +0100 Subject: [Python-checkins] devguide: Start a doc on marking issues as languishing. Message-ID: brett.cannon pushed fd414c42d80e to devguide: http://hg.python.org/devguide/rev/fd414c42d80e changeset: 69:fd414c42d80e user: Brett Cannon date: Sun Jan 09 17:36:13 2011 -0800 summary: Start a doc on marking issues as languishing. files: index.rst languishing.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -13,6 +13,7 @@ fixingissues triage devrole + languishing .. todolist:: @@ -42,7 +43,7 @@ * :ref:`fixingissues` * :ref:`triage` * :ref:`devrole` - * `Marking issues as languishing `_ + * :ref:`languishing` * `Following Python's development `_ * `Gaining commit privileges `_ * `Committing patches `_ diff --git a/languishing.rst b/languishing.rst new file mode 100644 --- /dev/null +++ b/languishing.rst @@ -0,0 +1,4 @@ +.. _languishing: + +Marking Issues as "Languishing" +=============================== -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 03:14:12 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 03:14:12 +0100 Subject: [Python-checkins] devguide: Tweak a section title. Message-ID: brett.cannon pushed d081789fae6b to devguide: http://hg.python.org/devguide/rev/d081789fae6b changeset: 70:d081789fae6b user: Brett Cannon date: Sun Jan 09 17:36:37 2011 -0800 summary: Tweak a section title. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -49,8 +49,8 @@ * `Committing patches `_ -Making changes to Python itself -------------------------------- +Proposing changes to Python itself +---------------------------------- * `Changing something already in the stdlib `_ * Adding to the stdblib -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 03:14:12 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 03:14:12 +0100 Subject: [Python-checkins] devguide: Make the wording about the order of the docs stronger and re-arrange Message-ID: brett.cannon pushed 4c5802cc45d1 to devguide: http://hg.python.org/devguide/rev/4c5802cc45d1 changeset: 71:4c5802cc45d1 user: Brett Cannon date: Sun Jan 09 17:45:57 2011 -0800 summary: Make the wording about the order of the docs stronger and re-arrange things to go from easier to harder within sub-bullets. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -23,10 +23,10 @@ ------------ People who wish to contribute to Python **must** read the following documents -in their top-level order (sub-level documents can be read in any order). You -can stop where you feel comfortable and begin contributing without reading and -understanding all of these documents, but please do not skip around within the -documentation. +in the order provided. +You can stop where you feel comfortable and begin contributing immediately +without reading and understanding these documents all at once, but please do +not skip around within the documentation. * :ref:`setup` * Coding style guides @@ -35,11 +35,11 @@ * :ref:`patch` * :ref:`runtests` * Beginner tasks to become familiar with the development process + * :ref:`docquality` * :ref:`coverage` - * :ref:`docquality` * Advanced tasks for once you are comfortable + * :ref:`silencewarnings` * Fixing issues found by the buildbots_ - * :ref:`silencewarnings` * :ref:`fixingissues` * :ref:`triage` * :ref:`devrole` -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 03:14:13 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 03:14:13 +0100 Subject: [Python-checkins] devguide: Fill in details on how to handle languishing issues. Message-ID: brett.cannon pushed 5b093d79a8f4 to devguide: http://hg.python.org/devguide/rev/5b093d79a8f4 changeset: 72:5b093d79a8f4 tag: tip user: Brett Cannon date: Sun Jan 09 18:14:05 2011 -0800 summary: Fill in details on how to handle languishing issues. files: languishing.rst diff --git a/languishing.rst b/languishing.rst --- a/languishing.rst +++ b/languishing.rst @@ -2,3 +2,25 @@ Marking Issues as "Languishing" =============================== + +Sometimes an issue has no clear answer. It can be because core developers +cannot agree on the proper solution (or if a problem even exists). Other +times a solution is agreed upon but writing the code for the solution would +take too much effort for little gain, and so no one wants to do the work (or +would simply break too much pre-existing code without a different solution. + +In these cases an issue will languish_ in the `issue tracker`_. In the case of +an issue that is languishing, it should have its status set as such. This +serves the purpose of preventing people who are trying to :ref:`fix issues +` from wasting time on issues that even core developers cannot +come up with an agreed-upon solution for. + +A good way to tell if an issue is languishing is based on whether an issue had +an in-depth discussion that stalled several months ago. In that instance it is +typically safe to set the status of the issue to "languishing". If you are +unsure you can always leave a comment on the issue asking if others agree that +it is languishing. + + +.. _issue tracker: http://bugs.python.org +.. _languish: http://bugs.python.org/issue?@columns=title,id,activity,status&@sort=activity&@group=priority&@filter=status&@pagesize=50&@startwith=0&status=4&@dispname=Languishing -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 04:26:09 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 10 Jan 2011 04:26:09 +0100 (CET) Subject: [Python-checkins] r87898 - in python/branches/py3k/Doc/library: ast.rst bisect.rst calendar.rst cmd.rst collections.rst contextlib.rst dis.rst filecmp.rst fileinput.rst fnmatch.rst glob.rst heapq.rst keyword.rst linecache.rst pprint.rst queue.rst random.rst sched.rst shelve.rst shutil.rst string.rst textwrap.rst threading.rst tokenize.rst trace.rst uu.rst Message-ID: <20110110032609.512D8EE98E@mail.python.org> Author: raymond.hettinger Date: Mon Jan 10 04:26:08 2011 New Revision: 87898 Log: Move source links to consistent location and remove wordy, big yellow boxes. Modified: python/branches/py3k/Doc/library/ast.rst python/branches/py3k/Doc/library/bisect.rst python/branches/py3k/Doc/library/calendar.rst python/branches/py3k/Doc/library/cmd.rst python/branches/py3k/Doc/library/collections.rst python/branches/py3k/Doc/library/contextlib.rst python/branches/py3k/Doc/library/dis.rst python/branches/py3k/Doc/library/filecmp.rst python/branches/py3k/Doc/library/fileinput.rst python/branches/py3k/Doc/library/fnmatch.rst python/branches/py3k/Doc/library/glob.rst python/branches/py3k/Doc/library/heapq.rst python/branches/py3k/Doc/library/keyword.rst python/branches/py3k/Doc/library/linecache.rst python/branches/py3k/Doc/library/pprint.rst python/branches/py3k/Doc/library/queue.rst python/branches/py3k/Doc/library/random.rst python/branches/py3k/Doc/library/sched.rst python/branches/py3k/Doc/library/shelve.rst python/branches/py3k/Doc/library/shutil.rst python/branches/py3k/Doc/library/string.rst python/branches/py3k/Doc/library/textwrap.rst python/branches/py3k/Doc/library/threading.rst python/branches/py3k/Doc/library/tokenize.rst python/branches/py3k/Doc/library/trace.rst python/branches/py3k/Doc/library/uu.rst Modified: python/branches/py3k/Doc/library/ast.rst ============================================================================== --- python/branches/py3k/Doc/library/ast.rst (original) +++ python/branches/py3k/Doc/library/ast.rst Mon Jan 10 04:26:08 2011 @@ -7,6 +7,7 @@ .. sectionauthor:: Martin v. L?wis .. sectionauthor:: Georg Brandl +**Source code:** :source:`Lib/ast.py` The :mod:`ast` module helps Python applications to process trees of the Python abstract syntax grammar. The abstract syntax itself might change with each @@ -19,9 +20,6 @@ classes all inherit from :class:`ast.AST`. An abstract syntax tree can be compiled into a Python code object using the built-in :func:`compile` function. -.. seealso:: - - Latest version of the :source:`ast module Python source code ` Node classes ------------ Modified: python/branches/py3k/Doc/library/bisect.rst ============================================================================== --- python/branches/py3k/Doc/library/bisect.rst (original) +++ python/branches/py3k/Doc/library/bisect.rst Mon Jan 10 04:26:08 2011 @@ -7,6 +7,8 @@ .. sectionauthor:: Raymond Hettinger .. example based on the PyModules FAQ entry by Aaron Watters +**Source code:** :source:`Lib/bisect.py` + This module provides support for maintaining a list in sorted order without having to sort the list after each insertion. For long lists of items with expensive comparison operations, this can be an improvement over the more common @@ -14,11 +16,6 @@ algorithm to do its work. The source code may be most useful as a working example of the algorithm (the boundary conditions are already right!). -.. seealso:: - - Latest version of the :source:`bisect module Python source code - ` - The following functions are provided: Modified: python/branches/py3k/Doc/library/calendar.rst ============================================================================== --- python/branches/py3k/Doc/library/calendar.rst (original) +++ python/branches/py3k/Doc/library/calendar.rst Mon Jan 10 04:26:08 2011 @@ -6,6 +6,7 @@ of the Unix cal program. .. sectionauthor:: Drew Csillag +**Source code:** :source:`Lib/calendar.py` This module allows you to output calendars like the Unix :program:`cal` program, and provides additional useful functions related to the calendar. By default, @@ -309,6 +310,3 @@ Module :mod:`time` Low-level time related functions. - - Latest version of the :source:`calendar module Python source code - ` Modified: python/branches/py3k/Doc/library/cmd.rst ============================================================================== --- python/branches/py3k/Doc/library/cmd.rst (original) +++ python/branches/py3k/Doc/library/cmd.rst Mon Jan 10 04:26:08 2011 @@ -5,16 +5,13 @@ :synopsis: Build line-oriented command interpreters. .. sectionauthor:: Eric S. Raymond +**Source code:** :source:`Lib/cmd.py` The :class:`Cmd` class provides a simple framework for writing line-oriented command interpreters. These are often useful for test harnesses, administrative tools, and prototypes that will later be wrapped in a more sophisticated interface. -.. seealso:: - - Latest version of the :source:`cmd module Python source code ` - .. class:: Cmd(completekey='tab', stdin=None, stdout=None) A :class:`Cmd` instance or subclass instance is a line-oriented interpreter Modified: python/branches/py3k/Doc/library/collections.rst ============================================================================== --- python/branches/py3k/Doc/library/collections.rst (original) +++ python/branches/py3k/Doc/library/collections.rst Mon Jan 10 04:26:08 2011 @@ -12,6 +12,8 @@ import itertools __name__ = '' +**Source code:** :source:`Lib/collections.py` + This module implements specialized container datatypes providing alternatives to Python's general purpose built-in containers, :class:`dict`, :class:`list`, :class:`set`, and :class:`tuple`. @@ -31,11 +33,6 @@ :ref:`abstract-base-classes` that can be used to test whether a class provides a particular interface, for example, whether it is hashable or a mapping. -.. seealso:: - - Latest version of the :source:`collections module Python source code - ` - :class:`Counter` objects ------------------------ Modified: python/branches/py3k/Doc/library/contextlib.rst ============================================================================== --- python/branches/py3k/Doc/library/contextlib.rst (original) +++ python/branches/py3k/Doc/library/contextlib.rst Mon Jan 10 04:26:08 2011 @@ -4,16 +4,12 @@ .. module:: contextlib :synopsis: Utilities for with-statement contexts. +**Source code:** :source:`Lib/contextlib.py` This module provides utilities for common tasks involving the :keyword:`with` statement. For more information see also :ref:`typecontextmanager` and :ref:`context-managers`. -.. seealso:: - - Latest version of the :source:`contextlib Python source code - ` - Functions provided: Modified: python/branches/py3k/Doc/library/dis.rst ============================================================================== --- python/branches/py3k/Doc/library/dis.rst (original) +++ python/branches/py3k/Doc/library/dis.rst Mon Jan 10 04:26:08 2011 @@ -4,19 +4,16 @@ .. module:: dis :synopsis: Disassembler for Python bytecode. +**Source code:** :source:`Lib/dis.py` The :mod:`dis` module supports the analysis of CPython :term:`bytecode` by disassembling it. The CPython bytecode which this module takes as an input is defined in the file :file:`Include/opcode.h` and used by the compiler and the interpreter. -.. seealso:: - - Latest version of the :source:`dis module Python source code ` - .. impl-detail:: - Bytecode is an implementation detail of the CPython interpreter! No + Bytecode is an implementation detail of the CPython interpreter. No guarantees are made that bytecode will not be added, removed, or changed between versions of Python. Use of this module should not be considered to work across Python VMs or Python releases. Modified: python/branches/py3k/Doc/library/filecmp.rst ============================================================================== --- python/branches/py3k/Doc/library/filecmp.rst (original) +++ python/branches/py3k/Doc/library/filecmp.rst Mon Jan 10 04:26:08 2011 @@ -5,16 +5,12 @@ :synopsis: Compare files efficiently. .. sectionauthor:: Moshe Zadka +**Source code:** :source:`Lib/filecmp.py` The :mod:`filecmp` module defines functions to compare files and directories, with various optional time/correctness trade-offs. For comparing files, see also the :mod:`difflib` module. -.. seealso:: - - Latest version of the :source:`filecmp Python source code - ` - The :mod:`filecmp` module defines the following functions: Modified: python/branches/py3k/Doc/library/fileinput.rst ============================================================================== --- python/branches/py3k/Doc/library/fileinput.rst (original) +++ python/branches/py3k/Doc/library/fileinput.rst Mon Jan 10 04:26:08 2011 @@ -6,6 +6,7 @@ .. moduleauthor:: Guido van Rossum .. sectionauthor:: Fred L. Drake, Jr. +**Source code:** :source:`Lib/fileinput.py` This module implements a helper class and functions to quickly write a loop over standard input or a list of files. If you just want to read or @@ -44,11 +45,6 @@ returns an accordingly opened file-like object. Two useful hooks are already provided by this module. -.. seealso:: - - Latest version of the :source:`fileinput Python source code - ` - The following function is the primary interface of this module: Modified: python/branches/py3k/Doc/library/fnmatch.rst ============================================================================== --- python/branches/py3k/Doc/library/fnmatch.rst (original) +++ python/branches/py3k/Doc/library/fnmatch.rst Mon Jan 10 04:26:08 2011 @@ -9,6 +9,8 @@ .. index:: module: re +**Source code:** :source:`Lib/fnmatch.py` + This module provides support for Unix shell-style wildcards, which are *not* the same as regular expressions (which are documented in the :mod:`re` module). The special characters used in shell-style wildcards are: @@ -88,6 +90,3 @@ Module :mod:`glob` Unix shell-style path expansion. - - Latest version of the :source:`fnmatch Python source code - ` Modified: python/branches/py3k/Doc/library/glob.rst ============================================================================== --- python/branches/py3k/Doc/library/glob.rst (original) +++ python/branches/py3k/Doc/library/glob.rst Mon Jan 10 04:26:08 2011 @@ -7,6 +7,8 @@ .. index:: single: filenames; pathname expansion +**Source code:** :source:`Lib/glob.py` + The :mod:`glob` module finds all the pathnames matching a specified pattern according to the rules used by the Unix shell. No tilde expansion is done, but ``*``, ``?``, and character ranges expressed with ``[]`` will be correctly @@ -50,5 +52,3 @@ Module :mod:`fnmatch` Shell-style filename (not path) expansion - Latest version of the :source:`glob module Python source code ` - Modified: python/branches/py3k/Doc/library/heapq.rst ============================================================================== --- python/branches/py3k/Doc/library/heapq.rst (original) +++ python/branches/py3k/Doc/library/heapq.rst Mon Jan 10 04:26:08 2011 @@ -8,14 +8,11 @@ .. sectionauthor:: Fran?ois Pinard .. sectionauthor:: Raymond Hettinger +**Source code:** :source:`Lib/heapq.py` + This module provides an implementation of the heap queue algorithm, also known as the priority queue algorithm. -.. seealso:: - - Latest version of the :source:`heapq Python source code - ` - Heaps are binary trees for which every parent node has a value less than or equal to any of its children. This implementation uses arrays for which ``heap[k] <= heap[2*k+1]`` and ``heap[k] <= heap[2*k+2]`` for all *k*, counting Modified: python/branches/py3k/Doc/library/keyword.rst ============================================================================== --- python/branches/py3k/Doc/library/keyword.rst (original) +++ python/branches/py3k/Doc/library/keyword.rst Mon Jan 10 04:26:08 2011 @@ -4,6 +4,7 @@ .. module:: keyword :synopsis: Test whether a string is a keyword in Python. +**Source code:** :source:`Lib/keyword.py` This module allows a Python program to determine if a string is a keyword. @@ -18,9 +19,3 @@ Sequence containing all the keywords defined for the interpreter. If any keywords are defined to only be active when particular :mod:`__future__` statements are in effect, these will be included as well. - - -.. seealso:: - - Latest version of the :source:`keyword module Python source code - ` Modified: python/branches/py3k/Doc/library/linecache.rst ============================================================================== --- python/branches/py3k/Doc/library/linecache.rst (original) +++ python/branches/py3k/Doc/library/linecache.rst Mon Jan 10 04:26:08 2011 @@ -5,17 +5,13 @@ :synopsis: This module provides random access to individual lines from text files. .. sectionauthor:: Moshe Zadka +**Source code:** :source:`Lib/linecache.py` The :mod:`linecache` module allows one to get any line from any file, while attempting to optimize internally, using a cache, the common case where many lines are read from a single file. This is used by the :mod:`traceback` module to retrieve source lines for inclusion in the formatted traceback. -.. seealso:: - - Latest version of the :source:`linecache module Python source code - ` - The :mod:`linecache` module defines the following functions: Modified: python/branches/py3k/Doc/library/pprint.rst ============================================================================== --- python/branches/py3k/Doc/library/pprint.rst (original) +++ python/branches/py3k/Doc/library/pprint.rst Mon Jan 10 04:26:08 2011 @@ -6,6 +6,7 @@ .. moduleauthor:: Fred L. Drake, Jr. .. sectionauthor:: Fred L. Drake, Jr. +**Source code:** :source:`Lib/pprint.py` The :mod:`pprint` module provides a capability to "pretty-print" arbitrary Python data structures in a form which can be used as input to the interpreter. @@ -21,11 +22,6 @@ Dictionaries are sorted by key before the display is computed. -.. seealso:: - - Latest version of the :source:`pprint module Python source code - ` - The :mod:`pprint` module defines one class: .. First the implementation class: Modified: python/branches/py3k/Doc/library/queue.rst ============================================================================== --- python/branches/py3k/Doc/library/queue.rst (original) +++ python/branches/py3k/Doc/library/queue.rst Mon Jan 10 04:26:08 2011 @@ -4,6 +4,7 @@ .. module:: queue :synopsis: A synchronized queue class. +**Source code:** :source:`Lib/queue.py` The :mod:`queue` module implements multi-producer, multi-consumer queues. It is especially useful in threaded programming when information must be @@ -181,5 +182,3 @@ queues with fast atomic :func:`append` and :func:`popleft` operations that do not require locking. - Latest version of the :source:`queue module Python source code - ` Modified: python/branches/py3k/Doc/library/random.rst ============================================================================== --- python/branches/py3k/Doc/library/random.rst (original) +++ python/branches/py3k/Doc/library/random.rst Mon Jan 10 04:26:08 2011 @@ -4,15 +4,11 @@ .. module:: random :synopsis: Generate pseudo-random numbers with various common distributions. +**Source code:** :source:`Lib/random.py` This module implements pseudo-random number generators for various distributions. -.. seealso:: - - Latest version of the :source:`random module Python source code - ` - For integers, there is uniform selection from a range. For sequences, there is uniform selection of a random element, a function to generate a random permutation of a list in-place, and a function for random sampling without @@ -45,8 +41,8 @@ uses the system function :func:`os.urandom` to generate random numbers from sources provided by the operating system. -Bookkeeping functions: +Bookkeeping functions: .. function:: seed([x], version=2) Modified: python/branches/py3k/Doc/library/sched.rst ============================================================================== --- python/branches/py3k/Doc/library/sched.rst (original) +++ python/branches/py3k/Doc/library/sched.rst Mon Jan 10 04:26:08 2011 @@ -7,14 +7,11 @@ .. index:: single: event scheduling +**Source code:** :source:`Lib/sched.py` + The :mod:`sched` module defines a class which implements a general purpose event scheduler: -.. seealso:: - - Latest version of the :source:`sched module Python source code - ` - .. class:: scheduler(timefunc, delayfunc) The :class:`scheduler` class defines a generic interface to scheduling events. Modified: python/branches/py3k/Doc/library/shelve.rst ============================================================================== --- python/branches/py3k/Doc/library/shelve.rst (original) +++ python/branches/py3k/Doc/library/shelve.rst Mon Jan 10 04:26:08 2011 @@ -7,16 +7,14 @@ .. index:: module: pickle +**Source code:** :source:`Lib/shelve.py` + A "shelf" is a persistent, dictionary-like object. The difference with "dbm" databases is that the values (not the keys!) in a shelf can be essentially arbitrary Python objects --- anything that the :mod:`pickle` module can handle. This includes most class instances, recursive data types, and objects containing lots of shared sub-objects. The keys are ordinary strings. -.. seealso:: - - Latest version of the :source:`shelve module Python source code - ` .. function:: open(filename, flag='c', protocol=None, writeback=False) Modified: python/branches/py3k/Doc/library/shutil.rst ============================================================================== --- python/branches/py3k/Doc/library/shutil.rst (original) +++ python/branches/py3k/Doc/library/shutil.rst Mon Jan 10 04:26:08 2011 @@ -10,20 +10,17 @@ single: file; copying single: copying files +**Source code:** :source:`Lib/shutil.py` + The :mod:`shutil` module offers a number of high-level operations on files and collections of files. In particular, functions are provided which support file copying and removal. For operations on individual files, see also the :mod:`os` module. -.. seealso:: - - Latest version of the :source:`shutil module Python source code - ` - .. warning:: Even the higher-level file copying functions (:func:`copy`, :func:`copy2`) - can't copy all file metadata. + cannot copy all file metadata. On POSIX platforms, this means that file owner and group are lost as well as ACLs. On Mac OS, the resource fork and other metadata are not used. Modified: python/branches/py3k/Doc/library/string.rst ============================================================================== --- python/branches/py3k/Doc/library/string.rst (original) +++ python/branches/py3k/Doc/library/string.rst Mon Jan 10 04:26:08 2011 @@ -11,9 +11,7 @@ :ref:`string-methods` - Latest version of the :source:`string module Python source code - ` - +**Source code:** :source:`Lib/string.py` String constants ---------------- Modified: python/branches/py3k/Doc/library/textwrap.rst ============================================================================== --- python/branches/py3k/Doc/library/textwrap.rst (original) +++ python/branches/py3k/Doc/library/textwrap.rst Mon Jan 10 04:26:08 2011 @@ -6,6 +6,7 @@ .. moduleauthor:: Greg Ward .. sectionauthor:: Greg Ward +**Source code:** :source:`Lib/textwrap.py` The :mod:`textwrap` module provides two convenience functions, :func:`wrap` and :func:`fill`, as well as :class:`TextWrapper`, the class that does all the work, @@ -13,11 +14,6 @@ or two text strings, the convenience functions should be good enough; otherwise, you should use an instance of :class:`TextWrapper` for efficiency. -.. seealso:: - - Latest version of the :source:`textwrap module Python source code - ` - .. function:: wrap(text, width=70, **kwargs) Wraps the single paragraph in *text* (a string) so every line is at most Modified: python/branches/py3k/Doc/library/threading.rst ============================================================================== --- python/branches/py3k/Doc/library/threading.rst (original) +++ python/branches/py3k/Doc/library/threading.rst Mon Jan 10 04:26:08 2011 @@ -4,6 +4,7 @@ .. module:: threading :synopsis: Thread-based parallelism. +**Source code:** :source:`Lib/threading.py` This module constructs higher-level threading interfaces on top of the lower level :mod:`_thread` module. See also the :mod:`queue` module. @@ -28,11 +29,6 @@ However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously. -.. seealso:: - - Latest version of the :source:`threading module Python source code - ` - This module defines the following functions and objects: Modified: python/branches/py3k/Doc/library/tokenize.rst ============================================================================== --- python/branches/py3k/Doc/library/tokenize.rst (original) +++ python/branches/py3k/Doc/library/tokenize.rst Mon Jan 10 04:26:08 2011 @@ -6,17 +6,13 @@ .. moduleauthor:: Ka Ping Yee .. sectionauthor:: Fred L. Drake, Jr. +**Source code:** :source:`Lib/tokenize.py` The :mod:`tokenize` module provides a lexical scanner for Python source code, implemented in Python. The scanner in this module returns comments as tokens as well, making it useful for implementing "pretty-printers," including colorizers for on-screen displays. -.. seealso:: - - Latest version of the :source:`tokenize module Python source code - ` - The primary entry point is a :term:`generator`: .. function:: tokenize(readline) Modified: python/branches/py3k/Doc/library/trace.rst ============================================================================== --- python/branches/py3k/Doc/library/trace.rst (original) +++ python/branches/py3k/Doc/library/trace.rst Mon Jan 10 04:26:08 2011 @@ -4,17 +4,13 @@ .. module:: trace :synopsis: Trace or track Python statement execution. +**Source code:** :source:`Lib/trace.py` The :mod:`trace` module allows you to trace program execution, generate annotated statement coverage listings, print caller/callee relationships and list functions executed during a program run. It can be used in another program or from the command line. -.. seealso:: - - Latest version of the :source:`trace module Python source code - ` - .. _trace-cli: Command-Line Usage Modified: python/branches/py3k/Doc/library/uu.rst ============================================================================== --- python/branches/py3k/Doc/library/uu.rst (original) +++ python/branches/py3k/Doc/library/uu.rst Mon Jan 10 04:26:08 2011 @@ -5,6 +5,7 @@ :synopsis: Encode and decode files in uuencode format. .. moduleauthor:: Lance Ellinghouse +**Source code:** :source:`Lib/uu.py` This module encodes and decodes files in uuencode format, allowing arbitrary binary data to be transferred over ASCII-only connections. Wherever a file @@ -56,5 +57,3 @@ Module :mod:`binascii` Support module containing ASCII-to-binary and binary-to-ASCII conversions. - - Latest version of the :source:`uu module Python source code ` From solipsis at pitrou.net Mon Jan 10 05:05:35 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 10 Jan 2011 05:05:35 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r87897): sum=0 Message-ID: py3k results for svn r87897 (hg cset 1f1e91f110cc) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflogcfMIBo', '-x'] From python-checkins at python.org Mon Jan 10 06:40:58 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 10 Jan 2011 06:40:58 +0100 (CET) Subject: [Python-checkins] r87899 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110110054058.33AE3EE982@mail.python.org> Author: raymond.hettinger Date: Mon Jan 10 06:40:57 2011 New Revision: 87899 Log: Fix typos. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Mon Jan 10 06:40:57 2011 @@ -205,8 +205,8 @@ "root": {"level": "DEBUG", "handlers": ["console", "console_priority"]}} -If that dictionary is stored in a file called :file:`conf.json`, it can loaded -and called with code like this:: +If that dictionary is stored in a file called :file:`conf.json`, it can be +loaded and called with code like this:: >>> import logging.config >>> logging.config.dictConfig(json.load(open('conf.json', 'rb'))) @@ -281,7 +281,7 @@ ===================================== Python's scheme for caching bytecode in *.pyc* files did not work well in -environments with multiple python interpreters. If one interpreter encountered +environments with multiple Python interpreters. If one interpreter encountered a cached file created by another interpreter, it would recompile the source and overwrite the cached file, thus losing the benefits of caching. @@ -367,7 +367,7 @@ This informational PEP clarifies how bytes/text issues are to be handled by the WGSI protocol. The challenge is that string handling in Python 3 is most -conveniently handled with the :class:`str` type eventhough the HTTP protocol +conveniently handled with the :class:`str` type even though the HTTP protocol is itself bytes oriented. The PEP differentiates so-called *native strings* that are used for @@ -428,8 +428,8 @@ (Suggested by Mark Dickinson and implemented by Eric Smith in :issue:`7094`.) * The interpreter can now be started with a quiet option, ``-q``, to suppress - the copyright and version information in an interactive mode. The option can - be introspected using the :attr:`sys.flags` attribute:: + the copyright and version information from being displayed in the interactive + mode. The option can be introspected using the :attr:`sys.flags` attribute:: $ python -q >>> sys.flags @@ -500,7 +500,7 @@ * The internal :c:type:`structsequence` tool now creates subclasses of tuple. This means that C generated structures like those returned by :func:`os.stat`, :func:`time.gmtime`, and :func:`sys.version_info` now work like a - :term:`named tuple` and are more interoperable with functions and methods that + :term:`named tuple` and now work with functions and methods that expect a tuple as an argument. The is a big step forward in making the C structures as flexible as their pure Python counterparts. @@ -530,7 +530,7 @@ produce various issues, especially under Windows. Here is an example of enabling the warning from the command line:: - $ ./python -q -Wdefault + $ python -q -Wdefault >>> f = open("foo", "wb") >>> del f __main__:1: ResourceWarning: unclosed file <_io.BufferedWriter name='foo'> @@ -553,7 +553,7 @@ >>> range(0, 100, 2)[0:5] range(0, 10, 2) - (Contributed by Daniel Stuzback in :issue:`9213` and by Alexander Belopolsky + (Contributed by Daniel Stutzback in :issue:`9213` and by Alexander Belopolsky in :issue:`2690`.) * The :func:`callable` builtin function from Py2.x was resurrected. It provides @@ -586,7 +586,7 @@ Throughout the standard library, there has been more careful attention to encodings and text versus bytes issues. In particular, interactions with the operating system are now better able to pass non-ASCII data using the Windows -mcbs encoding, locale aware encodings, or UTF-8. +mcbs encoding, locale-aware encodings, or UTF-8. Another significant win is the addition of substantially better support for *SSL* connections and security certificates. @@ -655,7 +655,7 @@ * :meth:`xml.etree.ElementTree.Element.iterfind` searches an element and subelements * :meth:`xml.etree.ElementTree.Element.itertext` creates a text iterator over - an element and its sub-elements + an element and its subelements * :meth:`xml.etree.ElementTree.TreeBuilder.end` closes the current element * :meth:`xml.etree.ElementTree.TreeBuilder.doctype` handles a doctype declaration @@ -714,7 +714,7 @@ * To help write classes with rich comparison methods, a new decorator :func:`functools.total_ordering` will use a existing equality and inequality - methods to fill-in the remaining methods. + methods to fill in the remaining methods. For example, supplying *__eq__* and *__lt__* will enable :func:`~functools.total_ordering` to fill-in *__le__*, *__gt__* and *__ge__*:: @@ -729,7 +729,7 @@ (other.lastname.lower(), other.firstname.lower())) With the *total_ordering* decorator, the remaining comparison methods - are filled-in automatically. + are filled in automatically. (Contributed by Raymond Hettinger.) @@ -823,7 +823,7 @@ * The :mod:`datetime` module has a new type :class:`~datetime.timezone` that implements the :class:`~datetime.tzinfo` interface by returning a fixed UTC - offset and timezone name. This makes it easier to create timezone aware + offset and timezone name. This makes it easier to create timezone-aware datetime objects: >>> datetime.now(timezone.utc) @@ -856,7 +856,7 @@ There is a new and slightly mind-blowing tool :class:`~contextlib.ContextDecorator` that is helpful for creating a -:term:`context manager` that does double-duty as a function decorator. +:term:`context manager` that does double duty as a function decorator. As a convenience, this new functionality is used by :func:`~contextlib.contextmanager` so that no extra effort is needed to support @@ -866,7 +866,7 @@ for pre-action and post-action wrappers. Context managers wrap a group of statements using the :keyword:`with`-statement, and function decorators wrap a group of statements enclosed in a function. So, occasionally there is a need to -write a pre/post action wrapper that can be used in either role. +write a pre-action or post-action wrapper that can be used in either role. For example, it is sometimes useful to wrap functions or groups of statements with a logger that can track the time of entry and time of exit. Rather than @@ -906,7 +906,7 @@ (Contributed by Michael Foord in :issue:`9110`.) decimal and fractions ----------------------- +--------------------- Mark Dickinson crafted an elegant and efficient scheme for assuring that different numeric datatypes will have the same hash value whenever their actual @@ -1107,7 +1107,7 @@ ---- The :mod:`nntplib` module has a revamped implementation with better bytes and -unicode semantics as well as more practical APIs. These improvements break +text semantics as well as more practical APIs. These improvements break compatibility with the nntplib version in Python 3.1, which was partly dysfunctional in itself. @@ -1131,14 +1131,14 @@ methods, improved diagnostic messages for test failures, and better method names. -* The command-line call, ``python -m unittest`` can now accept file paths +* The command-line call ``python -m unittest`` can now accept file paths instead of module names for running specific tests (:issue:`10620`). The new test discovery can find tests within packages, locating any test importable from the top level directory. The top level directory can be specified with the `-t` option, a pattern for matching files with ``-p``, and a directory to start discovery with ``-s``:: - $ python -m unittest discover -s my_proj_dir -p '_test.py' + $ python -m unittest discover -s my_proj_dir -p _test.py (Contributed by Michael Foord.) @@ -1171,7 +1171,7 @@ (Contributed by Raymond Hettinger.) * A principal feature of the unittest module is an effort to produce meaningful - diagnostics when a test fails. When possible the failure is recorded along + diagnostics when a test fails. When possible, the failure is recorded along with a diff of the output. This is especially helpful for analyzing log files of failed test runs. However, since diffs can sometime be voluminous, there is a new :attr:`~unittest.TestCase.maxDiff` attribute which sets maximum length of @@ -1189,7 +1189,7 @@ (Contributed by Raymond Hettinger and implemented by Ezio Melotti.) -* To improve consistency, some of long-standing method aliases are being +* To improve consistency, some long-standing method aliases are being deprecated in favor of the preferred names: - replace :meth:`assert_` with :meth:`.assertTrue` @@ -1252,7 +1252,7 @@ cleanup of temporary directories: >>> with tempfile.TemporaryDirectory() as tmpdirname: -... print 'created temporary directory', tmpdirname +... print('created temporary dir:', tmpdirname) (Contributed by Neil Schemenauer and Nick Coghlan; :issue:`5178`.) @@ -1282,7 +1282,7 @@ sysconfig --------- -The new :mod:`sysconfig` module makes it straight-forward to discover +The new :mod:`sysconfig` module makes it straightforward to discover installation paths and configuration variables which vary across platforms and installations. @@ -1291,8 +1291,8 @@ * :func:`~sysconfig.get_platform` returning values like *linux-i586* or *macosx-10.6-ppc*. -* :func:`~sysconfig.get_python_version` returns a Python version string in - the form, "3.2". +* :func:`~sysconfig.get_python_version` returns a Python version string + such as "3.2". It also provides access to the paths and variables corresponding to one of seven named schemes used by :mod:`distutils`. Those include *posix_prefix*, @@ -1350,13 +1350,13 @@ * A :file:`.pdbrc` script file can contain ``continue`` and ``next`` commands that continue debugging. * The :class:`Pdb` class constructor now accepts a *nosigint* argument. -* new commands: ``l(list)``, ``ll(long list`` and ``source`` for +* New commands: ``l(list)``, ``ll(long list`` and ``source`` for listing source code. -* new commands: ``display`` and ``undisplay`` for showing or hiding +* New commands: ``display`` and ``undisplay`` for showing or hiding the value of an expression if it has changed. -* new command: ``interact`` for starting an interactive interpreter containing +* New command: ``interact`` for starting an interactive interpreter containing the global and local names found in the current scope. -* breakpoints can be cleared by breakpoint number +* Breakpoints can be cleared by breakpoint number. (Contributed by Georg Brandl, Antonio Cuni and Ilya Sandler.) @@ -1509,12 +1509,12 @@ :meth:`list.sort` and :func:`sorted` now runs faster and uses less memory when called with a :term:`key function`. Previously, every element of a list was wrapped with a temporary object that remembered the key value - associated with each element. Now, an array of keys and values are + associated with each element. Now, two arrays of keys and values are sorted in parallel. This save the memory consumed by the sort wrappers, and it saves time lost during comparisons which were delegated by the sort wrappers. - (Patch by Daniel Stuzback in :issue:`9915`.) + (Patch by Daniel Stutzback in :issue:`9915`.) * JSON decoding performance is improved and memory consumption is reduced whenever the same string is repeated for multiple keys. Also, JSON encoding @@ -1544,11 +1544,11 @@ (:issue:`6713` by Gawain Bolton, Mark Dickinson, and Victor Stinner.) There were several other minor optimizations. Set differencing now runs faster -when one operand is much larger than the other (Patch by Andress Bennetts in +when one operand is much larger than the other (patch by Andress Bennetts in :issue:`8685`). The :meth:`array.repeat` method has a faster implementation (:issue:`1569291` by Alexander Belopolsky). The :class:`BaseHTTPRequestHandler` has more efficient buffering (:issue:`3709` by Andrew Schaaf). The -multi-argument form of :func:`operator.attrgetter` now function runs slightly +multi-argument form of :func:`operator.attrgetter` function now runs slightly faster (:issue:`10160` by Christos Georgiou). And :class:`ConfigParser` loads multi-line arguments a bit faster (:issue:`7113` by ?ukasz Langa). @@ -1598,7 +1598,7 @@ ``'mbcs'``), and the ``'surrogateescape'`` error handler on all operating systems. -* Added the *cp720* Arabic DOS encoding (:issue:`1616979`). +Also, support was added for *cp720* Arabic DOS encoding (:issue:`1616979`). Documentation @@ -1611,10 +1611,10 @@ accompanied by tables of cheatsheet-style summaries to provide an overview and memory jog without having to read all of the docs. -In some cases, the pure python source code can be helpful adjunct to the docs, +In some cases, the pure Python source code can be helpful adjunct to the docs, so now some modules feature quick links to the latest version of the source code. For example, the :mod:`functools` module documentation has a quick link -at the top labeled :source:`functools Python source code `. +at the top labeled *Source code* source:`Lib/functools.py`. The docs now contain more examples and recipes. In particular, :mod:`re` module has an extensive section, :ref:`re-examples`. Likewise, the :mod:`itertools` @@ -1624,15 +1624,15 @@ No functionality was changed. This just provides an easier-to-read alternate implementation. (Contributed by Alexander Belopolsky.) -The unmaintained *Demo* directory has been removed. Some demos were integrated -into the documentation, some were moved to the *Tools/demo* directory, and -others were removed altogether. (Contributed by Georg Brandl.) +The unmaintained :file:`Demo` directory has been removed. Some demos were +integrated into the documentation, some were moved to the :file:`Tools/demo` +directory, and others were removed altogether. (Contributed by Georg Brandl.) IDLE ==== -* The format menu now has an option to clean-up source files by stripping +* The format menu now has an option to clean source files by stripping trailing whitespace. (Contributed by Raymond Hettinger; :issue:`5150`.) @@ -1681,19 +1681,19 @@ :issue:`9778`.) * A new macro :c:macro:`Py_VA_COPY` copies the state of the variable argument - list. It is equivalent to C99 *va_copy* but available on all python platforms + list. It is equivalent to C99 *va_copy* but available on all Python platforms (:issue:`2443`). -* A new C API function :c:func:`PySys_SetArgvEx` allows an embedded - interpreter to set sys.argv without also modifying :attr:`sys.path` +* A new C API function :c:func:`PySys_SetArgvEx` allows an embedded interpreter + to set :attr:`sys.argv` without also modifying :attr:`sys.path` (:issue:`5753`). * :c:macro:`PyEval_CallObject` is now only available in macro form. The function declaration, which was kept for backwards compatibility reasons, is - now removed -- the macro was introduced in 1997 (:issue:`8276`). + now removed -- the macro was introduced in 1997 (:issue:`8276`). * The is a new function :c:func:`PyLong_AsLongLongAndOverflow` which - is analogous to :c:func:`PyLong_AsLongAndOverflow`. The both serve to + is analogous to :c:func:`PyLong_AsLongAndOverflow`. They both serve to convert Python :class:`int` into a native fixed-width type while providing detection of cases where the conversion won't fit (:issue:`7767`). @@ -1710,7 +1710,7 @@ gives improved memory leak detection when running under Valgrind, while taking advantage of pymalloc at other times (:issue:`2422`). -* Removed the "O?" format from the *PyArg_Parse* functions. The format is no +* Removed the ``O?`` format from the *PyArg_Parse* functions. The format is no longer used and it had never been documented (:issue:`8837`). There were a number of other small changes to the C-API. See the @@ -1779,7 +1779,7 @@ ``random.seed(s, version=1)``. * The previously deprecated :func:`string.maketrans` function has been removed - in favor of the static methods, :meth:`bytes.maketrans` and + in favor of the static method :meth:`bytes.maketrans` and :meth:`bytearray.maketrans`. This change solves the confusion around which types were supported by the :mod:`string` module. Now, :class:`str`, :class:`bytes`, and :class:`bytearray` each have their own **maketrans** and @@ -1805,13 +1805,13 @@ * :func:`struct.pack` now only allows bytes for the ``s`` string pack code. Formerly, it would accept text arguments and implicitly encode them to bytes using UTF-8. This was problematic because it made assumptions about the - correct encoding and because a variable length encoding can fail when writing + correct encoding and because a variable-length encoding can fail when writing to fixed length segment of a structure. Code such as ``struct.pack('<6sHHBBB', 'GIF87a', x, y)`` should be rewritten with to use bytes instead of text, ``struct.pack('<6sHHBBB', b'GIF87a', x, y)``. - (Discovered by David Beazley and fixed by Victor Stinner; :issue:`10783`. + (Discovered by David Beazley and fixed by Victor Stinner; :issue:`10783`.) * The :class:`xml.etree.ElementTree` class now raises an :exc:`xml.etree.ElementTree.ParseError` when a parse fails. Previously it From python-checkins at python.org Mon Jan 10 20:06:37 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 20:06:37 +0100 Subject: [Python-checkins] devguide: Drop the unit test step for people helping to triage a bug as that is more a Message-ID: brett.cannon pushed da3a3362a212 to devguide: http://hg.python.org/devguide/rev/da3a3362a212 changeset: 73:da3a3362a212 tag: tip user: Brett Cannon date: Mon Jan 10 11:06:31 2011 -0800 summary: Drop the unit test step for people helping to triage a bug as that is more a patch thing. files: triage.rst diff --git a/triage.rst b/triage.rst --- a/triage.rst +++ b/triage.rst @@ -21,7 +21,6 @@ * Clearly explain the bug so it can be reproduced * All relevant platform details are included * What version(s) of Python are affected by the bug are fully known -* Is there a proper unit test that can reproduce the bug? These are things you can help with once you have experience developing for Python. For instance, if a bug is not clearly explained enough for you to -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 20:14:39 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 10 Jan 2011 20:14:39 +0100 (CET) Subject: [Python-checkins] r87900 - python/branches/py3k/Doc/library/time.rst Message-ID: <20110110191439.170EAEE9E5@mail.python.org> Author: alexander.belopolsky Date: Mon Jan 10 20:14:38 2011 New Revision: 87900 Log: Fixed a footnote reference Modified: python/branches/py3k/Doc/library/time.rst Modified: python/branches/py3k/Doc/library/time.rst ============================================================================== --- python/branches/py3k/Doc/library/time.rst (original) +++ python/branches/py3k/Doc/library/time.rst Mon Jan 10 20:14:38 2011 @@ -400,7 +400,7 @@ +-------+-------------------+---------------------------------+ | 4 | :attr:`tm_min` | range [0, 59] | +-------+-------------------+---------------------------------+ - | 5 | :attr:`tm_sec` | range [0, 61]; see **(1)** in | + | 5 | :attr:`tm_sec` | range [0, 61]; see **(2)** in | | | | :func:`strftime` description | +-------+-------------------+---------------------------------+ | 6 | :attr:`tm_wday` | range [0, 6], Monday is 0 | From python-checkins at python.org Mon Jan 10 20:54:11 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 10 Jan 2011 20:54:11 +0100 (CET) Subject: [Python-checkins] r87901 - in python/branches/py3k/Doc: library/ast.rst library/bisect.rst library/calendar.rst library/cmd.rst library/collections.rst library/contextlib.rst library/dis.rst library/filecmp.rst library/fileinput.rst library/fnmatch.rst library/glob.rst library/heapq.rst library/keyword.rst library/linecache.rst library/pprint.rst library/queue.rst library/random.rst library/sched.rst library/shelve.rst library/shutil.rst library/string.rst library/textwrap.rst library/threading.rst library/tokenize.rst library/trace.rst library/uu.rst whatsnew/3.2.rst Message-ID: <20110110195411.782C0EE996@mail.python.org> Author: raymond.hettinger Date: Mon Jan 10 20:54:11 2011 New Revision: 87901 Log: Separate source link from main text. Modified: python/branches/py3k/Doc/library/ast.rst python/branches/py3k/Doc/library/bisect.rst python/branches/py3k/Doc/library/calendar.rst python/branches/py3k/Doc/library/cmd.rst python/branches/py3k/Doc/library/collections.rst python/branches/py3k/Doc/library/contextlib.rst python/branches/py3k/Doc/library/dis.rst python/branches/py3k/Doc/library/filecmp.rst python/branches/py3k/Doc/library/fileinput.rst python/branches/py3k/Doc/library/fnmatch.rst python/branches/py3k/Doc/library/glob.rst python/branches/py3k/Doc/library/heapq.rst python/branches/py3k/Doc/library/keyword.rst python/branches/py3k/Doc/library/linecache.rst python/branches/py3k/Doc/library/pprint.rst python/branches/py3k/Doc/library/queue.rst python/branches/py3k/Doc/library/random.rst python/branches/py3k/Doc/library/sched.rst python/branches/py3k/Doc/library/shelve.rst python/branches/py3k/Doc/library/shutil.rst python/branches/py3k/Doc/library/string.rst python/branches/py3k/Doc/library/textwrap.rst python/branches/py3k/Doc/library/threading.rst python/branches/py3k/Doc/library/tokenize.rst python/branches/py3k/Doc/library/trace.rst python/branches/py3k/Doc/library/uu.rst python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/library/ast.rst ============================================================================== --- python/branches/py3k/Doc/library/ast.rst (original) +++ python/branches/py3k/Doc/library/ast.rst Mon Jan 10 20:54:11 2011 @@ -9,6 +9,8 @@ **Source code:** :source:`Lib/ast.py` +-------------- + The :mod:`ast` module helps Python applications to process trees of the Python abstract syntax grammar. The abstract syntax itself might change with each Python release; this module helps to find out programmatically what the current Modified: python/branches/py3k/Doc/library/bisect.rst ============================================================================== --- python/branches/py3k/Doc/library/bisect.rst (original) +++ python/branches/py3k/Doc/library/bisect.rst Mon Jan 10 20:54:11 2011 @@ -9,6 +9,8 @@ **Source code:** :source:`Lib/bisect.py` +-------------- + This module provides support for maintaining a list in sorted order without having to sort the list after each insertion. For long lists of items with expensive comparison operations, this can be an improvement over the more common Modified: python/branches/py3k/Doc/library/calendar.rst ============================================================================== --- python/branches/py3k/Doc/library/calendar.rst (original) +++ python/branches/py3k/Doc/library/calendar.rst Mon Jan 10 20:54:11 2011 @@ -8,6 +8,8 @@ **Source code:** :source:`Lib/calendar.py` +-------------- + This module allows you to output calendars like the Unix :program:`cal` program, and provides additional useful functions related to the calendar. By default, these calendars have Monday as the first day of the week, and Sunday as the last Modified: python/branches/py3k/Doc/library/cmd.rst ============================================================================== --- python/branches/py3k/Doc/library/cmd.rst (original) +++ python/branches/py3k/Doc/library/cmd.rst Mon Jan 10 20:54:11 2011 @@ -7,6 +7,8 @@ **Source code:** :source:`Lib/cmd.py` +-------------- + The :class:`Cmd` class provides a simple framework for writing line-oriented command interpreters. These are often useful for test harnesses, administrative tools, and prototypes that will later be wrapped in a more sophisticated Modified: python/branches/py3k/Doc/library/collections.rst ============================================================================== --- python/branches/py3k/Doc/library/collections.rst (original) +++ python/branches/py3k/Doc/library/collections.rst Mon Jan 10 20:54:11 2011 @@ -14,6 +14,8 @@ **Source code:** :source:`Lib/collections.py` +-------------- + This module implements specialized container datatypes providing alternatives to Python's general purpose built-in containers, :class:`dict`, :class:`list`, :class:`set`, and :class:`tuple`. Modified: python/branches/py3k/Doc/library/contextlib.rst ============================================================================== --- python/branches/py3k/Doc/library/contextlib.rst (original) +++ python/branches/py3k/Doc/library/contextlib.rst Mon Jan 10 20:54:11 2011 @@ -6,6 +6,8 @@ **Source code:** :source:`Lib/contextlib.py` +-------------- + This module provides utilities for common tasks involving the :keyword:`with` statement. For more information see also :ref:`typecontextmanager` and :ref:`context-managers`. Modified: python/branches/py3k/Doc/library/dis.rst ============================================================================== --- python/branches/py3k/Doc/library/dis.rst (original) +++ python/branches/py3k/Doc/library/dis.rst Mon Jan 10 20:54:11 2011 @@ -6,6 +6,8 @@ **Source code:** :source:`Lib/dis.py` +-------------- + The :mod:`dis` module supports the analysis of CPython :term:`bytecode` by disassembling it. The CPython bytecode which this module takes as an input is defined in the file :file:`Include/opcode.h` and used by the compiler Modified: python/branches/py3k/Doc/library/filecmp.rst ============================================================================== --- python/branches/py3k/Doc/library/filecmp.rst (original) +++ python/branches/py3k/Doc/library/filecmp.rst Mon Jan 10 20:54:11 2011 @@ -7,6 +7,8 @@ **Source code:** :source:`Lib/filecmp.py` +-------------- + The :mod:`filecmp` module defines functions to compare files and directories, with various optional time/correctness trade-offs. For comparing files, see also the :mod:`difflib` module. Modified: python/branches/py3k/Doc/library/fileinput.rst ============================================================================== --- python/branches/py3k/Doc/library/fileinput.rst (original) +++ python/branches/py3k/Doc/library/fileinput.rst Mon Jan 10 20:54:11 2011 @@ -8,6 +8,8 @@ **Source code:** :source:`Lib/fileinput.py` +-------------- + This module implements a helper class and functions to quickly write a loop over standard input or a list of files. If you just want to read or write one file see :func:`open`. Modified: python/branches/py3k/Doc/library/fnmatch.rst ============================================================================== --- python/branches/py3k/Doc/library/fnmatch.rst (original) +++ python/branches/py3k/Doc/library/fnmatch.rst Mon Jan 10 20:54:11 2011 @@ -11,6 +11,8 @@ **Source code:** :source:`Lib/fnmatch.py` +-------------- + This module provides support for Unix shell-style wildcards, which are *not* the same as regular expressions (which are documented in the :mod:`re` module). The special characters used in shell-style wildcards are: Modified: python/branches/py3k/Doc/library/glob.rst ============================================================================== --- python/branches/py3k/Doc/library/glob.rst (original) +++ python/branches/py3k/Doc/library/glob.rst Mon Jan 10 20:54:11 2011 @@ -9,6 +9,8 @@ **Source code:** :source:`Lib/glob.py` +-------------- + The :mod:`glob` module finds all the pathnames matching a specified pattern according to the rules used by the Unix shell. No tilde expansion is done, but ``*``, ``?``, and character ranges expressed with ``[]`` will be correctly Modified: python/branches/py3k/Doc/library/heapq.rst ============================================================================== --- python/branches/py3k/Doc/library/heapq.rst (original) +++ python/branches/py3k/Doc/library/heapq.rst Mon Jan 10 20:54:11 2011 @@ -10,6 +10,8 @@ **Source code:** :source:`Lib/heapq.py` +-------------- + This module provides an implementation of the heap queue algorithm, also known as the priority queue algorithm. Modified: python/branches/py3k/Doc/library/keyword.rst ============================================================================== --- python/branches/py3k/Doc/library/keyword.rst (original) +++ python/branches/py3k/Doc/library/keyword.rst Mon Jan 10 20:54:11 2011 @@ -6,6 +6,8 @@ **Source code:** :source:`Lib/keyword.py` +-------------- + This module allows a Python program to determine if a string is a keyword. Modified: python/branches/py3k/Doc/library/linecache.rst ============================================================================== --- python/branches/py3k/Doc/library/linecache.rst (original) +++ python/branches/py3k/Doc/library/linecache.rst Mon Jan 10 20:54:11 2011 @@ -7,6 +7,8 @@ **Source code:** :source:`Lib/linecache.py` +-------------- + The :mod:`linecache` module allows one to get any line from any file, while attempting to optimize internally, using a cache, the common case where many lines are read from a single file. This is used by the :mod:`traceback` module Modified: python/branches/py3k/Doc/library/pprint.rst ============================================================================== --- python/branches/py3k/Doc/library/pprint.rst (original) +++ python/branches/py3k/Doc/library/pprint.rst Mon Jan 10 20:54:11 2011 @@ -8,6 +8,8 @@ **Source code:** :source:`Lib/pprint.py` +-------------- + The :mod:`pprint` module provides a capability to "pretty-print" arbitrary Python data structures in a form which can be used as input to the interpreter. If the formatted structures include objects which are not fundamental Python Modified: python/branches/py3k/Doc/library/queue.rst ============================================================================== --- python/branches/py3k/Doc/library/queue.rst (original) +++ python/branches/py3k/Doc/library/queue.rst Mon Jan 10 20:54:11 2011 @@ -6,6 +6,8 @@ **Source code:** :source:`Lib/queue.py` +-------------- + The :mod:`queue` module implements multi-producer, multi-consumer queues. It is especially useful in threaded programming when information must be exchanged safely between multiple threads. The :class:`Queue` class in this Modified: python/branches/py3k/Doc/library/random.rst ============================================================================== --- python/branches/py3k/Doc/library/random.rst (original) +++ python/branches/py3k/Doc/library/random.rst Mon Jan 10 20:54:11 2011 @@ -6,6 +6,8 @@ **Source code:** :source:`Lib/random.py` +-------------- + This module implements pseudo-random number generators for various distributions. Modified: python/branches/py3k/Doc/library/sched.rst ============================================================================== --- python/branches/py3k/Doc/library/sched.rst (original) +++ python/branches/py3k/Doc/library/sched.rst Mon Jan 10 20:54:11 2011 @@ -9,6 +9,8 @@ **Source code:** :source:`Lib/sched.py` +-------------- + The :mod:`sched` module defines a class which implements a general purpose event scheduler: Modified: python/branches/py3k/Doc/library/shelve.rst ============================================================================== --- python/branches/py3k/Doc/library/shelve.rst (original) +++ python/branches/py3k/Doc/library/shelve.rst Mon Jan 10 20:54:11 2011 @@ -9,6 +9,8 @@ **Source code:** :source:`Lib/shelve.py` +-------------- + A "shelf" is a persistent, dictionary-like object. The difference with "dbm" databases is that the values (not the keys!) in a shelf can be essentially arbitrary Python objects --- anything that the :mod:`pickle` module can handle. Modified: python/branches/py3k/Doc/library/shutil.rst ============================================================================== --- python/branches/py3k/Doc/library/shutil.rst (original) +++ python/branches/py3k/Doc/library/shutil.rst Mon Jan 10 20:54:11 2011 @@ -12,6 +12,8 @@ **Source code:** :source:`Lib/shutil.py` +-------------- + The :mod:`shutil` module offers a number of high-level operations on files and collections of files. In particular, functions are provided which support file copying and removal. For operations on individual files, see also the Modified: python/branches/py3k/Doc/library/string.rst ============================================================================== --- python/branches/py3k/Doc/library/string.rst (original) +++ python/branches/py3k/Doc/library/string.rst Mon Jan 10 20:54:11 2011 @@ -13,6 +13,8 @@ **Source code:** :source:`Lib/string.py` +-------------- + String constants ---------------- Modified: python/branches/py3k/Doc/library/textwrap.rst ============================================================================== --- python/branches/py3k/Doc/library/textwrap.rst (original) +++ python/branches/py3k/Doc/library/textwrap.rst Mon Jan 10 20:54:11 2011 @@ -8,6 +8,8 @@ **Source code:** :source:`Lib/textwrap.py` +-------------- + The :mod:`textwrap` module provides two convenience functions, :func:`wrap` and :func:`fill`, as well as :class:`TextWrapper`, the class that does all the work, and a utility function :func:`dedent`. If you're just wrapping or filling one Modified: python/branches/py3k/Doc/library/threading.rst ============================================================================== --- python/branches/py3k/Doc/library/threading.rst (original) +++ python/branches/py3k/Doc/library/threading.rst Mon Jan 10 20:54:11 2011 @@ -6,6 +6,8 @@ **Source code:** :source:`Lib/threading.py` +-------------- + This module constructs higher-level threading interfaces on top of the lower level :mod:`_thread` module. See also the :mod:`queue` module. Modified: python/branches/py3k/Doc/library/tokenize.rst ============================================================================== --- python/branches/py3k/Doc/library/tokenize.rst (original) +++ python/branches/py3k/Doc/library/tokenize.rst Mon Jan 10 20:54:11 2011 @@ -8,6 +8,8 @@ **Source code:** :source:`Lib/tokenize.py` +-------------- + The :mod:`tokenize` module provides a lexical scanner for Python source code, implemented in Python. The scanner in this module returns comments as tokens as well, making it useful for implementing "pretty-printers," including Modified: python/branches/py3k/Doc/library/trace.rst ============================================================================== --- python/branches/py3k/Doc/library/trace.rst (original) +++ python/branches/py3k/Doc/library/trace.rst Mon Jan 10 20:54:11 2011 @@ -6,6 +6,8 @@ **Source code:** :source:`Lib/trace.py` +-------------- + The :mod:`trace` module allows you to trace program execution, generate annotated statement coverage listings, print caller/callee relationships and list functions executed during a program run. It can be used in another program Modified: python/branches/py3k/Doc/library/uu.rst ============================================================================== --- python/branches/py3k/Doc/library/uu.rst (original) +++ python/branches/py3k/Doc/library/uu.rst Mon Jan 10 20:54:11 2011 @@ -7,6 +7,8 @@ **Source code:** :source:`Lib/uu.py` +-------------- + This module encodes and decodes files in uuencode format, allowing arbitrary binary data to be transferred over ASCII-only connections. Wherever a file argument is expected, the methods accept a file-like object. For backwards Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Mon Jan 10 20:54:11 2011 @@ -1614,7 +1614,7 @@ In some cases, the pure Python source code can be helpful adjunct to the docs, so now some modules feature quick links to the latest version of the source code. For example, the :mod:`functools` module documentation has a quick link -at the top labeled *Source code* source:`Lib/functools.py`. +at the top labeled: *Source code* :source:`Lib/functools.py`. The docs now contain more examples and recipes. In particular, :mod:`re` module has an extensive section, :ref:`re-examples`. Likewise, the :mod:`itertools` From python-checkins at python.org Mon Jan 10 21:15:37 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 21:15:37 +0100 Subject: [Python-checkins] devguide: TODO about explaining how to fill in every field in an issue for a triager. Message-ID: brett.cannon pushed 832d43e78d7f to devguide: http://hg.python.org/devguide/rev/832d43e78d7f changeset: 74:832d43e78d7f user: Brett Cannon date: Mon Jan 10 11:27:39 2011 -0800 summary: TODO about explaining how to fill in every field in an issue for a triager. files: index.rst diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -105,6 +105,10 @@ Could have people help make tests discoverable by unittest, but it requires some upfront work (e.g., how to handle ResourceDenied) +.. todo:: + Figure out where to put instructions for triagers on filling out issue + fields properly + .. _buildbots: http://python.org/dev/buildbot/ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 21:15:38 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 21:15:38 +0100 Subject: [Python-checkins] devguide: Add a doc listing the various places Python's development is discussed. Message-ID: brett.cannon pushed bc01a9d81b11 to devguide: http://hg.python.org/devguide/rev/bc01a9d81b11 changeset: 75:bc01a9d81b11 user: Brett Cannon date: Mon Jan 10 12:14:27 2011 -0800 summary: Add a doc listing the various places Python's development is discussed. files: communication.rst index.rst diff --git a/communication.rst b/communication.rst new file mode 100644 --- /dev/null +++ b/communication.rst @@ -0,0 +1,70 @@ +.. _communication: + +Following Python's Development +============================== + +Python's development is communicated through a myriad of ways, mostly through +mailing lists, but also other forms. + +Mailing Lists +------------- + +The primary mailing list where discussions about Python's development occur is +python-dev_. The list is open to the public and is subscribed to by all core +developers plus many people simply interested in following Python's +development. Discussion is focused on issues related to Python's development, +such as how to handle a specific issue, a PEP, etc. Ideas about new +functionality should **not** start here and instead should be sent to +python-ideas_. Technical support questions should also not be asked here and +instead should go to comp.lang.python_ or python-help_. + +The python-committers_ mailing list is publicly archived but only open to core +developers to subscribe to. If something only affect core developers (e.g., the +tree is frozen for commits, etc.), it is discussed here instead of python-dev +to keep traffic down on the latter. + +Python-ideas_ is a mailing list open to the public to discuss ideas on changing +Python. If a new idea does not start here (or comp.lang.python_), it will get +redirected here. + +Python-checkins_ sends out an email for every commit to Python's various +repositories (both svn.python.org and hg.python.org). All core developers +subscribe to this list and are known to reply to these emails to make comments +about various issues they catch in the commit. Replies get redirected to +python-dev. + +There are two mailing lists related to issues on the `issue tracker`_. If you +only want an email for when a new issue is open, subscribe to +new-bugs-announce_. If you would rather receive an email for all changes made +to any issue, subscribe to python-bugs-list_. + +A complete list of Python mailing lists can be found at http://mail.python.org. + +.. _issue tracker: http://bugs.python.org +.. _new-bugs-announce: http://mail.python.org/mailman/listinfo/new-bugs-announce +.. _python-bugs-list: http://mail.python.org/mailman/listinfo/python-bugs-list +.. _python-checkins: http://mail.python.org/mailman/listinfo/python-checkins +.. _python-committers: http://mail.python.org/mailman/listinfo/python-committers +.. _python-dev: http://mail.python.org/mailman/listinfo/python-dev +.. _python-help: http://mail.python.org/mailman/listinfo/python-help +.. _python-ideas: http://mail.python.org/mailman/listinfo/python-ideas + + +Newsgroups +---------- + +The newsgroup most closely related to Python's development is +comp.lang.python_ (also available as a mailing list through python-list). +Sometimes new ideas for Python start here to gather community opinion before +heading to python-ideas_. + +.. _comp.lang.python: http://mail.python.org/mailman/listinfo/python-list + + +IRC +--- + +Some core developers enjoy spending time on IRC discussing various issues +regarding Python's development in the #python-dev channel. This is not a place +to ask for help with Python, but to discuss issues related to Python's own +development. diff --git a/index.rst b/index.rst --- a/index.rst +++ b/index.rst @@ -14,6 +14,7 @@ triage devrole languishing + communication .. todolist:: @@ -44,7 +45,7 @@ * :ref:`triage` * :ref:`devrole` * :ref:`languishing` -* `Following Python's development `_ +* :ref:`communication` * `Gaining commit privileges `_ * `Committing patches `_ -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 10 21:15:38 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 10 Jan 2011 21:15:38 +0100 Subject: [Python-checkins] devguide: Mention Planet Python. Message-ID: brett.cannon pushed 34e251fe2995 to devguide: http://hg.python.org/devguide/rev/34e251fe2995 changeset: 76:34e251fe2995 tag: tip user: Brett Cannon date: Mon Jan 10 12:15:27 2011 -0800 summary: Mention Planet Python. files: communication.rst diff --git a/communication.rst b/communication.rst --- a/communication.rst +++ b/communication.rst @@ -68,3 +68,11 @@ regarding Python's development in the #python-dev channel. This is not a place to ask for help with Python, but to discuss issues related to Python's own development. + + +Blogs +----- + +Several core developers are active bloggers and discuss Python's development +that way. You can find their blogs (and varous other developers who use Python) +at http://planet.python.org/. -- Repository URL: http://hg.python.org/devguide From tjreedy at udel.edu Mon Jan 10 21:53:51 2011 From: tjreedy at udel.edu (Terry Reedy) Date: Mon, 10 Jan 2011 15:53:51 -0500 Subject: [Python-checkins] devguide: Add a doc listing the various places Python's development is discussed. In-Reply-To: References: Message-ID: <4D2B71DF.4050201@udel.edu> > +The primary mailing list where discussions about Python's development occur is > +python-dev_ suggest adding ", mirrored as newsgroup gmane.comp.python.devel." ... > +python-ideas_. Technical support questions should also not be asked here and > +instead should go to comp.lang.python_ or python-help_. Suggest replace "comp.lang.python" with "python-list, mirrored as gmane.comp.python.general". c.l.p is another mirror, but does not get the spam filtering of p-l and g.c.p.g and is indeed the source or transmitter (from google groups) of the spam that needs to be filtered. > + > +The python-committers_ mailing list is publicly archived but only open to core > +developers to subscribe to. If something only affect core developers (e.g., the > +tree is frozen for commits, etc.), it is discussed here instead of python-dev > +to keep traffic down on the latter. > + > +Python-ideas_ is a mailing list open to the public to discuss ideas on changing > +Python. If a new idea does not start here (or comp.lang.python_), it will get Again, /c.l.p/python-list/ > +subscribe to this list and are known to reply to these emails to make comments > +about various issues they catch in the commit. ;-) ... > +.. _python-help: http://mail.python.org/mailman/listinfo/python-help > +.. _python-ideas: http://mail.python.org/mailman/listinfo/python-ideas _python-list: http://mail.python.org/mailman/listinfo/python-list > +Newsgroups > +---------- "The free news site news.gmane.org mirrors (and archives) about 300 python-related mailing lists, including most or all of those at mail.python.org. Most are listed as gmane.comp.python.*." I would barely, if at all, mentions c.l.p: it is spammy, only mirrors 1 list rather than 300, and is not an archive in itself. Terry From python-checkins at python.org Mon Jan 10 22:16:07 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 10 Jan 2011 22:16:07 +0100 (CET) Subject: [Python-checkins] r87902 - in python/branches/py3k/Doc/library: functools.rst quopri.rst Message-ID: <20110110211607.70F94EE9A3@mail.python.org> Author: raymond.hettinger Date: Mon Jan 10 22:16:07 2011 New Revision: 87902 Log: Missed two source links Modified: python/branches/py3k/Doc/library/functools.rst python/branches/py3k/Doc/library/quopri.rst Modified: python/branches/py3k/Doc/library/functools.rst ============================================================================== --- python/branches/py3k/Doc/library/functools.rst (original) +++ python/branches/py3k/Doc/library/functools.rst Mon Jan 10 22:16:07 2011 @@ -8,16 +8,14 @@ .. moduleauthor:: Nick Coghlan .. sectionauthor:: Peter Harris +**Source code:** :source:`Lib/functools.py` + +-------------- The :mod:`functools` module is for higher-order functions: functions that act on or return other functions. In general, any callable object can be treated as a function for the purposes of this module. -.. seealso:: - - Latest version of the :source:`functools Python source code - ` - The :mod:`functools` module defines the following functions: .. function:: cmp_to_key(func) Modified: python/branches/py3k/Doc/library/quopri.rst ============================================================================== --- python/branches/py3k/Doc/library/quopri.rst (original) +++ python/branches/py3k/Doc/library/quopri.rst Mon Jan 10 22:16:07 2011 @@ -9,6 +9,10 @@ pair: quoted-printable; encoding single: MIME; quoted-printable encoding +**Source code:** :source:`Lib/quopri.py` + +-------------- + This module performs quoted-printable transport encoding and decoding, as defined in :rfc:`1521`: "MIME (Multipurpose Internet Mail Extensions) Part One: Mechanisms for Specifying and Describing the Format of Internet Message Bodies". @@ -57,6 +61,3 @@ Module :mod:`base64` Encode and decode MIME base64 data - - Latest version of the :source:`quopri module Python source code - ` From alexander.belopolsky at gmail.com Mon Jan 10 22:00:34 2011 From: alexander.belopolsky at gmail.com (Alexander Belopolsky) Date: Mon, 10 Jan 2011 16:00:34 -0500 Subject: [Python-checkins] devguide: TODO about explaining how to fill in every field in an issue for a triager. In-Reply-To: References: Message-ID: On Mon, Jan 10, 2011 at 3:15 PM, brett.cannon wrote: .. > +.. todo:: > + ? ?Figure out where to put instructions for triagers on filling out issue > + ? ?fields properly Some field titles are clickable and linked to field choices descriptions. Maybe these could be replaced with links to proper devguide sections. From python-checkins at python.org Mon Jan 10 22:26:50 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 10 Jan 2011 22:26:50 +0100 (CET) Subject: [Python-checkins] r87903 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110110212650.20750EE98C@mail.python.org> Author: raymond.hettinger Date: Mon Jan 10 22:26:49 2011 New Revision: 87903 Log: Misspelling. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Mon Jan 10 22:26:49 2011 @@ -553,7 +553,7 @@ >>> range(0, 100, 2)[0:5] range(0, 10, 2) - (Contributed by Daniel Stutzback in :issue:`9213` and by Alexander Belopolsky + (Contributed by Daniel Stutzbach in :issue:`9213` and by Alexander Belopolsky in :issue:`2690`.) * The :func:`callable` builtin function from Py2.x was resurrected. It provides @@ -1514,7 +1514,7 @@ and it saves time lost during comparisons which were delegated by the sort wrappers. - (Patch by Daniel Stutzback in :issue:`9915`.) + (Patch by Daniel Stutzbach in :issue:`9915`.) * JSON decoding performance is improved and memory consumption is reduced whenever the same string is repeated for multiple keys. Also, JSON encoding From python-checkins at python.org Mon Jan 10 22:27:49 2011 From: python-checkins at python.org (terry.reedy) Date: Mon, 10 Jan 2011 22:27:49 +0100 (CET) Subject: [Python-checkins] r87904 - in python/branches/py3k: Doc/howto/regex.rst Misc/NEWS Message-ID: <20110110212749.5B9BDEE998@mail.python.org> Author: terry.reedy Date: Mon Jan 10 22:27:49 2011 New Revision: 87904 Log: Issue #10875: Update Regular Expression HOWTO; patch by 'SilentGhost'. Modified: python/branches/py3k/Doc/howto/regex.rst python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Doc/howto/regex.rst ============================================================================== --- python/branches/py3k/Doc/howto/regex.rst (original) +++ python/branches/py3k/Doc/howto/regex.rst Mon Jan 10 22:27:49 2011 @@ -5,7 +5,6 @@ **************************** :Author: A.M. Kuchling -:Release: 0.05 .. TODO: Document lookbehind assertions @@ -24,11 +23,6 @@ Introduction ============ -The :mod:`re` module was added in Python 1.5, and provides Perl-style regular -expression patterns. Earlier versions of Python came with the :mod:`regex` -module, which provided Emacs-style patterns. The :mod:`regex` module was -removed completely in Python 2.5. - Regular expressions (called REs, or regexes, or regex patterns) are essentially a tiny, highly specialized programming language embedded inside Python and made available through the :mod:`re` module. Using this little language, you specify @@ -264,7 +258,7 @@ >>> import re >>> p = re.compile('ab*') >>> p - <_sre.SRE_Pattern object at 80b4150> + <_sre.SRE_Pattern object at 0x...> :func:`re.compile` also accepts an optional *flags* argument, used to enable various special features and syntax variations. We'll go over the available @@ -362,8 +356,8 @@ and more. You can learn about this by interactively experimenting with the :mod:`re` -module. If you have Tkinter available, you may also want to look at -:file:`Tools/scripts/redemo.py`, a demonstration program included with the +module. If you have :mod:`tkinter` available, you may also want to look at +:file:`Tools/demo/redemo.py`, a demonstration program included with the Python distribution. It allows you to enter REs and strings, and displays whether the RE matches or fails. :file:`redemo.py` can be quite useful when trying to debug a complicated RE. Phil Schwartz's `Kodos @@ -373,11 +367,10 @@ This HOWTO uses the standard Python interpreter for its examples. First, run the Python interpreter, import the :mod:`re` module, and compile a RE:: - Python 2.2.2 (#1, Feb 10 2003, 12:57:01) >>> import re >>> p = re.compile('[a-z]+') >>> p - <_sre.SRE_Pattern object at 80c3c28> + <_sre.SRE_Pattern object at 0x...> Now, you can try matching various strings against the RE ``[a-z]+``. An empty string shouldn't match at all, since ``+`` means 'one or more repetitions'. @@ -395,7 +388,7 @@ >>> m = p.match('tempo') >>> m - <_sre.SRE_Match object at 80c4f68> + <_sre.SRE_Match object at 0x...> Now you can query the :class:`MatchObject` for information about the matching string. :class:`MatchObject` instances also have several methods and @@ -434,7 +427,7 @@ >>> print(p.match('::: message')) None >>> m = p.search('::: message') ; print(m) - + <_sre.SRE_Match object at 0x...> >>> m.group() 'message' >>> m.span() @@ -459,11 +452,11 @@ :meth:`findall` has to create the entire list before it can be returned as the result. The :meth:`finditer` method returns a sequence of :class:`MatchObject` -instances as an :term:`iterator`. [#]_ :: +instances as an :term:`iterator`:: >>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...') >>> iterator - + >>> for match in iterator: ... print(match.span()) ... @@ -485,7 +478,7 @@ >>> print(re.match(r'From\s+', 'Fromage amk')) None >>> re.match(r'From\s+', 'From amk Thu May 14 19:12:10 1998') - + <_sre.SRE_Match object at 0x...> Under the hood, these functions simply create a pattern object for you and call the appropriate method on it. They also store the compiled object in a @@ -687,7 +680,7 @@ line, the RE to use is ``^From``. :: >>> print(re.search('^From', 'From Here to Eternity')) - + <_sre.SRE_Match object at 0x...> >>> print(re.search('^From', 'Reciting From Memory')) None @@ -699,11 +692,11 @@ or any location followed by a newline character. :: >>> print(re.search('}$', '{block}')) - + <_sre.SRE_Match object at 0x...> >>> print(re.search('}$', '{block} ')) None >>> print(re.search('}$', '{block}\n')) - + <_sre.SRE_Match object at 0x...> To match a literal ``'$'``, use ``\$`` or enclose it inside a character class, as in ``[$]``. @@ -728,7 +721,7 @@ >>> p = re.compile(r'\bclass\b') >>> print(p.search('no class at all')) - + <_sre.SRE_Match object at 0x...> >>> print(p.search('the declassified algorithm')) None >>> print(p.search('one subclass is')) @@ -746,7 +739,7 @@ >>> print(p.search('no class at all')) None >>> print(p.search('\b' + 'class' + '\b') ) - + <_sre.SRE_Match object at 0x...> Second, inside a character class, where there's no use for this assertion, ``\b`` represents the backspace character, for compatibility with Python's @@ -1316,8 +1309,8 @@ be *very* complicated. Use an HTML or XML parser module for such tasks.) -Not Using re.VERBOSE --------------------- +Using re.VERBOSE +---------------- By now you've probably noticed that regular expressions are a very compact notation, but they're not terribly readable. REs of moderate complexity can @@ -1366,8 +1359,3 @@ now-removed :mod:`regex` module, which won't help you much.) Consider checking it out from your library. - -.. rubric:: Footnotes - -.. [#] Introduced in Python 2.2.2. - Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 10 22:27:49 2011 @@ -40,6 +40,8 @@ Library ------- +- Issue #10875: Update Regular Expression HOWTO; patch by 'SilentGhost'. + - Issue #10872: The repr() of TextIOWrapper objects now includes the mode if available. From python-checkins at python.org Mon Jan 10 22:49:11 2011 From: python-checkins at python.org (terry.reedy) Date: Mon, 10 Jan 2011 22:49:11 +0100 (CET) Subject: [Python-checkins] r87905 - in python/branches/release31-maint: Doc/howto/regex.rst Misc/NEWS Message-ID: <20110110214911.8A4B8EE981@mail.python.org> Author: terry.reedy Date: Mon Jan 10 22:49:11 2011 New Revision: 87905 Log: Issue #10875: Update Regular Expression HOWTO; patch by 'SilentGhost'. Modified: python/branches/release31-maint/Doc/howto/regex.rst python/branches/release31-maint/Misc/NEWS Modified: python/branches/release31-maint/Doc/howto/regex.rst ============================================================================== --- python/branches/release31-maint/Doc/howto/regex.rst (original) +++ python/branches/release31-maint/Doc/howto/regex.rst Mon Jan 10 22:49:11 2011 @@ -5,7 +5,6 @@ **************************** :Author: A.M. Kuchling -:Release: 0.05 .. TODO: Document lookbehind assertions @@ -24,11 +23,6 @@ Introduction ============ -The :mod:`re` module was added in Python 1.5, and provides Perl-style regular -expression patterns. Earlier versions of Python came with the :mod:`regex` -module, which provided Emacs-style patterns. The :mod:`regex` module was -removed completely in Python 2.5. - Regular expressions (called REs, or regexes, or regex patterns) are essentially a tiny, highly specialized programming language embedded inside Python and made available through the :mod:`re` module. Using this little language, you specify @@ -264,7 +258,7 @@ >>> import re >>> p = re.compile('ab*') >>> p - <_sre.SRE_Pattern object at 80b4150> + <_sre.SRE_Pattern object at 0x...> :func:`re.compile` also accepts an optional *flags* argument, used to enable various special features and syntax variations. We'll go over the available @@ -362,8 +356,8 @@ and more. You can learn about this by interactively experimenting with the :mod:`re` -module. If you have Tkinter available, you may also want to look at -:file:`Tools/scripts/redemo.py`, a demonstration program included with the +module. If you have :mod:`tkinter` available, you may also want to look at +:file:`Tools/demo/redemo.py`, a demonstration program included with the Python distribution. It allows you to enter REs and strings, and displays whether the RE matches or fails. :file:`redemo.py` can be quite useful when trying to debug a complicated RE. Phil Schwartz's `Kodos @@ -373,11 +367,10 @@ This HOWTO uses the standard Python interpreter for its examples. First, run the Python interpreter, import the :mod:`re` module, and compile a RE:: - Python 2.2.2 (#1, Feb 10 2003, 12:57:01) >>> import re >>> p = re.compile('[a-z]+') >>> p - <_sre.SRE_Pattern object at 80c3c28> + <_sre.SRE_Pattern object at 0x...> Now, you can try matching various strings against the RE ``[a-z]+``. An empty string shouldn't match at all, since ``+`` means 'one or more repetitions'. @@ -395,7 +388,7 @@ >>> m = p.match('tempo') >>> m - <_sre.SRE_Match object at 80c4f68> + <_sre.SRE_Match object at 0x...> Now you can query the :class:`MatchObject` for information about the matching string. :class:`MatchObject` instances also have several methods and @@ -434,7 +427,7 @@ >>> print(p.match('::: message')) None >>> m = p.search('::: message') ; print(m) - + <_sre.SRE_Match object at 0x...> >>> m.group() 'message' >>> m.span() @@ -459,11 +452,11 @@ :meth:`findall` has to create the entire list before it can be returned as the result. The :meth:`finditer` method returns a sequence of :class:`MatchObject` -instances as an :term:`iterator`. [#]_ :: +instances as an :term:`iterator`:: >>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...') >>> iterator - + >>> for match in iterator: ... print(match.span()) ... @@ -485,7 +478,7 @@ >>> print(re.match(r'From\s+', 'Fromage amk')) None >>> re.match(r'From\s+', 'From amk Thu May 14 19:12:10 1998') - + <_sre.SRE_Match object at 0x...> Under the hood, these functions simply create a pattern object for you and call the appropriate method on it. They also store the compiled object in a @@ -687,7 +680,7 @@ line, the RE to use is ``^From``. :: >>> print(re.search('^From', 'From Here to Eternity')) - + <_sre.SRE_Match object at 0x...> >>> print(re.search('^From', 'Reciting From Memory')) None @@ -699,11 +692,11 @@ or any location followed by a newline character. :: >>> print(re.search('}$', '{block}')) - + <_sre.SRE_Match object at 0x...> >>> print(re.search('}$', '{block} ')) None >>> print(re.search('}$', '{block}\n')) - + <_sre.SRE_Match object at 0x...> To match a literal ``'$'``, use ``\$`` or enclose it inside a character class, as in ``[$]``. @@ -728,7 +721,7 @@ >>> p = re.compile(r'\bclass\b') >>> print(p.search('no class at all')) - + <_sre.SRE_Match object at 0x...> >>> print(p.search('the declassified algorithm')) None >>> print(p.search('one subclass is')) @@ -746,7 +739,7 @@ >>> print(p.search('no class at all')) None >>> print(p.search('\b' + 'class' + '\b') ) - + <_sre.SRE_Match object at 0x...> Second, inside a character class, where there's no use for this assertion, ``\b`` represents the backspace character, for compatibility with Python's @@ -1316,8 +1309,8 @@ be *very* complicated. Use an HTML or XML parser module for such tasks.) -Not Using re.VERBOSE --------------------- +Using re.VERBOSE +---------------- By now you've probably noticed that regular expressions are a very compact notation, but they're not terribly readable. REs of moderate complexity can @@ -1366,8 +1359,3 @@ now-removed :mod:`regex` module, which won't help you much.) Consider checking it out from your library. - -.. rubric:: Footnotes - -.. [#] Introduced in Python 2.2.2. - Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Mon Jan 10 22:49:11 2011 @@ -31,6 +31,8 @@ Library ------- +- Issue #10875: Update Regular Expression HOWTO; patch by 'SilentGhost'. + - Issue #10869: Fixed bug where ast.increment_lineno modified the root node twice. From python-checkins at python.org Mon Jan 10 22:55:34 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 10 Jan 2011 22:55:34 +0100 (CET) Subject: [Python-checkins] r87906 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110110215534.82887EE981@mail.python.org> Author: alexander.belopolsky Date: Mon Jan 10 22:55:34 2011 New Revision: 87906 Log: Added entries about removal of year 1900 limit. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Mon Jan 10 22:55:34 2011 @@ -839,6 +839,29 @@ (Contributed by Alexander Belopolsky in :issue:`1289118`, :issue:`5094`, :issue:`6641`, and :issue:`2706`.) +.. XXX + + * The ``strftime()`` method of :class:`~datetime.date` and + :class:`~datetime.datetime` are no longer restricted to years >= + 1900. The new supported year range is [1000, 9999]. (Contributed + by Alexander Belopolsky and Victor Stinner in :issue:`1777412`) + +.. XXX Add a section on time module. + + * The :func:`time.asctime` and :func:`time.ctime` functions no + longer call C library asctime. (Contributed by Alexander + Belopolsky in :issue:`8013`.) + + * Changed the rules for using 2-digit years in time tuples. The + :func:`time.asctime`, :func:`time.ctime` and + :func:`time.strftime` functions will now format any year when + ``time.accept2dyear`` is false and will accept years >= 1000 + otherwise. :func:`time.mktime` and :func:`time.strftime` now + accepts full range supported by the OS. Conversion of 2-digit + years to 4-digit is deprecated. (Contributed by Alexander + Belopolsky and Victor Stinner in :issue:`10827`.) + + abc --- From python-checkins at python.org Mon Jan 10 22:58:52 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 10 Jan 2011 22:58:52 +0100 (CET) Subject: [Python-checkins] r87907 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110110215852.3D4B8EE995@mail.python.org> Author: alexander.belopolsky Date: Mon Jan 10 22:58:52 2011 New Revision: 87907 Log: Removed time.ctime from the list of functions that take a time tuple argument Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Mon Jan 10 22:58:52 2011 @@ -853,7 +853,7 @@ Belopolsky in :issue:`8013`.) * Changed the rules for using 2-digit years in time tuples. The - :func:`time.asctime`, :func:`time.ctime` and + :func:`time.asctime` and :func:`time.strftime` functions will now format any year when ``time.accept2dyear`` is false and will accept years >= 1000 otherwise. :func:`time.mktime` and :func:`time.strftime` now From python-checkins at python.org Mon Jan 10 23:14:25 2011 From: python-checkins at python.org (ned.deily) Date: Mon, 10 Jan 2011 23:14:25 +0100 (CET) Subject: [Python-checkins] r87908 - in python/branches/py3k: Mac/Makefile.in Misc/NEWS Message-ID: <20110110221425.CFB2BE795@mail.python.org> Author: ned.deily Date: Mon Jan 10 23:14:25 2011 New Revision: 87908 Log: #10820: Fix OS X framework installs to support version-specific scripts (implemented in #10679). Modified: python/branches/py3k/Mac/Makefile.in python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Mac/Makefile.in ============================================================================== --- python/branches/py3k/Mac/Makefile.in (original) +++ python/branches/py3k/Mac/Makefile.in Mon Jan 10 23:14:25 2011 @@ -47,8 +47,7 @@ compileall=$(srcdir)/../Lib/compileall.py installapps: install_Python install_pythonw install_PythonLauncher install_IDLE \ - checkapplepython install_versionedtools - + checkapplepython install_pythonw: pythonw $(INSTALL_PROGRAM) $(STRIPFLAG) pythonw "$(DESTDIR)$(prefix)/bin/pythonw$(VERSION)" @@ -92,27 +91,6 @@ ln -fs "$(prefix)/bin/$${fn}" "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin/$${fn}" ;\ done -# By default most tools are installed without a version in their basename, to -# make it easier to install (and use) several python versions side-by-side move -# the tools to a version-specific name and add the non-versioned name as an -# alias. -install_versionedtools: - for fn in idle pydoc ;\ - do \ - if [ -h "$(DESTDIR)$(prefix)/bin/$${fn}3" ]; then \ - continue ;\ - fi ;\ - mv "$(DESTDIR)$(prefix)/bin/$${fn}3" "$(DESTDIR)$(prefix)/bin/$${fn}$(VERSION)" ;\ - ln -sf "$${fn}$(VERSION)" "$(DESTDIR)$(prefix)/bin/$${fn}3" ;\ - done - mv "$(DESTDIR)$(prefix)/bin/2to3" "$(DESTDIR)$(prefix)/bin/2to3-$(VERSION)" - ln -sf "2to3-$(VERSION)" "$(DESTDIR)$(prefix)/bin/2to3" - if [ ! -h "$(DESTDIR)$(prefix)/bin/python3-config" ]; then \ - mv "$(DESTDIR)$(prefix)/bin/python3-config" "$(DESTDIR)$(prefix)/bin/python$(VERSION)-config" ;\ - ln -sf "python$(VERSION)-config" "$(DESTDIR)$(prefix)/bin/python3-config" ; \ - fi - - pythonw: $(srcdir)/Tools/pythonw.c Makefile $(CC) $(LDFLAGS) -DPYTHONFRAMEWORK='"$(PYTHONFRAMEWORK)"' -o $@ $(srcdir)/Tools/pythonw.c -I.. -I$(srcdir)/../Include ../$(PYTHONFRAMEWORK).framework/Versions/$(VERSION)/$(PYTHONFRAMEWORK) Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 10 23:14:25 2011 @@ -189,6 +189,9 @@ Build ----- +- Issue #10820: Fix OS X framework installs to support version-specific + scripts (#10679). + - Issue #7716: Under Solaris, don't assume existence of /usr/xpg4/bin/grep in the configure script but use $GREP instead. Patch by Fabian Groffen. From python-checkins at python.org Mon Jan 10 23:15:19 2011 From: python-checkins at python.org (terry.reedy) Date: Mon, 10 Jan 2011 23:15:19 +0100 (CET) Subject: [Python-checkins] r87909 - in python/branches/release27-maint: Doc/howto/regex.rst Misc/NEWS Message-ID: <20110110221519.A6A12EE985@mail.python.org> Author: terry.reedy Date: Mon Jan 10 23:15:19 2011 New Revision: 87909 Log: Issue #10875: Update Regular Expression HOWTO; patch by 'SilentGhost'. Modified: python/branches/release27-maint/Doc/howto/regex.rst python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Doc/howto/regex.rst ============================================================================== --- python/branches/release27-maint/Doc/howto/regex.rst (original) +++ python/branches/release27-maint/Doc/howto/regex.rst Mon Jan 10 23:15:19 2011 @@ -5,7 +5,6 @@ **************************** :Author: A.M. Kuchling -:Release: 0.05 .. TODO: Document lookbehind assertions @@ -264,7 +263,7 @@ >>> import re >>> p = re.compile('ab*') >>> print p - <_sre.SRE_Pattern object at 80b4150> + <_sre.SRE_Pattern object at 0x...> :func:`re.compile` also accepts an optional *flags* argument, used to enable various special features and syntax variations. We'll go over the available @@ -377,7 +376,7 @@ >>> import re >>> p = re.compile('[a-z]+') >>> p - <_sre.SRE_Pattern object at 80c3c28> + <_sre.SRE_Pattern object at 0x...> Now, you can try matching various strings against the RE ``[a-z]+``. An empty string shouldn't match at all, since ``+`` means 'one or more repetitions'. @@ -395,7 +394,7 @@ >>> m = p.match('tempo') >>> print m - <_sre.SRE_Match object at 80c4f68> + <_sre.SRE_Match object at 0x...> Now you can query the :class:`MatchObject` for information about the matching string. :class:`MatchObject` instances also have several methods and @@ -434,7 +433,7 @@ >>> print p.match('::: message') None >>> m = p.search('::: message') ; print m - + <_sre.SRE_Match object at 0x...> >>> m.group() 'message' >>> m.span() @@ -485,7 +484,7 @@ >>> print re.match(r'From\s+', 'Fromage amk') None >>> re.match(r'From\s+', 'From amk Thu May 14 19:12:10 1998') - + <_sre.SRE_Match object at 0x...> Under the hood, these functions simply create a pattern object for you and call the appropriate method on it. They also store the compiled object in a @@ -686,7 +685,7 @@ line, the RE to use is ``^From``. :: >>> print re.search('^From', 'From Here to Eternity') - + <_sre.SRE_Match object at 0x...> >>> print re.search('^From', 'Reciting From Memory') None @@ -698,11 +697,11 @@ or any location followed by a newline character. :: >>> print re.search('}$', '{block}') - + <_sre.SRE_Match object at 0x...> >>> print re.search('}$', '{block} ') None >>> print re.search('}$', '{block}\n') - + <_sre.SRE_Match object at 0x...> To match a literal ``'$'``, use ``\$`` or enclose it inside a character class, as in ``[$]``. @@ -727,7 +726,7 @@ >>> p = re.compile(r'\bclass\b') >>> print p.search('no class at all') - + <_sre.SRE_Match object at 0x...> >>> print p.search('the declassified algorithm') None >>> print p.search('one subclass is') @@ -745,7 +744,7 @@ >>> print p.search('no class at all') None >>> print p.search('\b' + 'class' + '\b') - + <_sre.SRE_Match object at 0x...> Second, inside a character class, where there's no use for this assertion, ``\b`` represents the backspace character, for compatibility with Python's @@ -1315,7 +1314,7 @@ be *very* complicated. Use an HTML or XML parser module for such tasks.) -Not Using re.VERBOSE +Using re.VERBOSE -------------------- By now you've probably noticed that regular expressions are a very compact Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Mon Jan 10 23:15:19 2011 @@ -29,6 +29,8 @@ Library ------- +- Issue #10875: Update Regular Expression HOWTO; patch by 'SilentGhost'. + - Issue #10827: Changed the rules for 2-digit years. The time.asctime function will now format any year when ``time.accept2dyear`` is false and will accept years >= 1000 otherwise. The year range From python-checkins at python.org Mon Jan 10 23:56:14 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 10 Jan 2011 23:56:14 +0100 (CET) Subject: [Python-checkins] r87910 - in python/branches/py3k/Doc/library: datetime.rst time.rst Message-ID: <20110110225614.C2257EE981@mail.python.org> Author: alexander.belopolsky Date: Mon Jan 10 23:56:14 2011 New Revision: 87910 Log: Issue #2568: Removed bogus rationale for supporting tm_sec=61. Modified: python/branches/py3k/Doc/library/datetime.rst python/branches/py3k/Doc/library/time.rst Modified: python/branches/py3k/Doc/library/datetime.rst ============================================================================== --- python/branches/py3k/Doc/library/datetime.rst (original) +++ python/branches/py3k/Doc/library/datetime.rst Mon Jan 10 23:56:14 2011 @@ -1663,10 +1663,7 @@ The exact range of years for which :meth:`strftime` works also varies across platforms. Regardless of platform, years before 1000 cannot be -used with ``datetime`` module ``strftime()`` methods. The ``time`` -module ``strftime()`` function exibit different behavior depending on -the value of ``time.accept2dyear`` variable. See :ref:`Year 2000 -(Y2K) issues ` for details. +used with ``datetime`` module ``strftime()`` methods. +-----------+--------------------------------+-------+ | Directive | Meaning | Notes | @@ -1710,7 +1707,7 @@ | | AM or PM. | | +-----------+--------------------------------+-------+ | ``%S`` | Second as a decimal number | \(3) | -| | [00,61]. | | +| | [00,59]. | | +-----------+--------------------------------+-------+ | ``%U`` | Week number of the year | \(4) | | | (Sunday as the first day of | | @@ -1767,12 +1764,8 @@ the output hour field if the ``%I`` directive is used to parse the hour. (3) - The range really is ``0`` to ``61``; according to the Posix standard this - accounts for leap seconds and the (very rare) double leap seconds. - The :mod:`time` module may produce and does accept leap seconds since - it is based on the Posix standard, but the :mod:`datetime` module - does not accept leap seconds in :meth:`strptime` input nor will it - produce them in :func:`strftime` output. + Unlike :mod:`time` module, :mod:`datetime` module does not support + leap seconds. (4) When used with the :meth:`strptime` method, ``%U`` and ``%W`` are only used in Modified: python/branches/py3k/Doc/library/time.rst ============================================================================== --- python/branches/py3k/Doc/library/time.rst (original) +++ python/branches/py3k/Doc/library/time.rst Mon Jan 10 23:56:14 2011 @@ -308,7 +308,7 @@ | ``%y`` | Year without century as a decimal number | | | | [00,99]. | | +-----------+------------------------------------------------+-------+ - | ``%Y`` | Year with century as a decimal number. | | + | ``%Y`` | Year with century as a decimal number. | \(4) | | | | | +-----------+------------------------------------------------+-------+ | ``%Z`` | Time zone name (no characters if no time zone | | @@ -324,13 +324,20 @@ the output hour field if the ``%I`` directive is used to parse the hour. (2) - The range really is ``0`` to ``61``; this accounts for leap seconds and the - (very rare) double leap seconds. + The range really is ``0`` to ``61``; value ``60`` is valid in + timestamps representing leap seconds and value ``61`` is supported + for historical reasons. (3) When used with the :func:`strptime` function, ``%U`` and ``%W`` are only used in calculations when the day of the week and the year are specified. + (4) + Produces different results depending on the value of + ``time.accept2dyear`` variable. See :ref:`Year 2000 (Y2K) + issues ` for details. + + Here is an example, a format for dates compatible with that specified in the :rfc:`2822` Internet email standard. [#]_ :: From python-checkins at python.org Tue Jan 11 00:00:42 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 11 Jan 2011 00:00:42 +0100 (CET) Subject: [Python-checkins] r87911 - python/branches/py3k/Modules/pyexpat.c Message-ID: <20110110230042.21B31EE981@mail.python.org> Author: victor.stinner Date: Tue Jan 11 00:00:36 2011 New Revision: 87911 Log: Issue #9566: Fix pyparse.xmlparser.ParseFile() Fix readinst() if file.read(n) returns a bytes object longer than n: return -1 instead of the the buffer size to raise an exception. Simplify also the function code. Modified: python/branches/py3k/Modules/pyexpat.c Modified: python/branches/py3k/Modules/pyexpat.c ============================================================================== --- python/branches/py3k/Modules/pyexpat.c (original) +++ python/branches/py3k/Modules/pyexpat.c Tue Jan 11 00:00:36 2011 @@ -797,25 +797,13 @@ static int readinst(char *buf, int buf_size, PyObject *meth) { - PyObject *arg = NULL; - PyObject *bytes = NULL; - PyObject *str = NULL; - Py_ssize_t len = -1; + PyObject *str; + Py_ssize_t len; char *ptr; - if ((bytes = PyLong_FromLong(buf_size)) == NULL) - goto finally; - - if ((arg = PyTuple_New(1)) == NULL) { - Py_DECREF(bytes); - goto finally; - } - - PyTuple_SET_ITEM(arg, 0, bytes); - - str = PyObject_Call(meth, arg, NULL); + str = PyObject_CallFunction(meth, "n", buf_size); if (str == NULL) - goto finally; + goto error; if (PyBytes_Check(str)) ptr = PyBytes_AS_STRING(str); @@ -825,7 +813,7 @@ PyErr_Format(PyExc_TypeError, "read() did not return a bytes object (type=%.400s)", Py_TYPE(str)->tp_name); - goto finally; + goto error; } len = Py_SIZE(str); if (len > buf_size) { @@ -833,14 +821,16 @@ "read() returned too much data: " "%i bytes requested, %zd returned", buf_size, len); - goto finally; + goto error; } memcpy(buf, ptr, len); -finally: - Py_XDECREF(arg); - Py_XDECREF(str); - /* len <= buf_size <= INT_MAX (see above) */ + Py_DECREF(str); + /* len <= buf_size <= INT_MAX */ return (int)len; + +error: + Py_XDECREF(str); + return -1; } PyDoc_STRVAR(xmlparse_ParseFile__doc__, From python-checkins at python.org Tue Jan 11 00:13:22 2011 From: python-checkins at python.org (terry.reedy) Date: Tue, 11 Jan 2011 00:13:22 +0100 (CET) Subject: [Python-checkins] r87912 - python/branches/py3k/Doc/howto/regex.rst Message-ID: <20110110231322.01C3FEE9B2@mail.python.org> Author: terry.reedy Date: Tue Jan 11 00:13:21 2011 New Revision: 87912 Log: Issue #10875: Update Regular Expression HOWTO; last bit. Modified: python/branches/py3k/Doc/howto/regex.rst Modified: python/branches/py3k/Doc/howto/regex.rst ============================================================================== --- python/branches/py3k/Doc/howto/regex.rst (original) +++ python/branches/py3k/Doc/howto/regex.rst Tue Jan 11 00:13:21 2011 @@ -107,7 +107,10 @@ Some of the special sequences beginning with ``'\'`` represent predefined sets of characters that are often useful, such as the set of digits, the set of letters, or the set of anything that isn't whitespace. The following predefined -special sequences are available: +special sequences are a subset of those available. The equivalent classes are +for bytes patterns. For a complete list of sequences and expanded class +definitions for Unicode string patterns, see the last part of +:ref:`Regular Expression Syntax `. ``\d`` Matches any decimal digit; this is equivalent to the class ``[0-9]``. From python-checkins at python.org Tue Jan 11 00:16:24 2011 From: python-checkins at python.org (terry.reedy) Date: Tue, 11 Jan 2011 00:16:24 +0100 (CET) Subject: [Python-checkins] r87913 - python/branches/release31-maint/Doc/howto/regex.rst Message-ID: <20110110231624.8FBEAEE9AF@mail.python.org> Author: terry.reedy Date: Tue Jan 11 00:16:24 2011 New Revision: 87913 Log: Issue #10875: Update Regular Expression HOWTO; additional backport. Modified: python/branches/release31-maint/Doc/howto/regex.rst Modified: python/branches/release31-maint/Doc/howto/regex.rst ============================================================================== --- python/branches/release31-maint/Doc/howto/regex.rst (original) +++ python/branches/release31-maint/Doc/howto/regex.rst Tue Jan 11 00:16:24 2011 @@ -107,7 +107,10 @@ Some of the special sequences beginning with ``'\'`` represent predefined sets of characters that are often useful, such as the set of digits, the set of letters, or the set of anything that isn't whitespace. The following predefined -special sequences are available: +special sequences are a subset of those available. The equivalent classes are +for bytes patterns. For a complete list of sequences and expanded class +definitions for Unicode string patterns, see the last part of +:ref:`Regular Expression Syntax `. ``\d`` Matches any decimal digit; this is equivalent to the class ``[0-9]``. From python-checkins at python.org Tue Jan 11 00:28:33 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Tue, 11 Jan 2011 00:28:33 +0100 (CET) Subject: [Python-checkins] r87914 - python/branches/py3k/Doc/library/datetime.rst Message-ID: <20110110232833.6D998EE982@mail.python.org> Author: alexander.belopolsky Date: Tue Jan 11 00:28:33 2011 New Revision: 87914 Log: Improved description of %Y directive. Modified: python/branches/py3k/Doc/library/datetime.rst Modified: python/branches/py3k/Doc/library/datetime.rst ============================================================================== --- python/branches/py3k/Doc/library/datetime.rst (original) +++ python/branches/py3k/Doc/library/datetime.rst Tue Jan 11 00:28:33 2011 @@ -1661,10 +1661,6 @@ implementation. Note that the 1999 version of the C standard added additional format codes. -The exact range of years for which :meth:`strftime` works also varies -across platforms. Regardless of platform, years before 1000 cannot be -used with ``datetime`` module ``strftime()`` methods. - +-----------+--------------------------------+-------+ | Directive | Meaning | Notes | +===========+================================+=======+ @@ -1737,10 +1733,11 @@ | ``%y`` | Year without century as a | | | | decimal number [00,99]. | | +-----------+--------------------------------+-------+ -| ``%Y`` | Year with century as a decimal | | -| | number. | | +| ``%Y`` | Year with century as a decimal | \(5) | +| | number [0001,9999] (strptime), | | +| | [1000,9999] (strftime). | | +-----------+--------------------------------+-------+ -| ``%z`` | UTC offset in the form +HHMM | \(5) | +| ``%z`` | UTC offset in the form +HHMM | \(6) | | | or -HHMM (empty string if the | | | | the object is naive). | | +-----------+--------------------------------+-------+ @@ -1772,6 +1769,18 @@ calculations when the day of the week and the year are specified. (5) + For technical reasons, :meth:`strftime` method does not support + dates with year < 1000: ``t.strftime(format)`` will raise a + :exc:`ValueError` even if ``format`` does not contain ``%Y`` + directive. The :meth:`strptime` method can parse years in the full + [1, 9999] range, but years < 1000 must be zero-filled to 4-digit + width. + + .. versionchanged:: 3.2 + In previous versions, :meth:`strftime` method was restricted to + years >= 1900. + +(6) For example, if :meth:`utcoffset` returns ``timedelta(hours=-3, minutes=-30)``, ``%z`` is replaced with the string ``'-0330'``. From python-checkins at python.org Tue Jan 11 00:31:51 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Tue, 11 Jan 2011 00:31:51 +0100 (CET) Subject: [Python-checkins] r87915 - python/branches/py3k/Doc/library/datetime.rst Message-ID: <20110110233151.5A642EE987@mail.python.org> Author: alexander.belopolsky Date: Tue Jan 11 00:31:51 2011 New Revision: 87915 Log: Improved footnote for the %Y directive slightly. Modified: python/branches/py3k/Doc/library/datetime.rst Modified: python/branches/py3k/Doc/library/datetime.rst ============================================================================== --- python/branches/py3k/Doc/library/datetime.rst (original) +++ python/branches/py3k/Doc/library/datetime.rst Tue Jan 11 00:31:51 2011 @@ -1770,11 +1770,11 @@ (5) For technical reasons, :meth:`strftime` method does not support - dates with year < 1000: ``t.strftime(format)`` will raise a - :exc:`ValueError` even if ``format`` does not contain ``%Y`` - directive. The :meth:`strptime` method can parse years in the full - [1, 9999] range, but years < 1000 must be zero-filled to 4-digit - width. + dates before year 1000: ``t.strftime(format)`` will raise a + :exc:`ValueError` when ``t.year < 1000`` even if ``format`` does + not contain ``%Y`` directive. The :meth:`strptime` method can + parse years in the full [1, 9999] range, but years < 1000 must be + zero-filled to 4-digit width. .. versionchanged:: 3.2 In previous versions, :meth:`strftime` method was restricted to From python-checkins at python.org Tue Jan 11 00:38:15 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 11 Jan 2011 00:38:15 +0100 (CET) Subject: [Python-checkins] r87916 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110110233815.3C3FBEE982@mail.python.org> Author: raymond.hettinger Date: Tue Jan 11 00:38:15 2011 New Revision: 87916 Log: Fix typos and markup. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Tue Jan 11 00:38:15 2011 @@ -393,8 +393,8 @@ bytes to native strings using ``h.encode('utf-8').decode('latin-1')``. * Values yielded by an application or sent using the :meth:`write` method - must be byte strings. The :func:`start_response` function and environ - must use native strings. The two cannot be mixed. + must be byte strings. The :func:`start_response` function and environ + must use native strings. The two cannot be mixed. For server implementers writing CGI-to-WSGI pathways or other CGI-style protocols, the users must to be able access the environment using native strings @@ -437,7 +437,7 @@ optimize=0, dont_write_bytecode=0, no_user_site=0, no_site=0, ignore_environment=0, verbose=0, bytes_warning=0, quiet=1) - (Contributed by Marcin Wojdyr in issue:`1772833`). + (Contributed by Marcin Wojdyr in :issue:`1772833`). * The :func:`hasattr` function works by calling :func:`getattr` and detecting whether an exception is raised. This technique allows it to detect methods @@ -498,7 +498,7 @@ (See :issue:`4617`.) * The internal :c:type:`structsequence` tool now creates subclasses of tuple. - This means that C generated structures like those returned by :func:`os.stat`, + This means that C structures like those returned by :func:`os.stat`, :func:`time.gmtime`, and :func:`sys.version_info` now work like a :term:`named tuple` and now work with functions and methods that expect a tuple as an argument. The is a big step forward in making the C @@ -591,9 +591,8 @@ Another significant win is the addition of substantially better support for *SSL* connections and security certificates. -In addition, more functions and classes now have a :term:`context manager` to -support convenient and reliable resource clean-up using the -:keyword:`with`-statement. +In addition, more classes now implement a :term:`context manager` to support +convenient and reliable resource clean-up using the :keyword:`with`-statement. email ----- @@ -1014,7 +1013,7 @@ The :mod:`gzip` module also gains the :func:`~gzip.compress` and :func:`~gzip.decompress` functions for easier in-memory compression and -decompression. Keep in mind that text needs to be encoded in to :class:`bytes` +decompression. Keep in mind that text needs to be encoded as :class:`bytes` before compressing and decompressing: >>> s = 'Three shall be the number thou shalt count, ' @@ -1373,7 +1372,7 @@ * A :file:`.pdbrc` script file can contain ``continue`` and ``next`` commands that continue debugging. * The :class:`Pdb` class constructor now accepts a *nosigint* argument. -* New commands: ``l(list)``, ``ll(long list`` and ``source`` for +* New commands: ``l(list)``, ``ll(long list)`` and ``source`` for listing source code. * New commands: ``display`` and ``undisplay`` for showing or hiding the value of an expression if it has changed. @@ -1634,10 +1633,10 @@ accompanied by tables of cheatsheet-style summaries to provide an overview and memory jog without having to read all of the docs. -In some cases, the pure Python source code can be helpful adjunct to the docs, -so now some modules feature quick links to the latest version of the source -code. For example, the :mod:`functools` module documentation has a quick link -at the top labeled: *Source code* :source:`Lib/functools.py`. +In some cases, the pure Python source code can be a helpful adjunct to the +documentation, so now many modules now feature quick links to the latest version +of the source code. For example, the :mod:`functools` module documentation has +a quick link at the top labeled: **Source code** :source:`Lib/functools.py`. The docs now contain more examples and recipes. In particular, :mod:`re` module has an extensive section, :ref:`re-examples`. Likewise, the :mod:`itertools` @@ -1783,7 +1782,7 @@ * :class:`bytearray` objects can no longer be used as filenames; instead, they should be converted to :class:`bytes`. -* PyArg_Parse*() functions: +* ``PyArg_Parse*()`` functions: * "t#" format has been removed: use "s#" or "s*" instead * "w" and "w#" formats has been removed: use "w*" instead @@ -1802,7 +1801,7 @@ ``random.seed(s, version=1)``. * The previously deprecated :func:`string.maketrans` function has been removed - in favor of the static method :meth:`bytes.maketrans` and + in favor of the static methods :meth:`bytes.maketrans` and :meth:`bytearray.maketrans`. This change solves the confusion around which types were supported by the :mod:`string` module. Now, :class:`str`, :class:`bytes`, and :class:`bytearray` each have their own **maketrans** and From python-checkins at python.org Tue Jan 11 01:04:12 2011 From: python-checkins at python.org (victor.stinner) Date: Tue, 11 Jan 2011 01:04:12 +0100 (CET) Subject: [Python-checkins] r87917 - in python/branches/py3k/Modules: _io/fileio.c posixmodule.c Message-ID: <20110111000412.F3BE3EE9A2@mail.python.org> Author: victor.stinner Date: Tue Jan 11 01:04:12 2011 New Revision: 87917 Log: Issue #9611: remove useless and dangerous explicit conversion to size_t Modified: python/branches/py3k/Modules/_io/fileio.c python/branches/py3k/Modules/posixmodule.c Modified: python/branches/py3k/Modules/_io/fileio.c ============================================================================== --- python/branches/py3k/Modules/_io/fileio.c (original) +++ python/branches/py3k/Modules/_io/fileio.c Tue Jan 11 01:04:12 2011 @@ -530,7 +530,7 @@ len = INT_MAX; n = read(self->fd, pbuf.buf, (int)len); #else - n = read(self->fd, pbuf.buf, (size_t)len); + n = read(self->fd, pbuf.buf, len); #endif Py_END_ALLOW_THREADS } else @@ -716,7 +716,7 @@ len = INT_MAX; n = write(self->fd, pbuf.buf, (int)len); #else - n = write(self->fd, pbuf.buf, (size_t)len); + n = write(self->fd, pbuf.buf, len); #endif Py_END_ALLOW_THREADS } else Modified: python/branches/py3k/Modules/posixmodule.c ============================================================================== --- python/branches/py3k/Modules/posixmodule.c (original) +++ python/branches/py3k/Modules/posixmodule.c Tue Jan 11 01:04:12 2011 @@ -5712,7 +5712,7 @@ len = INT_MAX; size = write(fd, pbuf.buf, (int)len); #else - size = write(fd, pbuf.buf, (size_t)len); + size = write(fd, pbuf.buf, len); #endif Py_END_ALLOW_THREADS PyBuffer_Release(&pbuf); From python-checkins at python.org Tue Jan 11 01:07:12 2011 From: python-checkins at python.org (terry.reedy) Date: Tue, 11 Jan 2011 01:07:12 +0100 (CET) Subject: [Python-checkins] r87918 - python/branches/release27-maint/Doc/howto/regex.rst Message-ID: <20110111000712.C61D6EE99E@mail.python.org> Author: terry.reedy Date: Tue Jan 11 01:07:12 2011 New Revision: 87918 Log: Issue #10875: Update Regular Expression HOWTO; additional backport with 2.7 modification. Modified: python/branches/release27-maint/Doc/howto/regex.rst Modified: python/branches/release27-maint/Doc/howto/regex.rst ============================================================================== --- python/branches/release27-maint/Doc/howto/regex.rst (original) +++ python/branches/release27-maint/Doc/howto/regex.rst Tue Jan 11 01:07:12 2011 @@ -112,7 +112,10 @@ Some of the special sequences beginning with ``'\'`` represent predefined sets of characters that are often useful, such as the set of digits, the set of letters, or the set of anything that isn't whitespace. The following predefined -special sequences are available: +special sequences are a subset of those available. The equivalent classes are +for byte string patterns. For a complete list of sequences and expanded class +definitions for Unicode string patterns, see the last part of +:ref:`Regular Expression Syntax `. ``\d`` Matches any decimal digit; this is equivalent to the class ``[0-9]``. From python-checkins at python.org Tue Jan 11 02:21:25 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Tue, 11 Jan 2011 02:21:25 +0100 (CET) Subject: [Python-checkins] r87919 - in python/branches/py3k: Lib/test/test_time.py Modules/timemodule.c Message-ID: <20110111012125.62A9AEE998@mail.python.org> Author: alexander.belopolsky Date: Tue Jan 11 02:21:25 2011 New Revision: 87919 Log: Issue #1726687: time.mktime() will now correctly compute value one second before epoch. Original patch by Peter Wang, reported by Martin Blais. Modified: python/branches/py3k/Lib/test/test_time.py python/branches/py3k/Modules/timemodule.c Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Tue Jan 11 02:21:25 2011 @@ -339,6 +339,19 @@ self.assertEqual(self.yearstr(-1234), '-1234') self.assertEqual(self.yearstr(-123456), '-123456') + + def test_mktime(self): + # Issue #1726687 + for t in (-2, -1, 0, 1): + try: + tt = time.localtime(t) + except (OverflowError, ValueError): + pass + self.assertEqual(time.mktime(tt), t) + # Hopefully year = -1 is enough to make OS mktime fail + self.assertRaises(OverflowError, time.mktime, + (-1, 1, 1, 0, 0, 0, -1, -1, -1)) + class TestAsctimeAccept2dYear(_TestAsctimeYear, _Test2dYear): pass Modified: python/branches/py3k/Modules/timemodule.c ============================================================================== --- python/branches/py3k/Modules/timemodule.c (original) +++ python/branches/py3k/Modules/timemodule.c Tue Jan 11 02:21:25 2011 @@ -694,8 +694,11 @@ time_t tt; if (!gettmarg(tup, &buf)) return NULL; + buf.tm_wday = -1; /* sentinel; original value ignored */ tt = mktime(&buf); - if (tt == (time_t)(-1)) { + /* Return value of -1 does not necessarily mean an error, but tm_wday + * cannot remain set to -1 if mktime succedded. */ + if (tt == (time_t)(-1) && buf.tm_wday == -1) { PyErr_SetString(PyExc_OverflowError, "mktime argument out of range"); return NULL; From python-checkins at python.org Tue Jan 11 02:35:22 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Tue, 11 Jan 2011 02:35:22 +0100 (CET) Subject: [Python-checkins] r87920 - python/branches/py3k/Lib/test/test_time.py Message-ID: <20110111013522.80158EE98E@mail.python.org> Author: alexander.belopolsky Date: Tue Jan 11 02:35:22 2011 New Revision: 87920 Log: Make mktime test more robust. Modified: python/branches/py3k/Lib/test/test_time.py Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Tue Jan 11 02:35:22 2011 @@ -348,9 +348,13 @@ except (OverflowError, ValueError): pass self.assertEqual(time.mktime(tt), t) - # Hopefully year = -1 is enough to make OS mktime fail - self.assertRaises(OverflowError, time.mktime, - (-1, 1, 1, 0, 0, 0, -1, -1, -1)) + # It may not be possible to reliably make mktime return error + # on all platfom. This will make sure that no other exception + # than OverflowError is raised for an extreme value. + try: + time.mktime((-1, 1, 1, 0, 0, 0, -1, -1, -1)) + except OverflowError: + pass class TestAsctimeAccept2dYear(_TestAsctimeYear, _Test2dYear): pass From python-checkins at python.org Tue Jan 11 03:22:16 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Tue, 11 Jan 2011 03:22:16 +0100 (CET) Subject: [Python-checkins] r87921 - python/branches/py3k/Lib/test/test_time.py Message-ID: <20110111022216.E08CEEE988@mail.python.org> Author: alexander.belopolsky Date: Tue Jan 11 03:22:16 2011 New Revision: 87921 Log: This should fix mktime test on Windows Modified: python/branches/py3k/Lib/test/test_time.py Modified: python/branches/py3k/Lib/test/test_time.py ============================================================================== --- python/branches/py3k/Lib/test/test_time.py (original) +++ python/branches/py3k/Lib/test/test_time.py Tue Jan 11 03:22:16 2011 @@ -347,7 +347,8 @@ tt = time.localtime(t) except (OverflowError, ValueError): pass - self.assertEqual(time.mktime(tt), t) + else: + self.assertEqual(time.mktime(tt), t) # It may not be possible to reliably make mktime return error # on all platfom. This will make sure that no other exception # than OverflowError is raised for an extreme value. From python-checkins at python.org Tue Jan 11 03:42:15 2011 From: python-checkins at python.org (nick.coghlan) Date: Tue, 11 Jan 2011 03:42:15 +0100 (CET) Subject: [Python-checkins] r87922 - python/branches/py3k/Misc/developers.txt Message-ID: <20110111024215.A026BEE98A@mail.python.org> Author: nick.coghlan Date: Tue Jan 11 03:42:15 2011 New Revision: 87922 Log: developers.txt entry for Eli (at Brett's request) Modified: python/branches/py3k/Misc/developers.txt Modified: python/branches/py3k/Misc/developers.txt ============================================================================== --- python/branches/py3k/Misc/developers.txt (original) +++ python/branches/py3k/Misc/developers.txt Tue Jan 11 03:42:15 2011 @@ -23,6 +23,9 @@ Permissions History ------------------- +- Eli Bendersky was given commit access on Jan 11 2011 by BAC, + on recommendation by Terry Reedy and Nick Coghlan. + - Ned Deily was given commit access on Jan 9 2011 by MvL, on recommendation by Antoine Pitrou. From solipsis at pitrou.net Tue Jan 11 05:05:22 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Tue, 11 Jan 2011 05:05:22 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r87921): sum=0 Message-ID: py3k results for svn r87921 (hg cset 146c739bcd3e) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflogYS5xVf', '-x'] From python-checkins at python.org Tue Jan 11 08:51:13 2011 From: python-checkins at python.org (georg.brandl) Date: Tue, 11 Jan 2011 08:51:13 +0100 (CET) Subject: [Python-checkins] r87923 - peps/trunk/pep-0392.txt Message-ID: <20110111075113.607F0EE987@mail.python.org> Author: georg.brandl Date: Tue Jan 11 08:51:13 2011 New Revision: 87923 Log: Delay a bit more. Modified: peps/trunk/pep-0392.txt Modified: peps/trunk/pep-0392.txt ============================================================================== --- peps/trunk/pep-0392.txt (original) +++ peps/trunk/pep-0392.txt Tue Jan 11 08:51:13 2011 @@ -43,9 +43,9 @@ (No new features beyond this point.) - 3.2 beta 2: December 18, 2010 -- 3.2 candidate 1: January 8, 2011 -- 3.2 candidate 2: January 22, 2011 -- 3.2 final: February 5, 2011 +- 3.2 candidate 1: January 15, 2011 +- 3.2 candidate 2: January 29, 2011 +- 3.2 final: February 12, 2011 .. don't forget to update final date above as well From python-checkins at python.org Tue Jan 11 09:49:10 2011 From: python-checkins at python.org (raymond.hettinger) Date: Tue, 11 Jan 2011 09:49:10 +0100 (CET) Subject: [Python-checkins] r87924 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110111084910.68665EE982@mail.python.org> Author: raymond.hettinger Date: Tue Jan 11 09:49:10 2011 New Revision: 87924 Log: Add a todo. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Tue Jan 11 09:49:10 2011 @@ -817,6 +817,8 @@ (Contributed by Raymond Hettinger.) +.. XXX threading.py and Barrier objects + datetime -------- From python-checkins at python.org Tue Jan 11 11:05:20 2011 From: python-checkins at python.org (nick.coghlan) Date: Tue, 11 Jan 2011 11:05:20 +0100 (CET) Subject: [Python-checkins] r87925 - in python/branches/py3k/Lib/test: support.py test_zipimport_support.py Message-ID: <20110111100520.BFE78EE985@mail.python.org> Author: nick.coghlan Date: Tue Jan 11 11:05:20 2011 New Revision: 87925 Log: Issue 10556: test_zipimport_support implicitly imports too many modules (including _ssl) to safely clobber sys.modules after each test Modified: python/branches/py3k/Lib/test/support.py python/branches/py3k/Lib/test/test_zipimport_support.py Modified: python/branches/py3k/Lib/test/support.py ============================================================================== --- python/branches/py3k/Lib/test/support.py (original) +++ python/branches/py3k/Lib/test/support.py Tue Jan 11 11:05:20 2011 @@ -1199,6 +1199,12 @@ if k.startswith('encodings.')] sys.modules.clear() sys.modules.update(encodings) + # XXX: This kind of problem can affect more than just encodings. In particular + # extension modules (such as _ssl) don't cope with releoding properly. + # Really, test modules should be cleaning out the test specific modules they + # know they added (ala test_runpy) rather than relying on this function (as + # test_importhooks and test_pkg do currently). + # Implicitly imported *real* modules should be left alone (see issue 10556). sys.modules.update(oldmodules) #======================================================================= Modified: python/branches/py3k/Lib/test/test_zipimport_support.py ============================================================================== --- python/branches/py3k/Lib/test/test_zipimport_support.py (original) +++ python/branches/py3k/Lib/test/test_zipimport_support.py Tue Jan 11 11:05:20 2011 @@ -13,6 +13,7 @@ import inspect import linecache import pdb +import unittest from test.script_helper import (spawn_python, kill_python, assert_python_ok, temp_dir, make_script, make_zip_script) @@ -29,7 +30,6 @@ # Retrieve some helpers from other test cases from test import test_doctest, sample_doctest -from test.test_importhooks import ImportHooksBaseTestCase def _run_object_doctest(obj, module): @@ -59,17 +59,28 @@ -class ZipSupportTests(ImportHooksBaseTestCase): - # We use the ImportHooksBaseTestCase to restore +class ZipSupportTests(unittest.TestCase): + # This used to use the ImportHooksBaseTestCase to restore # the state of the import related information - # in the sys module after each test + # in the sys module after each test. However, that restores + # *too much* information and breaks for the invocation of + # of test_doctest. So we do our own thing and leave + # sys.modules alone. # We also clear the linecache and zipimport cache # just to avoid any bogus errors due to name reuse in the tests def setUp(self): linecache.clearcache() zipimport._zip_directory_cache.clear() - ImportHooksBaseTestCase.setUp(self) - + self.path = sys.path[:] + self.meta_path = sys.meta_path[:] + self.path_hooks = sys.path_hooks[:] + sys.path_importer_cache.clear() + + def tearDown(self): + sys.path[:] = self.path + sys.meta_path[:] = self.meta_path + sys.path_hooks[:] = self.path_hooks + sys.path_importer_cache.clear() def test_inspect_getsource_issue4223(self): test_src = "def foo(): pass\n" From python-checkins at python.org Tue Jan 11 11:24:34 2011 From: python-checkins at python.org (eric.smith) Date: Tue, 11 Jan 2011 11:24:34 +0100 (CET) Subject: [Python-checkins] r87926 - python/branches/py3k/Lib/test/support.py Message-ID: <20110111102434.A2162EE988@mail.python.org> Author: eric.smith Date: Tue Jan 11 11:24:34 2011 New Revision: 87926 Log: Typo. Modified: python/branches/py3k/Lib/test/support.py Modified: python/branches/py3k/Lib/test/support.py ============================================================================== --- python/branches/py3k/Lib/test/support.py (original) +++ python/branches/py3k/Lib/test/support.py Tue Jan 11 11:24:34 2011 @@ -1200,7 +1200,7 @@ sys.modules.clear() sys.modules.update(encodings) # XXX: This kind of problem can affect more than just encodings. In particular - # extension modules (such as _ssl) don't cope with releoding properly. + # extension modules (such as _ssl) don't cope with reloading properly. # Really, test modules should be cleaning out the test specific modules they # know they added (ala test_runpy) rather than relying on this function (as # test_importhooks and test_pkg do currently). From python-checkins at python.org Tue Jan 11 13:21:37 2011 From: python-checkins at python.org (eric.araujo) Date: Tue, 11 Jan 2011 13:21:37 +0100 (CET) Subject: [Python-checkins] r87927 - python/branches/release31-maint/Misc/maintainers.rst Message-ID: <20110111122137.5C838EE987@mail.python.org> Author: eric.araujo Date: Tue Jan 11 13:21:37 2011 New Revision: 87927 Log: Synchronize maintainers file Modified: python/branches/release31-maint/Misc/maintainers.rst Modified: python/branches/release31-maint/Misc/maintainers.rst ============================================================================== --- python/branches/release31-maint/Misc/maintainers.rst (original) +++ python/branches/release31-maint/Misc/maintainers.rst Tue Jan 11 13:21:37 2011 @@ -63,7 +63,7 @@ bisect rhettinger builtins bz2 -calendar +calendar rhettinger cgi cgitb chunk @@ -72,7 +72,8 @@ code codecs lemburg, doerwalter codeop -collections rhettinger, stutzbach +collections rhettinger +collections._abcoll rhettinger, stutzbach colorsys compileall configparser lukasz.langa @@ -81,10 +82,10 @@ copyreg alexandre.vassalotti cProfile crypt -csv +csv skip.montanaro ctypes theller curses -datetime alexander.belopolsky +datetime belopolsky dbm decimal facundobatista, rhettinger, mark.dickinson difflib tim_one @@ -104,7 +105,7 @@ fpectl fractions mark.dickinson, rhettinger ftplib giampaolo.rodola -functools +functools ncoghlan, rhettinger gc pitrou getopt getpass @@ -125,7 +126,7 @@ inspect io pitrou, benjamin.peterson, stutzbach itertools rhettinger -json bob.ippolito (inactive) +json bob.ippolito (inactive), rhettinger keyword lib2to3 benjamin.peterson linecache @@ -212,18 +213,18 @@ test textwrap georg.brandl threading pitrou -time alexander.belopolsky +time belopolsky timeit georg.brandl tkinter gpolo token georg.brandl tokenize -trace alexander.belopolsky +trace belopolsky traceback georg.brandl* tty turtle gregorlingl types unicodedata loewis, lemburg, ezio.melotti -unittest michael.foord +unittest michael.foord, ezio.melotti urllib orsenthil uu uuid @@ -300,9 +301,9 @@ release management tarek, lemburg, benjamin.peterson, barry, loewis, gvanrossum, anthonybaxter str.format eric.smith -testing michael.foord, pitrou, giampaolo.rodola +testing michael.foord, pitrou, giampaolo.rodola, ezio.melotti threads pitrou -time and dates lemburg +time and dates lemburg, belopolsky unicode lemburg, ezio.melotti, haypo version control ================== =========== From python-checkins at python.org Tue Jan 11 13:22:14 2011 From: python-checkins at python.org (eric.araujo) Date: Tue, 11 Jan 2011 13:22:14 +0100 (CET) Subject: [Python-checkins] r87928 - python/branches/release27-maint/Misc/maintainers.rst Message-ID: <20110111122214.4604BEE987@mail.python.org> Author: eric.araujo Date: Tue Jan 11 13:22:14 2011 New Revision: 87928 Log: Synchronize maintainers file Modified: python/branches/release27-maint/Misc/maintainers.rst Modified: python/branches/release27-maint/Misc/maintainers.rst ============================================================================== --- python/branches/release27-maint/Misc/maintainers.rst (original) +++ python/branches/release27-maint/Misc/maintainers.rst Tue Jan 11 13:22:14 2011 @@ -65,7 +65,7 @@ binhex bisect rhettinger bz2 -calendar +calendar rhettinger cgi CGIHTTPServer cgitb @@ -75,7 +75,8 @@ code codecs lemburg, doerwalter codeop -collections rhettinger, stutzbach +collections rhettinger +collections._abcoll rhettinger, stutzbach colorsys compileall ConfigParser lukasz.langa @@ -84,10 +85,10 @@ copy_reg alexandre.vassalotti cProfile crypt -csv +csv skip.montanaro ctypes theller curses -datetime alexander.belopolsky +datetime belopolsky dbm decimal facundobatista, rhettinger, mark.dickinson difflib tim_one @@ -107,7 +108,7 @@ fpectl fractions mark.dickinson, rhettinger ftplib giampaolo.rodola -functools +functools ncoghlan, rhettinger gc pitrou getopt getpass @@ -130,7 +131,7 @@ inspect io pitrou, benjamin.peterson, stutzbach itertools rhettinger -json bob.ippolito (inactive) +json bob.ippolito (inactive), rhettinger keyword lib2to3 benjamin.peterson linecache @@ -218,18 +219,18 @@ test textwrap georg.brandl threading pitrou -time alexander.belopolsky +time belopolsky timeit georg.brandl Tkinter gpolo token georg.brandl tokenize -trace alexander.belopolsky +trace belopolsky traceback georg.brandl* tty turtle gregorlingl types unicodedata loewis, lemburg, ezio.melotti -unittest michael.foord +unittest michael.foord, ezio.melotti urllib orsenthil uu uuid @@ -305,9 +306,9 @@ release management tarek, lemburg, benjamin.peterson, barry, loewis, gvanrossum, anthonybaxter str.format eric.smith -testing michael.foord, pitrou, giampaolo.rodola +testing michael.foord, pitrou, giampaolo.rodola, ezio.melotti threads pitrou -time and dates lemburg +time and dates lemburg, belopolsky unicode lemburg, ezio.melotti, haypo version control ================== =========== From python-checkins at python.org Tue Jan 11 15:07:13 2011 From: python-checkins at python.org (stefan.krah) Date: Tue, 11 Jan 2011 15:07:13 +0100 (CET) Subject: [Python-checkins] r87929 - in python/branches/py3k-cdecimal/Modules/cdecimal: basearith.c basearith.h bits.h cdecimal.c crt.c io.c mpdecimal.c transpose.c umodarith.h Message-ID: <20110111140713.2DF04EE983@mail.python.org> Author: stefan.krah Date: Tue Jan 11 15:07:12 2011 New Revision: 87929 Log: Whitespace only. Modified: python/branches/py3k-cdecimal/Modules/cdecimal/basearith.c python/branches/py3k-cdecimal/Modules/cdecimal/basearith.h python/branches/py3k-cdecimal/Modules/cdecimal/bits.h python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c python/branches/py3k-cdecimal/Modules/cdecimal/crt.c python/branches/py3k-cdecimal/Modules/cdecimal/io.c python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c python/branches/py3k-cdecimal/Modules/cdecimal/transpose.c python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h Modified: python/branches/py3k-cdecimal/Modules/cdecimal/basearith.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/basearith.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/basearith.c Tue Jan 11 15:07:12 2011 @@ -468,7 +468,7 @@ _mpd_divmod_pow10(&hprev, &rest, src[q], r); _mpd_divmod_pow10(&rnd, &rest, rest, r-1); - + if (rest == 0 && q > 0) { rest = !_mpd_isallzero(src, q); } Modified: python/branches/py3k-cdecimal/Modules/cdecimal/basearith.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/basearith.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/basearith.h Tue Jan 11 15:07:12 2011 @@ -96,7 +96,7 @@ h += hi; h -= MPD_RADIX; - *q = (h - t); + *q = (h - t); *r = l + (MPD_RADIX & h); } #else Modified: python/branches/py3k-cdecimal/Modules/cdecimal/bits.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/bits.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/bits.h Tue Jan 11 15:07:12 2011 @@ -105,7 +105,7 @@ * Caller has to make sure that a is not 0. */ static inline int -mpd_bsr(mpd_size_t a) +mpd_bsr(mpd_size_t a) { mpd_size_t retval; @@ -128,7 +128,7 @@ * Caller has to make sure that a is not 0. */ static inline int -mpd_bsf(mpd_size_t a) +mpd_bsf(mpd_size_t a) { mpd_size_t retval; @@ -154,7 +154,7 @@ * Caller has to make sure that a is not 0. */ static inline int __cdecl -mpd_bsr(mpd_size_t a) +mpd_bsr(mpd_size_t a) { unsigned long retval; @@ -172,7 +172,7 @@ * Caller has to make sure that a is not 0. */ static inline int __cdecl -mpd_bsf(mpd_size_t a) +mpd_bsf(mpd_size_t a) { unsigned long retval; Modified: python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c Tue Jan 11 15:07:12 2011 @@ -391,7 +391,7 @@ if (ctx->traps&status) { PyObject *ex, *siglist; - ex = flags_as_exception(ctx->traps&status); + ex = flags_as_exception(ctx->traps&status); if (ex == NULL) { return 1; /* GCOV_NOT_REACHED */ } @@ -498,7 +498,7 @@ } return PyDict_Type.tp_richcompare(a, b, op); } - + static int signaldict_contains(PyObject *self, PyObject *key) { @@ -2234,11 +2234,11 @@ } k--; - if ((d1 = mpd_qnew()) == NULL) { + if ((d1 = mpd_qnew()) == NULL) { Py_DECREF(n_d); /* GCOV_UNLIKELY */ return NULL; /* GCOV_UNLIKELY */ } - if ((d2 = mpd_qnew()) == NULL) { + if ((d2 = mpd_qnew()) == NULL) { mpd_del(d1); /* GCOV_UNLIKELY */ Py_DECREF(n_d); /* GCOV_UNLIKELY */ return NULL; /* GCOV_UNLIKELY */ @@ -3539,7 +3539,7 @@ CONVERT_BINOP(base, exp, &a, &b, ctx); if (mod != Py_None) { - if (!convert_op(mod, &c, ctx)) { + if (!convert_op(mod, &c, ctx)) { Py_DECREF(a); Py_DECREF(b); return (PyObject *) c; @@ -3549,7 +3549,7 @@ if ((result = dec_alloc()) == NULL) { return NULL; /* GCOV_UNLIKELY */ } - + if (c == NULL) { mpd_qpow(result->dec, a->dec, b->dec, ctx, &status); } Modified: python/branches/py3k-cdecimal/Modules/cdecimal/crt.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/crt.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/crt.c Tue Jan 11 15:07:12 2011 @@ -177,7 +177,7 @@ _crt_mulP1P2_3(t, s); _crt_add3(z, t); - _crt_add3(carry, z); + _crt_add3(carry, z); x1[i] = _crt_div3(carry, carry, MPD_RADIX); } Modified: python/branches/py3k-cdecimal/Modules/cdecimal/io.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/io.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/io.c Tue Jan 11 15:07:12 2011 @@ -153,7 +153,7 @@ } } break; - + } } @@ -269,7 +269,7 @@ if (fracdigits > MPD_MAX_PREC) { goto conversion_error; } - if (dec->exp < (MPD_SSIZE_MIN+1)+(mpd_ssize_t)fracdigits) { + if (dec->exp < (MPD_SSIZE_MIN+1)+(mpd_ssize_t)fracdigits) { dec->exp = MPD_SSIZE_MIN+1; } else { @@ -485,7 +485,7 @@ * * dplace: Position of the decimal point relative to the first * member of the coefficient. - * + * * 0.00000_.____._____000000. * ^ ^ ^ ^ * | | | | @@ -744,7 +744,7 @@ /* zero padding */ if (*cp == '0') { - /* zero padding implies alignment, which should not be + /* zero padding implies alignment, which should not be * specified twice. */ if (have_align) { return 0; @@ -884,7 +884,7 @@ static void _mpd_add_sep_dot(mpd_mbstr_t *dest, const char *src, mpd_ssize_t n_src, /* integer part and length */ - const char *sign, const char *dot, const char *rest, + const char *sign, const char *dot, const char *rest, mpd_spec_t *spec) { mpd_ssize_t n_sep, n_sign, consume; @@ -899,7 +899,7 @@ /* rest <= MPD_MAX_PREC */ _mbstr_copy_ascii(dest, rest, (mpd_ssize_t)strlen(rest)); - + if (dot) { _mbstr_copy_char(dest, dot, (mpd_ssize_t)strlen(dot)); } Modified: python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/mpdecimal.c Tue Jan 11 15:07:12 2011 @@ -1364,7 +1364,7 @@ * Check if the operand is NaN, copy to result and return 1 if this is * the case. Copying can fail since NaNs are allowed to have a payload that * does not fit in MPD_MINALLOC. - */ + */ int mpd_qcheck_nan(mpd_t *result, const mpd_t *a, const mpd_context_t *ctx, uint32_t *status) @@ -1383,7 +1383,7 @@ * Check if either operand is NaN, copy to result and return 1 if this * is the case. Copying can fail since NaNs are allowed to have a payload * that does not fit in MPD_MINALLOC. - */ + */ int mpd_qcheck_nans(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_context_t *ctx, uint32_t *status) @@ -1412,7 +1412,7 @@ * Check if one of the operands is NaN, copy to result and return 1 if this * is the case. Copying can fail since NaNs are allowed to have a payload * that does not fit in MPD_MINALLOC. - */ + */ static int mpd_qcheck_3nans(mpd_t *result, const mpd_t *a, const mpd_t *b, const mpd_t *c, const mpd_context_t *ctx, uint32_t *status) @@ -1513,7 +1513,7 @@ /* * Apply rounding to a decimal. Allow overflow of the precision. - */ + */ static inline void _mpd_apply_round_excess(mpd_t *dec, mpd_uint_t rnd, const mpd_context_t *ctx, uint32_t *status) @@ -1631,7 +1631,7 @@ if (mpd_iszerocoeff(dec)) { if (dec->exp < etiny) { dec->exp = etiny; - mpd_zerocoeff(dec); + mpd_zerocoeff(dec); *status |= MPD_Clamped; } return; @@ -1865,7 +1865,7 @@ * Compare the data of big and small. This function does the equivalent * of first shifting small to the left and then comparing the data of * big and small, except that no allocation for the left shift is needed. - */ + */ static int _mpd_basecmp(mpd_uint_t *big, mpd_uint_t *small, mpd_size_t n, mpd_size_t m, mpd_size_t shift) @@ -2269,7 +2269,7 @@ * Same as mpd_qshiftr(), but 'result' is a static array. It is the * caller's responsibility to make sure that the array is big enough. * The function cannot fail. - */ + */ mpd_uint_t mpd_qsshiftr(mpd_t *result, const mpd_t *a, mpd_ssize_t n) { @@ -3821,7 +3821,7 @@ * ACM Transactions on Mathematical Software, Vol. 12, No. 2, June 1986. * * Main differences: - * + * * - The number of iterations for the Horner scheme is calculated using the * C log10() function. * @@ -3854,7 +3854,7 @@ * this will also happen for t > 10 (32 bit) or (t > 19) (64 bit). */ #if defined(CONFIG_64) - #define MPD_EXP_MAX_T 19 + #define MPD_EXP_MAX_T 19 #elif defined(CONFIG_32) #define MPD_EXP_MAX_T 10 #endif @@ -4362,7 +4362,7 @@ * * 2) |log10(a)| >= adjexp(a), if adjexp(a) >= 0 * |log10(a)| > -adjexp(a)-1, if adjexp(a) < 0 - * + * * 3) |log(a)| > 2*|log10(a)| */ adjexp = mpd_adjexp(a); @@ -5460,7 +5460,7 @@ *status |= (workctx.status&MPD_Errors); } -/* +/* * The number closest to the first operand that is in the direction towards * the second operand. */ @@ -5530,7 +5530,7 @@ } } - *status |= workstatus; + *status |= workstatus; mpd_set_sign(result, resultsign); } @@ -5756,7 +5756,7 @@ * * Let (0 < x < 1 and y > 0) or (x > 1 and y < 0). (H3) * Let ub_omega(exp_clamp) < lb_zeta(x) + lb_theta(y) (H4) - * + * * Then: * log10(abs(exp_clamp)) < log10(abs(log10(x))) + log10(abs(y)). (4) * log10(x) * y < exp_clamp (5) @@ -5856,7 +5856,7 @@ } */ -/* The power function for real exponents */ +/* The power function for real exponents */ static void _mpd_qpow_real(mpd_t *result, const mpd_t *base, const mpd_t *exp, const mpd_context_t *ctx, uint32_t *status) @@ -6113,7 +6113,7 @@ mpd_qrem(&tbase, &tbase, &tmod, &maxcontext, status); mpd_qdivint(&texp, &texp, &two, &maxcontext, status); } - if (mpd_isspecial(&texp) || mpd_isspecial(&tbase) || + if (mpd_isspecial(&texp) || mpd_isspecial(&tbase) || mpd_isspecial(&tmod) || mpd_isspecial(result)) { /* MPD_Malloc_error */ goto mpd_errors; Modified: python/branches/py3k-cdecimal/Modules/cdecimal/transpose.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/transpose.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/transpose.c Tue Jan 11 15:07:12 2011 @@ -128,7 +128,7 @@ next = mulmod_size_t(next, r, m); hp = matrix + next*cols/2; - } + } memcpy(hp+offset, writebuf, stride*(sizeof *writebuf)); @@ -228,7 +228,7 @@ to += size; } } - } + } } } Modified: python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/umodarith.h Tue Jan 11 15:07:12 2011 @@ -79,7 +79,7 @@ ext_submod(mpd_uint_t a, mpd_uint_t b, mpd_uint_t m) { mpd_uint_t d; - + a = (a >= m) ? a - m : a; b = (b >= m) ? b - m : b; @@ -146,7 +146,7 @@ y <<= 32; lo = y + x; - if (lo < y) hi++; + if (lo < y) hi++; /* second reduction */ x = y = hi; @@ -157,7 +157,7 @@ y <<= 32; lo = y + x; - if (lo < y) hi++; + if (lo < y) hi++; return (hi || lo >= m ? lo - m : lo); } @@ -172,7 +172,7 @@ y <<= 34; lo = y + x; - if (lo < y) hi++; + if (lo < y) hi++; /* second reduction */ x = y = hi; @@ -183,7 +183,7 @@ y <<= 34; lo = y + x; - if (lo < y) hi++; + if (lo < y) hi++; /* third reduction */ x = y = hi; @@ -194,7 +194,7 @@ y <<= 34; lo = y + x; - if (lo < y) hi++; + if (lo < y) hi++; return (hi || lo >= m ? lo - m : lo); } @@ -209,7 +209,7 @@ y <<= 40; lo = y + x; - if (lo < y) hi++; + if (lo < y) hi++; /* second reduction */ x = y = hi; @@ -220,7 +220,7 @@ y <<= 40; lo = y + x; - if (lo < y) hi++; + if (lo < y) hi++; /* third reduction */ x = y = hi; @@ -231,7 +231,7 @@ y <<= 40; lo = y + x; - if (lo < y) hi++; + if (lo < y) hi++; return (hi || lo >= m ? lo - m : lo); } From python-checkins at python.org Tue Jan 11 15:08:25 2011 From: python-checkins at python.org (stefan.krah) Date: Tue, 11 Jan 2011 15:08:25 +0100 (CET) Subject: [Python-checkins] r87930 - python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c Message-ID: <20110111140825.84BF0EE983@mail.python.org> Author: stefan.krah Date: Tue Jan 11 15:08:25 2011 New Revision: 87930 Log: Fix precision range error message. Modified: python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c Modified: python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c ============================================================================== --- python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c (original) +++ python/branches/py3k-cdecimal/Modules/cdecimal/cdecimal.c Tue Jan 11 15:08:25 2011 @@ -799,7 +799,7 @@ ctx = CtxAddr(self); if (!mpd_qsetprec(ctx, x)) { return value_error_int( - "valid range for prec is [0, MAX_PREC]."); + "valid range for prec is [1, MAX_PREC]."); } return 0; From python-checkins at python.org Tue Jan 11 15:35:57 2011 From: python-checkins at python.org (stefan.krah) Date: Tue, 11 Jan 2011 15:35:57 +0100 (CET) Subject: [Python-checkins] r87931 - in python/branches/py3k-cdecimal/Lib/test/mpdecimal: config.h.in configure configure.in Message-ID: <20110111143557.4D732EE986@mail.python.org> Author: stefan.krah Date: Tue Jan 11 15:35:57 2011 New Revision: 87931 Log: Add specific test for the gcc ipa-pure-const bug. Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/config.h.in python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure.in Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/config.h.in ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/config.h.in (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/config.h.in Tue Jan 11 15:35:57 2011 @@ -1,8 +1,5 @@ /* config.h.in. Generated from configure.in by autoheader. */ -/* Define if the gcc version is 4.5.x. */ -#undef HAVE_GCC_4_5 - /* Define if we can use x64 gcc inline assembler. */ #undef HAVE_GCC_ASM_FOR_X64 @@ -16,6 +13,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define if gcc has the ipa-pure-const bug. */ +#undef HAVE_IPA_PURE_CONST_BUG + /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure Tue Jan 11 15:35:57 2011 @@ -4035,26 +4035,56 @@ ppro) MPD_CONFIG=$M32"-DCONFIG_32 -DPPRO -DASM" CONFIGURE_LDFLAGS=$M32 - # gcc-4.5 miscompiles inline asm: + # Some versions of gcc miscompile inline asm: # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html case $CC in *gcc*) - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc-4.5" >&5 -$as_echo_n "checking for gcc-4.5... " >&6; } - gcc_version=`$CC -dumpversion` - have_gcc_4_5=no - case $gcc_version in - 4.5*) - have_gcc_4_5=yes - MPD_CONFIG="$MPD_CONFIG -fno-ipa-pure-const" - -$as_echo "#define HAVE_GCC_4_5 1" >>confdefs.h - - ;; - esac - { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_4_5" >&5 -$as_echo "$have_gcc_4_5" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc ipa-pure-const bug" >&5 +$as_echo_n "checking for gcc ipa-pure-const bug... " >&6; } + saved_cflags="$CFLAGS" + CFLAGS="-O2" + if test "$cross_compiling" = yes; then : + have_ipa_pure_const_bug=undefined +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + __attribute__((noinline)) int + foo(int *p) { + int r; + asm ( "movl \$6, (%1)\n\t" + "xorl %0, %0\n\t" + : "=r" (r) : "r" (p) : "memory" + ); + return r; + } + int main() { + int p = 8; + if ((foo(&p) ? : p) != 6) + return 1; + return 0; + } + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + have_ipa_pure_const_bug=no +else + have_ipa_pure_const_bug=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$saved_cflags" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_ipa_pure_const_bug" >&5 +$as_echo "$have_ipa_pure_const_bug" >&6; } + if test "$have_ipa_pure_const_bug" = yes; then + MPD_CONFIG="$MPD_CONFIG -fno-ipa-pure-const" + +$as_echo "#define HAVE_IPA_PURE_CONST_BUG 1" >>confdefs.h + + fi ;; esac ;; Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure.in ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure.in (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/configure.in Tue Jan 11 15:35:57 2011 @@ -246,23 +246,41 @@ ppro) MPD_CONFIG=$M32"-DCONFIG_32 -DPPRO -DASM" CONFIGURE_LDFLAGS=$M32 - # gcc-4.5 miscompiles inline asm: + # Some versions of gcc miscompile inline asm: # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491 # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html case $CC in *gcc*) - AC_MSG_CHECKING(for gcc-4.5) - gcc_version=`$CC -dumpversion` - have_gcc_4_5=no - case $gcc_version in - 4.5*) - have_gcc_4_5=yes - MPD_CONFIG="$MPD_CONFIG -fno-ipa-pure-const" - AC_DEFINE(HAVE_GCC_4_5, 1, - [Define if the gcc version is 4.5.x.]) - ;; - esac - AC_MSG_RESULT($have_gcc_4_5) + AC_MSG_CHECKING(for gcc ipa-pure-const bug) + saved_cflags="$CFLAGS" + CFLAGS="-O2" + AC_RUN_IFELSE([AC_LANG_SOURCE([[ + __attribute__((noinline)) int + foo(int *p) { + int r; + asm ( "movl \$6, (%1)\n\t" + "xorl %0, %0\n\t" + : "=r" (r) : "r" (p) : "memory" + ); + return r; + } + int main() { + int p = 8; + if ((foo(&p) ? : p) != 6) + return 1; + return 0; + } + ]])], + [have_ipa_pure_const_bug=no], + [have_ipa_pure_const_bug=yes], + [have_ipa_pure_const_bug=undefined]) + CFLAGS="$saved_cflags" + AC_MSG_RESULT($have_ipa_pure_const_bug) + if test "$have_ipa_pure_const_bug" = yes; then + MPD_CONFIG="$MPD_CONFIG -fno-ipa-pure-const" + AC_DEFINE(HAVE_IPA_PURE_CONST_BUG, 1, + [Define if gcc has the ipa-pure-const bug.]) + fi ;; esac ;; From python-checkins at python.org Tue Jan 11 15:49:16 2011 From: python-checkins at python.org (stefan.krah) Date: Tue, 11 Jan 2011 15:49:16 +0100 (CET) Subject: [Python-checkins] r87932 - in python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests: cov.c fntcov.c karatsuba_fnt.c karatsuba_fnt2.c mpd_mpz_add.c mpd_mpz_divmod.c mpd_mpz_mul.c mpd_mpz_sub.c runtest.c test_transpose.c Message-ID: <20110111144916.4E6B8EE982@mail.python.org> Author: stefan.krah Date: Tue Jan 11 15:49:16 2011 New Revision: 87932 Log: Whitespace only. Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/cov.c python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/fntcov.c python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/karatsuba_fnt.c python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/karatsuba_fnt2.c python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_add.c python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_divmod.c python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_mul.c python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_sub.c python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/runtest.c python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/test_transpose.c Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/cov.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/cov.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/cov.c Tue Jan 11 15:49:16 2011 @@ -198,13 +198,13 @@ mpd_set_string(a, "nan", &ctx); ASSERT(mpd_qget_uint(a, &status) == MPD_UINT_MAX) ASSERT(status&MPD_Invalid_operation) - + /* non-integer */ status = 0; mpd_set_string(a, "2345e-1", &ctx); ASSERT(mpd_qget_uint(a, &status) == MPD_UINT_MAX) ASSERT(status&MPD_Invalid_operation) - + /* too large */ status = 0; mpd_set_uint(a, 8, &ctx); @@ -217,7 +217,7 @@ mpd_set_uint(a, ((uint64_t)MPD_SSIZE_MAX)+1, &ctx); ASSERT(mpd_qget_ssize(a, &status) == MPD_SSIZE_MAX) ASSERT(status&MPD_Invalid_operation) - + mpd_del(a); } Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/fntcov.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/fntcov.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/fntcov.c Tue Jan 11 15:49:16 2011 @@ -152,7 +152,7 @@ exit(1); } } - + mpd_free(fntresult); mpd_free(kresult); mpd_free(kfntresult); @@ -173,7 +173,7 @@ exit(1); } } - + mpd_free(fntresult); mpd_free(kresult); mpd_free(kfntresult); @@ -317,7 +317,7 @@ goto malloc_error; } - ASSERT(z->data[0] == 1) + ASSERT(z->data[0] == 1) for (k = 1; k < ylen; k++) { ASSERT(z->data[k] == 0) } Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/karatsuba_fnt.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/karatsuba_fnt.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/karatsuba_fnt.c Tue Jan 11 15:49:16 2011 @@ -91,7 +91,7 @@ exit(1); } } - + mpd_free(fntresult); mpd_free(kresult); } @@ -129,7 +129,7 @@ exit(1); } } - + mpd_free(fntresult); mpd_free(kresult); } Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/karatsuba_fnt2.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/karatsuba_fnt2.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/karatsuba_fnt2.c Tue Jan 11 15:49:16 2011 @@ -92,7 +92,7 @@ exit(1); } } - + mpd_free(fntresult); mpd_free(kresult); } @@ -130,7 +130,7 @@ exit(1); } } - + mpd_free(fntresult); mpd_free(kresult); } Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_add.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_add.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_add.c Tue Jan 11 15:49:16 2011 @@ -119,7 +119,7 @@ fprintf(stderr, " FAIL: seed = %"PRI_time_t"\n", seed); exit(1); } - + mpd_free(mpdresult); mpd_free(mpzresult); } Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_divmod.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_divmod.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_divmod.c Tue Jan 11 15:49:16 2011 @@ -135,7 +135,7 @@ fprintf(stderr, " FAIL: seed = %"PRI_time_t"\n", seed); exit(1); } - + mpd_free(q_mpd); mpd_free(r_mpd); mpd_free(q_mpz); Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_mul.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_mul.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_mul.c Tue Jan 11 15:49:16 2011 @@ -119,7 +119,7 @@ fprintf(stderr, " FAIL: seed = %"PRI_time_t"\n", seed); exit(1); } - + mpd_free(mpdresult); mpd_free(mpzresult); } Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_sub.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_sub.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/mpd_mpz_sub.c Tue Jan 11 15:49:16 2011 @@ -119,7 +119,7 @@ fprintf(stderr, " FAIL: seed = %"PRI_time_t"\n", seed); exit(1); } - + mpd_free(mpdresult); mpd_free(mpzresult); } Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/runtest.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/runtest.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/runtest.c Tue Jan 11 15:49:16 2011 @@ -632,7 +632,7 @@ static int scan_1op_result(mpd_t *op1, char **result, char *token[], mpd_context_t *ctx) { - /* operand 1 */ + /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } @@ -656,7 +656,7 @@ static int scan_1op_2results(mpd_t *op1, char **result1, char **result2, char *token[], mpd_context_t *ctx) { - /* operand 1 */ + /* operand 1 */ if (token[2] == NULL) { mpd_err_fatal("parse error at id %s", token[0]); } @@ -994,7 +994,7 @@ free(expected); } -/* +/* * Test a function returning pointer to const char, accepting: * op1, context */ Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/test_transpose.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/test_transpose.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/test_transpose.c Tue Jan 11 15:49:16 2011 @@ -145,7 +145,7 @@ next = mulmod_size_t(next, r, m); hp = matrix + next*cols/2; - } + } memcpy(hp+offset, writebuf, stride*(sizeof *writebuf)); @@ -245,7 +245,7 @@ to += size; } } - } + } } } From python-checkins at python.org Tue Jan 11 15:52:18 2011 From: python-checkins at python.org (stefan.krah) Date: Tue, 11 Jan 2011 15:52:18 +0100 (CET) Subject: [Python-checkins] r87933 - python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/runtest.c Message-ID: <20110111145218.7C195EE982@mail.python.org> Author: stefan.krah Date: Tue Jan 11 15:52:18 2011 New Revision: 87933 Log: Get rid of several 'unused' warnings. Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/runtest.c Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/runtest.c ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/runtest.c (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/tests/runtest.c Tue Jan 11 15:52:18 2011 @@ -3917,14 +3917,6 @@ check_equalmem(tmp, op, token[0]); } -/* unused for now */ -static inline void -add_clarification(char *filename) -{ - filename = NULL; - return; -} - /* process a file */ static void @@ -3935,7 +3927,7 @@ char *line; char *tmpline; char *token[MAXTOKEN+1]; - uint32_t testno = 0; + uint32_t testno; mpd_ssize_t l; @@ -3959,8 +3951,6 @@ mpd_err_fatal("out of memory"); } - add_clarification(filename); - while (fgets(line, MAXLINE+1, file) != NULL) { @@ -4095,6 +4085,7 @@ * - testno can be used for setting a watchpoint in the debugger */ testno = get_testno(token[0]); + (void)testno; /* The id is in the skip list */ if (check_skip(token[0])) { From python-checkins at python.org Tue Jan 11 16:23:23 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Tue, 11 Jan 2011 16:23:23 +0100 (CET) Subject: [Python-checkins] r87934 - in python/branches/release31-maint: Lib/pydoc.py Message-ID: <20110111152323.0DB53EE98A@mail.python.org> Author: alexander.belopolsky Date: Tue Jan 11 16:23:22 2011 New Revision: 87934 Log: Merged revisions 82547 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r82547 | alexander.belopolsky | 2010-07-04 13:00:20 -0400 (Sun, 04 Jul 2010) | 3 lines Issue #9118: help(None) will now return NoneType doc instead of starting interactive help. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/pydoc.py Modified: python/branches/release31-maint/Lib/pydoc.py ============================================================================== --- python/branches/release31-maint/Lib/pydoc.py (original) +++ python/branches/release31-maint/Lib/pydoc.py Tue Jan 11 16:23:22 2011 @@ -1706,8 +1706,9 @@ return '' return '' - def __call__(self, request=None): - if request is not None: + _GoInteractive = object() + def __call__(self, request=_GoInteractive): + if request is not self._GoInteractive: self.help(request) else: self.intro() From python-checkins at python.org Tue Jan 11 16:35:24 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Tue, 11 Jan 2011 16:35:24 +0100 (CET) Subject: [Python-checkins] r87935 - in python/branches/release27-maint: Lib/pydoc.py Message-ID: <20110111153524.2D299EE98A@mail.python.org> Author: alexander.belopolsky Date: Tue Jan 11 16:35:23 2011 New Revision: 87935 Log: Merged revisions 82547 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r82547 | alexander.belopolsky | 2010-07-04 13:00:20 -0400 (Sun, 04 Jul 2010) | 3 lines Issue #9118: help(None) will now return NoneType doc instead of starting interactive help. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/pydoc.py Modified: python/branches/release27-maint/Lib/pydoc.py ============================================================================== --- python/branches/release27-maint/Lib/pydoc.py (original) +++ python/branches/release27-maint/Lib/pydoc.py Tue Jan 11 16:35:23 2011 @@ -1718,8 +1718,9 @@ return '' return '' - def __call__(self, request=None): - if request is not None: + _GoInteractive = object() + def __call__(self, request=_GoInteractive): + if request is not self._GoInteractive: self.help(request) else: self.intro() From python-checkins at python.org Tue Jan 11 17:56:28 2011 From: python-checkins at python.org (stefan.krah) Date: Tue, 11 Jan 2011 17:56:28 +0100 (CET) Subject: [Python-checkins] r87936 - python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.in Message-ID: <20110111165628.EC402EE996@mail.python.org> Author: stefan.krah Date: Tue Jan 11 17:56:28 2011 New Revision: 87936 Log: Copy with permissions of the install user. Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.in Modified: python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.in ============================================================================== --- python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.in (original) +++ python/branches/py3k-cdecimal/Lib/test/mpdecimal/Makefile.in Tue Jan 11 17:56:28 2011 @@ -201,7 +201,7 @@ check: $(LIBSTATIC) FORCE cd tests && $(MAKE) "CFLAGS=$(CFLAGS)" "LDFLAGS=$(LDFLAGS)" && ./runshort.sh - + extended:\ Makefile $(LIBSTATIC) cd tests && $(MAKE) extended @@ -243,7 +243,7 @@ install: FORCE mkdir -p $(DESTDIR)$(includedir) && cp mpdecimal.h $(DESTDIR)$(includedir) mkdir -p $(DESTDIR)$(libdir) && cp $(LIBSTATIC) $(LIBSHARED) $(DESTDIR)$(libdir) - mkdir -p $(DESTDIR)$(docdir) && cp -Rp doc/* $(DESTDIR)$(docdir) + mkdir -p $(DESTDIR)$(docdir) && cp -R doc/* $(DESTDIR)$(docdir) clean: FORCE rm -f *.o *.so *.gch *.gcda *.gcno *.gcov *.dyn *.dpi *.lock \ From python-checkins at python.org Tue Jan 11 18:07:57 2011 From: python-checkins at python.org (stefan.krah) Date: Tue, 11 Jan 2011 18:07:57 +0100 (CET) Subject: [Python-checkins] r87937 - in python/branches/py3k-cdecimal: Doc/ACKS.txt Doc/Makefile Doc/README.txt Doc/c-api/arg.rst Doc/glossary.rst Doc/howto/logging.rst Doc/howto/regex.rst Doc/library/argparse.rst Doc/library/ast.rst Doc/library/atexit.rst Doc/library/bisect.rst Doc/library/calendar.rst Doc/library/cmd.rst Doc/library/collections.rst Doc/library/contextlib.rst Doc/library/csv.rst Doc/library/datetime.rst Doc/library/decimal.rst Doc/library/dis.rst Doc/library/email.charset.rst Doc/library/email.generator.rst Doc/library/email.header.rst Doc/library/email.message.rst Doc/library/exceptions.rst Doc/library/filecmp.rst Doc/library/fileinput.rst Doc/library/fnmatch.rst Doc/library/functional.rst Doc/library/functools.rst Doc/library/glob.rst Doc/library/heapq.rst Doc/library/index.rst Doc/library/inspect.rst Doc/library/keyword.rst Doc/library/linecache.rst Doc/library/numeric.rst Doc/library/operator.rst Doc/library/optparse.rst Doc/library/pprint.rst Doc/library/pyexpat.rst Doc/library/queue.rst Doc/library/quopri.rst Doc/library/random.rst Doc/library/sched.rst Doc/library/shelve.rst Doc/library/shutil.rst Doc/library/socket.rst Doc/library/ssl.rst Doc/library/stdtypes.rst Doc/library/string.rst Doc/library/textwrap.rst Doc/library/threading.rst Doc/library/time.rst Doc/library/tokenize.rst Doc/library/trace.rst Doc/library/unittest.rst Doc/library/uu.rst Doc/library/wave.rst Doc/library/zlib.rst Doc/reference/compound_stmts.rst Doc/reference/executionmodel.rst Doc/tools/sphinxext/download.html Doc/tools/sphinxext/indexcontent.html Doc/whatsnew/3.2.rst Include/abstract.h Include/memoryobject.h Include/object.h Include/objimpl.h Include/typeslots.h Lib/_pyio.py Lib/ast.py Lib/bdb.py Lib/collections.py Lib/concurrent/futures/process.py Lib/contextlib.py Lib/datetime.py Lib/email/charset.py Lib/email/header.py Lib/email/message.py Lib/email/test/test_email.py Lib/encodings/aliases.py Lib/functools.py Lib/imaplib.py Lib/multiprocessing/connection.py Lib/pydoc.py Lib/socket.py Lib/subprocess.py Lib/test/datetimetester.py Lib/test/regrtest.py Lib/test/sha256.pem Lib/test/support.py Lib/test/test_array.py Lib/test/test_ast.py Lib/test/test_atexit.py Lib/test/test_bytes.py Lib/test/test_collections.py Lib/test/test_concurrent_futures.py Lib/test/test_functools.py Lib/test/test_httplib.py Lib/test/test_imaplib.py Lib/test/test_io.py Lib/test/test_os.py Lib/test/test_pyexpat.py Lib/test/test_site.py Lib/test/test_socket.py Lib/test/test_socketserver.py Lib/test/test_ssl.py Lib/test/test_subprocess.py Lib/test/test_sys.py Lib/test/test_threading.py Lib/test/test_threadsignals.py Lib/test/test_time.py Lib/test/test_timeout.py Lib/test/test_ttk_guionly.py Lib/test/test_unicode.py Lib/test/test_urllib2.py Lib/test/test_winreg.py Lib/test/test_with.py Lib/test/test_wsgiref.py Lib/test/test_xml_etree_c.py Lib/test/test_xmlrpc.py Lib/test/test_zipimport_support.py Lib/test/test_zlib.py Lib/threading.py Lib/tkinter/test/test_tkinter/test_loadtk.py Lib/unittest/case.py Lib/unittest/test/test_assertions.py Lib/unittest/test/test_case.py Lib/wsgiref/handlers.py Mac/IDLE/IDLE.app/Contents/Info.plist Mac/Makefile.in Mac/PythonLauncher/Info.plist.in Mac/Resources/app/Info.plist.in Mac/Resources/framework/Info.plist.in Misc/ACKS Misc/NEWS Misc/developers.txt Modules/_collectionsmodule.c Modules/_ctypes/_ctypes.c Modules/_datetimemodule.c Modules/_io/fileio.c Modules/_io/textio.c Modules/_posixsubprocess.c Modules/_testcapimodule.c Modules/atexitmodule.c Modules/audioop.c Modules/gcmodule.c Modules/main.c Modules/md5module.c Modules/posixmodule.c Modules/pyexpat.c Modules/selectmodule.c Modules/sha1module.c Modules/sha256module.c Modules/sha512module.c Modules/timemodule.c Modules/unicodedata.c Modules/zlibmodule.c Objects/codeobject.c Objects/fileobject.c Objects/listobject.c Objects/obmalloc.c Objects/typeobject.c Objects/typeslots.inc Objects/typeslots.py PC/python3.def Parser/tokenizer.c Python/ceval.c Python/getargs.c Python/pythonrun.c Python/sysmodule.c Tools/README Tools/unittestgui configure configure.in Message-ID: <20110111170757.82B26EE9B7@mail.python.org> Author: stefan.krah Date: Tue Jan 11 18:07:55 2011 New Revision: 87937 Log: Merged revisions 87627-87628,87638-87639,87642,87646,87648,87651,87653-87657,87665-87667,87671-87673,87677-87689,87691,87695,87698,87703-87705,87710-87714,87716-87722,87728-87740,87744,87746-87750,87753-87762,87765-87769,87771-87784,87786-87792,87795-87797,87802,87805-87808,87810-87813,87820-87835,87838-87840,87843-87850,87853,87856,87858-87863,87865,87867-87871,87873,87876-87877,87890-87891,87895-87904,87906-87908,87910-87912,87914-87917,87919-87922,87924-87926 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r87627 | georg.brandl | 2011-01-02 15:23:43 +0100 (Sun, 02 Jan 2011) | 1 line #1665333: add more docs for optparse.OptionGroup. ........ r87628 | antoine.pitrou | 2011-01-02 17:16:09 +0100 (Sun, 02 Jan 2011) | 3 lines Relax test condition a lot ........ r87638 | georg.brandl | 2011-01-02 20:07:51 +0100 (Sun, 02 Jan 2011) | 1 line Fix code indentation. ........ r87639 | antoine.pitrou | 2011-01-02 20:34:03 +0100 (Sun, 02 Jan 2011) | 4 lines Issue #10475: Don't hardcode compilers for LDSHARED/LDCXXSHARED on NetBSD and DragonFly BSD. Patch by Nicolas Joly. ........ r87642 | victor.stinner | 2011-01-02 20:50:36 +0100 (Sun, 02 Jan 2011) | 3 lines Issue #10807: Remove base64, bz2, hex, quopri, rot13, uu and zlib codecs from the codec aliases. They are still accessible via codecs.lookup(). ........ r87646 | antoine.pitrou | 2011-01-02 21:45:21 +0100 (Sun, 02 Jan 2011) | 3 lines Fix bad quoting in r87639. Caught by Arfrever. ........ r87648 | alexander.belopolsky | 2011-01-02 21:48:22 +0100 (Sun, 02 Jan 2011) | 1 line Issue #8013: Fixed time.asctime segfault when OS's asctime fails ........ r87651 | gregory.p.smith | 2011-01-02 21:52:48 +0100 (Sun, 02 Jan 2011) | 3 lines issue10802: fallback to pipe+fcntl when the pipe2 syscall fails with errno ENOSYS. ........ r87653 | antoine.pitrou | 2011-01-02 23:06:53 +0100 (Sun, 02 Jan 2011) | 3 lines Clarify behaviour of close() and shutdown() on sockets. ........ r87654 | antoine.pitrou | 2011-01-02 23:09:27 +0100 (Sun, 02 Jan 2011) | 3 lines Add a shutdown() call in the server example. ........ r87655 | antoine.pitrou | 2011-01-02 23:12:22 +0100 (Sun, 02 Jan 2011) | 3 lines Some nits. ........ r87656 | alexander.belopolsky | 2011-01-02 23:16:10 +0100 (Sun, 02 Jan 2011) | 1 line Issue #8013: Fixed test ........ r87657 | georg.brandl | 2011-01-02 23:33:43 +0100 (Sun, 02 Jan 2011) | 5 lines #8013 follow-up: * In asctime and ctime, properly remove the newline if the year has more than four digits * Consistent error message for both functions * Fix the test comments and add a check for the removed newline ........ r87665 | martin.v.loewis | 2011-01-03 01:07:01 +0100 (Mon, 03 Jan 2011) | 3 lines Issue #10798: Reject supporting concurrent.futures if the system has too few POSIX semaphores. ........ r87666 | amaury.forgeotdarc | 2011-01-03 01:19:11 +0100 (Mon, 03 Jan 2011) | 4 lines #8278: In the Windows implementation of stat() and utime(), use time_t instead of int. This gives support for dates after 2038, at least when compiled with VS2003 or later, where time_t is 64bit. ........ r87667 | martin.v.loewis | 2011-01-03 01:19:59 +0100 (Mon, 03 Jan 2011) | 2 lines Skip hanging test. ........ r87671 | raymond.hettinger | 2011-01-03 03:12:02 +0100 (Mon, 03 Jan 2011) | 1 line Make C helper function more closely match the pure python version, and add tests. ........ r87672 | raymond.hettinger | 2011-01-03 03:44:14 +0100 (Mon, 03 Jan 2011) | 1 line Supply a reduce method for pickling. ........ r87673 | brian.quinlan | 2011-01-03 03:56:39 +0100 (Mon, 03 Jan 2011) | 1 line Removes the 'Call' class which is used to control execution order and is unreliable on Windows ........ r87677 | senthil.kumaran | 2011-01-03 10:47:09 +0100 (Mon, 03 Jan 2011) | 3 lines py3k implmentation of RSA algorithm, ........ r87678 | senthil.kumaran | 2011-01-03 11:11:07 +0100 (Mon, 03 Jan 2011) | 3 lines Reverting the mistaken commit r87677. Checked in py3rsa.py by mistake. ........ r87679 | michael.foord | 2011-01-03 13:55:11 +0100 (Mon, 03 Jan 2011) | 1 line Issue 10786: unittest documentation update. ........ r87680 | victor.stinner | 2011-01-03 15:30:39 +0100 (Mon, 03 Jan 2011) | 1 line test_sockserver: close servers when done ........ r87681 | victor.stinner | 2011-01-03 15:30:41 +0100 (Mon, 03 Jan 2011) | 3 lines test_timeout: move testRecvfromTimeout() to a UDP-specific test case Fix a ResourceWarning(unclosed socket). ........ r87682 | victor.stinner | 2011-01-03 15:30:43 +0100 (Mon, 03 Jan 2011) | 3 lines test_tkinter: use a context manager to close directly the pipe Patch written by Nadeem Vawda ........ r87683 | victor.stinner | 2011-01-03 15:30:44 +0100 (Mon, 03 Jan 2011) | 3 lines test_xmlrpc: close the transport when done Fix a ResourceWarning(unclosed socket). Patch written by Nadeem Vawda. ........ r87684 | victor.stinner | 2011-01-03 15:30:46 +0100 (Mon, 03 Jan 2011) | 3 lines test_socket: use context managers to close directly the socket Fix ResourceWarning(unclosed socket) warnings. Patch written by Nadeem Vawda. ........ r87685 | michael.foord | 2011-01-03 16:39:49 +0100 (Mon, 03 Jan 2011) | 1 line Issue 10502: addition of unittestgui to Tools/ ........ r87686 | victor.stinner | 2011-01-03 16:47:59 +0100 (Mon, 03 Jan 2011) | 3 lines Issue #10816: multiprocessing.SocketClient() closes the socket on error Use a context manager to close immediatly the socket on error. ........ r87687 | victor.stinner | 2011-01-03 17:12:39 +0100 (Mon, 03 Jan 2011) | 1 line pydoc: close the DocServer when done ........ r87688 | victor.stinner | 2011-01-03 17:36:00 +0100 (Mon, 03 Jan 2011) | 1 line test_subprocess: close pipes at the end of test_pipe_cloexec_real_tools() ........ r87689 | michael.foord | 2011-01-03 18:00:11 +0100 (Mon, 03 Jan 2011) | 2 lines Enable unittest.TestCase to be instantiated without providing a method name. Changed unittestgui to show number of discovered tests in the status bar. ........ r87691 | eric.araujo | 2011-01-03 18:51:11 +0100 (Mon, 03 Jan 2011) | 2 lines Fix test_site for systems without unsetenv. Reported by Zsolt Cserna. ........ r87695 | antoine.pitrou | 2011-01-03 19:23:55 +0100 (Mon, 03 Jan 2011) | 5 lines Issue #10806, issue #9905: Fix subprocess pipes when some of the standard file descriptors (0, 1, 2) are closed in the parent process. Initial patch by Ross Lagerwall. ........ r87698 | antoine.pitrou | 2011-01-03 19:53:50 +0100 (Mon, 03 Jan 2011) | 4 lines Issue #7716: Under Solaris, don't assume existence of /usr/xpg4/bin/grep in the configure script but use $GREP instead. Patch by Fabian Groffen. ........ r87703 | michael.foord | 2011-01-03 20:13:02 +0100 (Mon, 03 Jan 2011) | 1 line Update description of Tools/unicode ........ r87704 | antoine.pitrou | 2011-01-03 21:38:52 +0100 (Mon, 03 Jan 2011) | 5 lines Issue #6293: Have regrtest.py echo back sys.flags. This is done by default in whole runs and enabled selectively using `--header` when running an explicit list of tests. Original patch by Collin Winter. ........ r87705 | antoine.pitrou | 2011-01-03 21:40:07 +0100 (Mon, 03 Jan 2011) | 3 lines Mention --randseed in option list ........ r87710 | gregory.p.smith | 2011-01-03 22:06:12 +0100 (Mon, 03 Jan 2011) | 4 lines issue6643 - Two locks held within the threading module on each thread instance needed to be reinitialized after fork(). Adds tests to confirm that they are and that a potential deadlock and crasher bug are fixed (platform dependant). ........ r87711 | gregory.p.smith | 2011-01-03 22:09:23 +0100 (Mon, 03 Jan 2011) | 2 lines news for 6643 ........ r87712 | antoine.pitrou | 2011-01-03 22:15:48 +0100 (Mon, 03 Jan 2011) | 3 lines Add a subprocess test of remapping standard file descriptors (issue #1187). ........ r87713 | antoine.pitrou | 2011-01-03 23:12:43 +0100 (Mon, 03 Jan 2011) | 3 lines Temporary debug output for intermittent failures in test_subprocess ........ r87714 | antoine.pitrou | 2011-01-03 23:24:52 +0100 (Mon, 03 Jan 2011) | 3 lines Add some more output ........ r87716 | antoine.pitrou | 2011-01-04 00:42:01 +0100 (Tue, 04 Jan 2011) | 3 lines Un-complicate some code ........ r87717 | victor.stinner | 2011-01-04 00:56:12 +0100 (Tue, 04 Jan 2011) | 1 line fix test_unittest: ignore DeprecationWarning on assertDictContainsSubset() ........ r87718 | antoine.pitrou | 2011-01-04 01:00:31 +0100 (Tue, 04 Jan 2011) | 4 lines Issue #10333: Remove ancient GC API, which has been deprecated since Python 2.2. ........ r87719 | victor.stinner | 2011-01-04 01:04:44 +0100 (Tue, 04 Jan 2011) | 1 line test_array: fix the DeprecationWarning('object.__init__() takes no parameters') ........ r87720 | victor.stinner | 2011-01-04 01:04:46 +0100 (Tue, 04 Jan 2011) | 1 line test_httplib: fix a DeprecationWarning, assertEquals=>assertEqual ........ r87721 | antoine.pitrou | 2011-01-04 01:24:03 +0100 (Tue, 04 Jan 2011) | 3 lines Issue #10267: Fix refleak in test_ttk_guionly. Patch by Hirokazu Yamamoto. ........ r87722 | victor.stinner | 2011-01-04 01:29:35 +0100 (Tue, 04 Jan 2011) | 2 lines Issue #9015, #9611: FileIO.readinto(), FileIO.write() and os.write() clamp the length to 2^31-1 on Windows. ........ r87728 | victor.stinner | 2011-01-04 03:07:34 +0100 (Tue, 04 Jan 2011) | 3 lines Issue #8651: PyArg_Parse*() functions raise an OverflowError if the file doesn't have PY_SSIZE_T_CLEAN define and the size doesn't fit in an int (length bigger than 2^31-1). ........ r87729 | victor.stinner | 2011-01-04 03:07:36 +0100 (Tue, 04 Jan 2011) | 3 lines Issue #8650: zlib.compress() and zlib.decompress() raise an OverflowError if the input buffer length doesn't fit into an unsigned int (length bigger than 2^32-1 bytes). ........ r87730 | victor.stinner | 2011-01-04 12:00:45 +0100 (Tue, 04 Jan 2011) | 2 lines Issue #10819: SocketIO.name property returns -1 when its closed, instead of raising a ValueError, to fix repr(). ........ r87731 | victor.stinner | 2011-01-04 12:16:48 +0100 (Tue, 04 Jan 2011) | 3 lines Issue #8992: Simplify addcleanup() API Don't need to handle unknown destructor anymore. ........ r87732 | victor.stinner | 2011-01-04 12:16:49 +0100 (Tue, 04 Jan 2011) | 3 lines Issue #8992: convertsimple() doesn't need to fill msgbuf if an error occurred Return msgbug on error is enough. ........ r87733 | victor.stinner | 2011-01-04 13:59:15 +0100 (Tue, 04 Jan 2011) | 1 line Issue #9566: use Py_ssize_t instead of int ........ r87734 | victor.stinner | 2011-01-04 14:15:39 +0100 (Tue, 04 Jan 2011) | 1 line Issue #9015, #9611: stdprinter.write() clamps the length to 2^31-1 on Windows ........ r87735 | vinay.sajip | 2011-01-04 14:58:49 +0100 (Tue, 04 Jan 2011) | 1 line logging HOWTO: fixed markup for numbered handler list. ........ r87736 | alexander.belopolsky | 2011-01-04 17:34:30 +0100 (Tue, 04 Jan 2011) | 6 lines Issue #8013: time.asctime and time.ctime no longer call system asctime and ctime functions. The year range for time.asctime is now 1900 through maxint. The range for time.ctime is the same as for time.localtime. The string produced by these functions is longer than 24 characters when year is greater than 9999. ........ r87737 | alexander.belopolsky | 2011-01-04 18:08:04 +0100 (Tue, 04 Jan 2011) | 1 line Issue #8013: Fix time.ctime test failure on 32-bit platforms. ........ r87738 | alexander.belopolsky | 2011-01-04 18:15:52 +0100 (Tue, 04 Jan 2011) | 1 line Whitespace cleanup ........ r87739 | georg.brandl | 2011-01-04 18:27:13 +0100 (Tue, 04 Jan 2011) | 1 line Fix exception catching. ........ r87740 | gregory.p.smith | 2011-01-04 19:33:38 +0100 (Tue, 04 Jan 2011) | 6 lines Fix the new bug introduced in the r87710 fix for issue 6643. DummyThread deletes its _block attribute, deal with that. This prevents an uncaught exception in a thread during test_thread. This refactors a bit to better match what I did in the r87727 backport to 2.7. ........ r87744 | antoine.pitrou | 2011-01-04 20:07:07 +0100 (Tue, 04 Jan 2011) | 4 lines In subprocess, wrap pipe fds before launching the child. Hopefully this will fix intermittent failures on some buildbots (issue #8458). ........ r87746 | victor.stinner | 2011-01-04 22:58:10 +0100 (Tue, 04 Jan 2011) | 1 line Issue #9566: explain why (int)len cannot underflow ........ r87747 | victor.stinner | 2011-01-04 23:00:04 +0100 (Tue, 04 Jan 2011) | 1 line Issue #9566: PyUnicode_FromFormatV() doesn't support %zi, use %zd instead ........ r87748 | antoine.pitrou | 2011-01-04 23:54:30 +0100 (Tue, 04 Jan 2011) | 3 lines Fix test_time under Windows ........ r87749 | victor.stinner | 2011-01-05 01:19:28 +0100 (Wed, 05 Jan 2011) | 4 lines test_unicode: use ctypes to test PyUnicode_FromFormat() Instead of _testcapi.format_unicode() because it has a limited API: it requires exactly one argument of type unicode. ........ r87750 | r.david.murray | 2011-01-05 02:39:32 +0100 (Wed, 05 Jan 2011) | 5 lines #10790: make append work when output codec is different from input codec There's still a bug here (the encode call shouldn't use the 'errors' paramter), but I'll fix that later. ........ r87753 | victor.stinner | 2011-01-05 04:33:26 +0100 (Wed, 05 Jan 2011) | 4 lines Remove arbitrary string length limits PyUnicode_FromFormat() and PyErr_Format() allocates a buffer of the needed size, it is no more a fixed-buffer of 500 bytes. ........ r87754 | victor.stinner | 2011-01-05 04:33:28 +0100 (Wed, 05 Jan 2011) | 1 line test_bytes: test PyBytes_FromFormat() using ctypes ........ r87755 | victor.stinner | 2011-01-05 04:54:25 +0100 (Wed, 05 Jan 2011) | 1 line Issue #10756: atexit normalizes the exception before displaying it. ........ r87756 | victor.stinner | 2011-01-05 04:54:26 +0100 (Wed, 05 Jan 2011) | 3 lines regrtest: close the new stdout and restore the original stdout at exit Fix a ResourceWarning(unclosed file). ........ r87757 | victor.stinner | 2011-01-05 04:54:28 +0100 (Wed, 05 Jan 2011) | 4 lines test_threading: use Popen.communicate() instead of .wait() Popen.communicate() avoids deadlocks and close the pipes when done. This commit fixes a ResourceWarning(unclosed pipe). ........ r87758 | victor.stinner | 2011-01-05 04:56:22 +0100 (Wed, 05 Jan 2011) | 1 line Issue #10756: add the author, Andreas St?hrk ........ r87759 | victor.stinner | 2011-01-05 04:58:54 +0100 (Wed, 05 Jan 2011) | 1 line test_time: assertEquals => assertEqual ........ r87760 | georg.brandl | 2011-01-05 11:59:48 +0100 (Wed, 05 Jan 2011) | 1 line Fix duplicate end tag. ........ r87761 | georg.brandl | 2011-01-05 12:00:25 +0100 (Wed, 05 Jan 2011) | 1 line #10130: Prepare for building epub-format docs. ........ r87762 | antoine.pitrou | 2011-01-05 19:37:22 +0100 (Wed, 05 Jan 2011) | 3 lines Issue #5485: Add doc for expat.xmlparser.SetParamEntityParsing. ........ r87765 | antoine.pitrou | 2011-01-05 19:44:14 +0100 (Wed, 05 Jan 2011) | 4 lines Issue #5485: Add tests for the UseForeignDTD method of expat parser objects. Patch by Jean-Paul Calderone and Sandro Tosi. ........ r87766 | raymond.hettinger | 2011-01-05 21:08:25 +0100 (Wed, 05 Jan 2011) | 1 line Fix count of flag fields. Being one short caused the 'quiet' option not to print. ........ r87767 | raymond.hettinger | 2011-01-05 21:24:08 +0100 (Wed, 05 Jan 2011) | 1 line Update tests and whatsnew for the 'quiet' flag ........ r87768 | antoine.pitrou | 2011-01-05 22:03:42 +0100 (Wed, 05 Jan 2011) | 4 lines Issue #7995: When calling accept() on a socket with a timeout, the returned socket is now always non-blocking, regardless of the operating system. ........ r87769 | antoine.pitrou | 2011-01-05 22:17:36 +0100 (Wed, 05 Jan 2011) | 3 lines Overhaul the documentation about socket timeouts. ........ r87771 | georg.brandl | 2011-01-05 22:47:47 +0100 (Wed, 05 Jan 2011) | 1 line On Py3k, -tt and -3 are no-op and unsupported respectively. ........ r87772 | raymond.hettinger | 2011-01-05 23:27:49 +0100 (Wed, 05 Jan 2011) | 1 line RC1 updates to whatsnew ........ r87773 | raymond.hettinger | 2011-01-05 23:41:23 +0100 (Wed, 05 Jan 2011) | 2 lines Remove mention of codes pending further discussion on transform()/untransform(). ........ r87774 | antoine.pitrou | 2011-01-05 23:43:26 +0100 (Wed, 05 Jan 2011) | 3 lines Fix mistake in NEWS ........ r87775 | raymond.hettinger | 2011-01-06 00:00:00 +0100 (Thu, 06 Jan 2011) | 2 lines Add more porting notes. ........ r87776 | alexander.belopolsky | 2011-01-06 00:00:47 +0100 (Thu, 06 Jan 2011) | 5 lines - time.accept2dyear = True is now equivalent to time.accept2dyear = 1 - removed unnecessary struct_time to tuple conversion - added more unit tests (See issue #10827 for discussion.) ........ r87777 | victor.stinner | 2011-01-06 00:01:37 +0100 (Thu, 06 Jan 2011) | 4 lines imaplib: IMAP4 constructor closes the socket on error Fix a ResourceWarning(unclosed socket) if an exception is raised in the constructor after the creation of the socket. Patch written by Nadeem Vawda. ........ r87778 | victor.stinner | 2011-01-06 00:01:38 +0100 (Thu, 06 Jan 2011) | 3 lines test_imaplib: reap_server() closes the server when done Fix a ResourceWarning(unclosed socket). Patch written by Nadeem Vawda. ........ r87779 | victor.stinner | 2011-01-06 00:47:00 +0100 (Thu, 06 Jan 2011) | 3 lines test_atexit: fix code saving/restoring stdout and stderr That's why I prefer a single instruction per line :-) ........ r87780 | victor.stinner | 2011-01-06 01:49:38 +0100 (Thu, 06 Jan 2011) | 3 lines Issue #10492: bdb.Bdb.run() only traces the execution of the code And not the compilation (if the input is a string). ........ r87781 | raymond.hettinger | 2011-01-06 03:01:26 +0100 (Thu, 06 Jan 2011) | 2 lines Add PEP 3333 to whatsnew. ........ r87782 | raymond.hettinger | 2011-01-06 03:08:30 +0100 (Thu, 06 Jan 2011) | 1 line Nits ........ r87783 | raymond.hettinger | 2011-01-06 06:34:17 +0100 (Thu, 06 Jan 2011) | 1 line Issue 10825: Minor updates to the test suite. ........ r87784 | antoine.pitrou | 2011-01-06 08:16:31 +0100 (Thu, 06 Jan 2011) | 3 lines Issue #10840: make it explicit that "s*" and friends provide contiguous memory. ........ r87786 | antoine.pitrou | 2011-01-06 10:05:22 +0100 (Thu, 06 Jan 2011) | 4 lines Issue #1677694: Refactor and improve test_timeout. Original patch by Bj?rn Lindqvist. ........ r87787 | georg.brandl | 2011-01-06 10:15:45 +0100 (Thu, 06 Jan 2011) | 1 line Remove doc for nonexisting parameter. ........ r87788 | georg.brandl | 2011-01-06 10:23:19 +0100 (Thu, 06 Jan 2011) | 1 line itertools, operator and functools are not really "numeric" modules; move them into their own "functional" chapter. ........ r87789 | georg.brandl | 2011-01-06 10:23:56 +0100 (Thu, 06 Jan 2011) | 1 line Fix various issues (mostly Python 2 relics) found by Jacques Ducasse. ........ r87790 | georg.brandl | 2011-01-06 10:25:27 +0100 (Thu, 06 Jan 2011) | 1 line Add acks where acks are due. ........ r87791 | georg.brandl | 2011-01-06 11:05:26 +0100 (Thu, 06 Jan 2011) | 1 line #10844: update copyright years in Mac plists. ........ r87792 | antoine.pitrou | 2011-01-06 17:31:28 +0100 (Thu, 06 Jan 2011) | 3 lines Elaborate about the GIL. ........ r87795 | alexander.belopolsky | 2011-01-06 17:45:25 +0100 (Thu, 06 Jan 2011) | 1 line Use PyOS_snprintf for better portability. ........ r87796 | david.malcolm | 2011-01-06 18:01:36 +0100 (Thu, 06 Jan 2011) | 6 lines Issue #10655: Fix the build on PowerPC on Linux with GCC when building with timestamp profiling (--with-tsc): the preprocessor test for the PowerPC support now looks for "__powerpc__" as well as "__ppc__": the latter seems to only be present on OS X; the former is the correct one for Linux with GCC. ........ r87797 | antoine.pitrou | 2011-01-06 18:17:04 +0100 (Thu, 06 Jan 2011) | 4 lines Issue #3839: wsgiref should not override a Content-Length header set by the application. Initial patch by Clovis Fabricio. ........ r87802 | antoine.pitrou | 2011-01-06 19:25:55 +0100 (Thu, 06 Jan 2011) | 6 lines Issue #7858: Raise an error properly when os.utime() fails under Windows on an existing file. (this does not seem to be easily testable) ........ r87805 | martin.v.loewis | 2011-01-06 20:15:47 +0100 (Thu, 06 Jan 2011) | 2 lines Remove buffer API from stable ABI for now, see #10181. ........ r87806 | martin.v.loewis | 2011-01-06 20:26:21 +0100 (Thu, 06 Jan 2011) | 2 lines Support comment lines and missing indices in typeslots.h. ........ r87807 | georg.brandl | 2011-01-06 20:28:18 +0100 (Thu, 06 Jan 2011) | 1 line #10846: fix typo. ........ r87808 | martin.v.loewis | 2011-01-06 20:28:31 +0100 (Thu, 06 Jan 2011) | 3 lines Drop bf_getbuffer/bf_releasebuffer from stable ABI, see #10181. ........ r87810 | raymond.hettinger | 2011-01-06 21:55:29 +0100 (Thu, 06 Jan 2011) | 2 lines Typo. ........ r87811 | alexander.belopolsky | 2011-01-06 22:57:06 +0100 (Thu, 06 Jan 2011) | 1 line Further simplify gettmarg() ........ r87812 | brett.cannon | 2011-01-06 23:32:41 +0100 (Thu, 06 Jan 2011) | 2 lines Get --coverage to be an acceptable flag for test.regrtest again. ........ r87813 | brett.cannon | 2011-01-07 00:08:16 +0100 (Fri, 07 Jan 2011) | 1 line Undo an accidental commit in r87812. ........ r87820 | georg.brandl | 2011-01-07 19:28:45 +0100 (Fri, 07 Jan 2011) | 1 line #10856: document (Base)Exception.args better. ........ r87821 | antoine.pitrou | 2011-01-07 19:33:07 +0100 (Fri, 07 Jan 2011) | 3 lines Put link to source at the end. There's nothing edificating in threading.py. ........ r87822 | antoine.pitrou | 2011-01-07 19:42:21 +0100 (Fri, 07 Jan 2011) | 3 lines atexit.py doesn't exist ........ r87823 | antoine.pitrou | 2011-01-07 19:43:14 +0100 (Fri, 07 Jan 2011) | 3 lines Put those source links together ........ r87824 | victor.stinner | 2011-01-07 19:47:22 +0100 (Fri, 07 Jan 2011) | 5 lines Issue #10841: set binary mode on files; the parser translates newlines On Windows, set the binary mode on stdin, stdout, stderr and all io.FileIO objects (to not translate newlines, \r\n <=> \n). The Python parser translates newlines (\r\n => \n). ........ r87825 | victor.stinner | 2011-01-07 19:56:19 +0100 (Fri, 07 Jan 2011) | 1 line Issue #10841: don't translate newlines for pgen ........ r87826 | antoine.pitrou | 2011-01-07 19:58:21 +0100 (Fri, 07 Jan 2011) | 3 lines Put those "seealso"s together ........ r87827 | antoine.pitrou | 2011-01-07 20:01:48 +0100 (Fri, 07 Jan 2011) | 3 lines Group seealsos ........ r87828 | antoine.pitrou | 2011-01-07 20:16:12 +0100 (Fri, 07 Jan 2011) | 3 lines Mention multiprocessing.Queue in the queue docs ........ r87829 | alexander.belopolsky | 2011-01-07 20:59:19 +0100 (Fri, 07 Jan 2011) | 7 lines Issue #10827: Changed the rules for 2-digit years. The time.asctime function will now format any year when time.accept2dyear is false and will accept years >= 1000 otherwise. The year range accepted by time.mktime and time.strftime is still system dependent, but time.mktime will now accept full range supported by the OS. Conversion of 2-digit years to 4-digit is deprecated. ........ r87830 | raymond.hettinger | 2011-01-07 21:33:09 +0100 (Fri, 07 Jan 2011) | 2 lines Combine the two seealso sections. ........ r87831 | georg.brandl | 2011-01-07 21:58:25 +0100 (Fri, 07 Jan 2011) | 1 line Fix indent. ........ r87832 | raymond.hettinger | 2011-01-07 22:04:30 +0100 (Fri, 07 Jan 2011) | 2 lines Update the digest of PEP 3333 based on comments for Phillip Eby. ........ r87833 | raymond.hettinger | 2011-01-07 22:17:56 +0100 (Fri, 07 Jan 2011) | 1 line Revert r87823 which moved the source link to the wrong section. ........ r87834 | antoine.pitrou | 2011-01-07 22:43:59 +0100 (Fri, 07 Jan 2011) | 5 lines Issue #8020: Avoid a crash where the small objects allocator would read non-Python managed memory while it is being modified by another thread. Patch by Matt Bandy. ........ r87835 | antoine.pitrou | 2011-01-07 22:47:02 +0100 (Fri, 07 Jan 2011) | 3 lines Put NEWS entry in the right section. ........ r87838 | raymond.hettinger | 2011-01-07 22:54:18 +0100 (Fri, 07 Jan 2011) | 1 line Revert r87821 which moved the source link to the wrong section (from the module intro covering the module to a section on thread imports). ........ r87839 | r.david.murray | 2011-01-07 22:57:25 +0100 (Fri, 07 Jan 2011) | 9 lines Fix formatting of values with embedded newlines when rfc2047 encoding Before this patch if a value being encoded had an embedded newline, the line following the newline would have no leading whitespace, and the whitespace it did have was encoded into the word. Now the existing whitespace gets turned into a blank, the way it does in other header reformatting, and the _continuation_ws gets added at the beginning of the encoded line. ........ r87840 | r.david.murray | 2011-01-08 00:25:30 +0100 (Sat, 08 Jan 2011) | 6 lines #10686: recode non-ASCII headers to 'unknown-8bit' instead of ?s. This applies only when generating strings from non-RFC compliant binary input; it makes the existing recoding behavior more consistent (ie: now no data is lost when recoding). ........ r87843 | alexander.belopolsky | 2011-01-08 01:13:34 +0100 (Sat, 08 Jan 2011) | 1 line Issue #1777412: extended year range of strftime down to 1000. ........ r87844 | alexander.belopolsky | 2011-01-08 02:23:02 +0100 (Sat, 08 Jan 2011) | 3 lines Fixed error handling branches. Thanks Victor Stinner for pointing this out. ........ r87845 | victor.stinner | 2011-01-08 02:56:31 +0100 (Sat, 08 Jan 2011) | 4 lines Issue #1777412: strftime() accepts year >= 1 instead of year >= 1900 * With Visual Studio, year have to be in [1; 9999] * Add more tests on the year field ........ r87846 | victor.stinner | 2011-01-08 03:00:24 +0100 (Sat, 08 Jan 2011) | 1 line Issue #1777412: test large years value for strftime('%Y') ........ r87847 | victor.stinner | 2011-01-08 03:46:33 +0100 (Sat, 08 Jan 2011) | 1 line Issue #1777412: fix test_time for Mac OS X and OpenIndiana ........ r87848 | victor.stinner | 2011-01-08 04:06:52 +0100 (Sat, 08 Jan 2011) | 3 lines Issue #1777412: Remove all limits on tm_year from time.strftime() The buildbots will tell us which platform does support or not negative years. ........ r87849 | victor.stinner | 2011-01-08 04:16:05 +0100 (Sat, 08 Jan 2011) | 1 line test_ssl: test SHA256 using sha256.tbs-internet.com instead of sha2.hboeck.de ........ r87850 | victor.stinner | 2011-01-08 04:35:36 +0100 (Sat, 08 Jan 2011) | 1 line Issue #10864: limit year to [1; 9999] for strftime() on Solaris ........ r87853 | raymond.hettinger | 2011-01-08 08:01:56 +0100 (Sat, 08 Jan 2011) | 4 lines Issue #10042: Fixed the total_ordering decorator to handle cross-type comparisons that could lead to infinite recursion. ........ r87856 | raymond.hettinger | 2011-01-08 10:03:11 +0100 (Sat, 08 Jan 2011) | 2 lines Issue #10813: Small improvement to decimal money format recipe. ........ r87858 | raymond.hettinger | 2011-01-08 10:35:38 +0100 (Sat, 08 Jan 2011) | 2 lines Issue 10533: Need example of using __missing__. ........ r87859 | georg.brandl | 2011-01-08 10:45:43 +0100 (Sat, 08 Jan 2011) | 1 line #10855: document close() semantics of wave objects. ........ r87860 | antoine.pitrou | 2011-01-08 10:55:31 +0100 (Sat, 08 Jan 2011) | 4 lines Issue #10859: Make `contextlib.GeneratorContextManager` officially private by renaming it to `_GeneratorContextManager`. ........ r87861 | antoine.pitrou | 2011-01-08 11:23:29 +0100 (Sat, 08 Jan 2011) | 3 lines Fix test_ssl after r87849 ........ r87862 | raymond.hettinger | 2011-01-08 11:26:53 +0100 (Sat, 08 Jan 2011) | 3 lines Issue 9717: Segregate and improve the documentation of "in-place" operators in the operator module. ........ r87863 | antoine.pitrou | 2011-01-08 11:28:11 +0100 (Sat, 08 Jan 2011) | 3 lines Add EHOSTUNREACH ('No route to host') to the errnos trapped by transient_internet(). ........ r87865 | raymond.hettinger | 2011-01-08 11:32:31 +0100 (Sat, 08 Jan 2011) | 1 line Markup fix ........ r87867 | victor.stinner | 2011-01-08 17:31:24 +0100 (Sat, 08 Jan 2011) | 1 line Issue #1777412: document the change in the NEWS file ........ r87868 | victor.stinner | 2011-01-08 17:37:47 +0100 (Sat, 08 Jan 2011) | 1 line NEWS: merge #1777412 and #10827 entries ........ r87869 | alexander.belopolsky | 2011-01-08 21:47:21 +0100 (Sat, 08 Jan 2011) | 1 line Fixed documentation to reflect recent changes for years < 1900. ........ r87870 | georg.brandl | 2011-01-08 22:04:25 +0100 (Sat, 08 Jan 2011) | 1 line zlib only works with bytes objects. ........ r87871 | raymond.hettinger | 2011-01-09 00:44:37 +0100 (Sun, 09 Jan 2011) | 2 lines Issue #10357: Clarify what it means to be a mapping. ........ r87873 | r.david.murray | 2011-01-09 03:35:24 +0100 (Sun, 09 Jan 2011) | 12 lines #5871: protect against header injection attacks. This makes Header.encode throw a HeaderParseError if it winds up formatting a header such that a continuation line has no leading whitespace and looks like a header. Since Header accepts values containing newlines and preserves them (and this is by design), without this fix any program that took user input (say, a subject in a web form) and passed it to the email package as a header was vulnerable to header injection attacks. (As far as we know this has never been exploited.) Thanks to Jakub Wilk for reporting this vulnerability. ........ r87876 | georg.brandl | 2011-01-09 08:38:51 +0100 (Sun, 09 Jan 2011) | 1 line #10869: do not visit root node twice in ast.increment_lineno(). ........ r87877 | georg.brandl | 2011-01-09 08:50:48 +0100 (Sun, 09 Jan 2011) | 1 line Add missing line. ........ r87890 | georg.brandl | 2011-01-09 10:04:08 +0100 (Sun, 09 Jan 2011) | 1 line Wrap some long examples and signatures. ........ r87891 | georg.brandl | 2011-01-09 10:31:01 +0100 (Sun, 09 Jan 2011) | 1 line #10871: "file" does not exist anymore in Python 3. Also adapt the reprs of opened file objects. ........ r87895 | lukasz.langa | 2011-01-09 19:18:53 +0100 (Sun, 09 Jan 2011) | 5 lines #10874: test_urllib2 shouldn't use `is` operator for comparing strings Patch by Adreas St?hrk. ........ r87896 | martin.v.loewis | 2011-01-09 19:28:07 +0100 (Sun, 09 Jan 2011) | 2 lines Add Ned Deily. ........ r87897 | antoine.pitrou | 2011-01-09 21:38:15 +0100 (Sun, 09 Jan 2011) | 6 lines Issue #10872: The repr() of TextIOWrapper objects now includes the mode if available. (at Georg's request) ........ r87898 | raymond.hettinger | 2011-01-10 04:26:08 +0100 (Mon, 10 Jan 2011) | 1 line Move source links to consistent location and remove wordy, big yellow boxes. ........ r87899 | raymond.hettinger | 2011-01-10 06:40:57 +0100 (Mon, 10 Jan 2011) | 2 lines Fix typos. ........ r87900 | alexander.belopolsky | 2011-01-10 20:14:38 +0100 (Mon, 10 Jan 2011) | 1 line Fixed a footnote reference ........ r87901 | raymond.hettinger | 2011-01-10 20:54:11 +0100 (Mon, 10 Jan 2011) | 1 line Separate source link from main text. ........ r87902 | raymond.hettinger | 2011-01-10 22:16:07 +0100 (Mon, 10 Jan 2011) | 1 line Missed two source links ........ r87903 | raymond.hettinger | 2011-01-10 22:26:49 +0100 (Mon, 10 Jan 2011) | 2 lines Misspelling. ........ r87904 | terry.reedy | 2011-01-10 22:27:49 +0100 (Mon, 10 Jan 2011) | 2 lines Issue #10875: Update Regular Expression HOWTO; patch by 'SilentGhost'. ........ r87906 | alexander.belopolsky | 2011-01-10 22:55:34 +0100 (Mon, 10 Jan 2011) | 1 line Added entries about removal of year 1900 limit. ........ r87907 | alexander.belopolsky | 2011-01-10 22:58:52 +0100 (Mon, 10 Jan 2011) | 1 line Removed time.ctime from the list of functions that take a time tuple argument ........ r87908 | ned.deily | 2011-01-10 23:14:25 +0100 (Mon, 10 Jan 2011) | 4 lines #10820: Fix OS X framework installs to support version-specific scripts (implemented in #10679). ........ r87910 | alexander.belopolsky | 2011-01-10 23:56:14 +0100 (Mon, 10 Jan 2011) | 1 line Issue #2568: Removed bogus rationale for supporting tm_sec=61. ........ r87911 | victor.stinner | 2011-01-11 00:00:36 +0100 (Tue, 11 Jan 2011) | 5 lines Issue #9566: Fix pyparse.xmlparser.ParseFile() Fix readinst() if file.read(n) returns a bytes object longer than n: return -1 instead of the the buffer size to raise an exception. Simplify also the function code. ........ r87912 | terry.reedy | 2011-01-11 00:13:21 +0100 (Tue, 11 Jan 2011) | 2 lines Issue #10875: Update Regular Expression HOWTO; last bit. ........ r87914 | alexander.belopolsky | 2011-01-11 00:28:33 +0100 (Tue, 11 Jan 2011) | 1 line Improved description of %Y directive. ........ r87915 | alexander.belopolsky | 2011-01-11 00:31:51 +0100 (Tue, 11 Jan 2011) | 1 line Improved footnote for the %Y directive slightly. ........ r87916 | raymond.hettinger | 2011-01-11 00:38:15 +0100 (Tue, 11 Jan 2011) | 2 lines Fix typos and markup. ........ r87917 | victor.stinner | 2011-01-11 01:04:12 +0100 (Tue, 11 Jan 2011) | 1 line Issue #9611: remove useless and dangerous explicit conversion to size_t ........ r87919 | alexander.belopolsky | 2011-01-11 02:21:25 +0100 (Tue, 11 Jan 2011) | 4 lines Issue #1726687: time.mktime() will now correctly compute value one second before epoch. Original patch by Peter Wang, reported by Martin Blais. ........ r87920 | alexander.belopolsky | 2011-01-11 02:35:22 +0100 (Tue, 11 Jan 2011) | 1 line Make mktime test more robust. ........ r87921 | alexander.belopolsky | 2011-01-11 03:22:16 +0100 (Tue, 11 Jan 2011) | 1 line This should fix mktime test on Windows ........ r87922 | nick.coghlan | 2011-01-11 03:42:15 +0100 (Tue, 11 Jan 2011) | 1 line developers.txt entry for Eli (at Brett's request) ........ r87924 | raymond.hettinger | 2011-01-11 09:49:10 +0100 (Tue, 11 Jan 2011) | 2 lines Add a todo. ........ r87925 | nick.coghlan | 2011-01-11 11:05:20 +0100 (Tue, 11 Jan 2011) | 1 line Issue 10556: test_zipimport_support implicitly imports too many modules (including _ssl) to safely clobber sys.modules after each test ........ r87926 | eric.smith | 2011-01-11 11:24:34 +0100 (Tue, 11 Jan 2011) | 1 line Typo. ........ Added: python/branches/py3k-cdecimal/Doc/library/functional.rst - copied unchanged from r87926, /python/branches/py3k/Doc/library/functional.rst python/branches/py3k-cdecimal/Tools/unittestgui/ - copied from r87926, /python/branches/py3k/Tools/unittestgui/ Modified: python/branches/py3k-cdecimal/ (props changed) python/branches/py3k-cdecimal/Doc/ACKS.txt python/branches/py3k-cdecimal/Doc/Makefile python/branches/py3k-cdecimal/Doc/README.txt python/branches/py3k-cdecimal/Doc/c-api/arg.rst python/branches/py3k-cdecimal/Doc/glossary.rst python/branches/py3k-cdecimal/Doc/howto/logging.rst python/branches/py3k-cdecimal/Doc/howto/regex.rst python/branches/py3k-cdecimal/Doc/library/argparse.rst python/branches/py3k-cdecimal/Doc/library/ast.rst python/branches/py3k-cdecimal/Doc/library/atexit.rst python/branches/py3k-cdecimal/Doc/library/bisect.rst python/branches/py3k-cdecimal/Doc/library/calendar.rst python/branches/py3k-cdecimal/Doc/library/cmd.rst python/branches/py3k-cdecimal/Doc/library/collections.rst python/branches/py3k-cdecimal/Doc/library/contextlib.rst python/branches/py3k-cdecimal/Doc/library/csv.rst python/branches/py3k-cdecimal/Doc/library/datetime.rst python/branches/py3k-cdecimal/Doc/library/decimal.rst python/branches/py3k-cdecimal/Doc/library/dis.rst python/branches/py3k-cdecimal/Doc/library/email.charset.rst python/branches/py3k-cdecimal/Doc/library/email.generator.rst python/branches/py3k-cdecimal/Doc/library/email.header.rst python/branches/py3k-cdecimal/Doc/library/email.message.rst python/branches/py3k-cdecimal/Doc/library/exceptions.rst python/branches/py3k-cdecimal/Doc/library/filecmp.rst python/branches/py3k-cdecimal/Doc/library/fileinput.rst python/branches/py3k-cdecimal/Doc/library/fnmatch.rst python/branches/py3k-cdecimal/Doc/library/functools.rst python/branches/py3k-cdecimal/Doc/library/glob.rst python/branches/py3k-cdecimal/Doc/library/heapq.rst python/branches/py3k-cdecimal/Doc/library/index.rst python/branches/py3k-cdecimal/Doc/library/inspect.rst python/branches/py3k-cdecimal/Doc/library/keyword.rst python/branches/py3k-cdecimal/Doc/library/linecache.rst python/branches/py3k-cdecimal/Doc/library/numeric.rst python/branches/py3k-cdecimal/Doc/library/operator.rst python/branches/py3k-cdecimal/Doc/library/optparse.rst python/branches/py3k-cdecimal/Doc/library/pprint.rst python/branches/py3k-cdecimal/Doc/library/pyexpat.rst python/branches/py3k-cdecimal/Doc/library/queue.rst python/branches/py3k-cdecimal/Doc/library/quopri.rst python/branches/py3k-cdecimal/Doc/library/random.rst python/branches/py3k-cdecimal/Doc/library/sched.rst python/branches/py3k-cdecimal/Doc/library/shelve.rst python/branches/py3k-cdecimal/Doc/library/shutil.rst python/branches/py3k-cdecimal/Doc/library/socket.rst python/branches/py3k-cdecimal/Doc/library/ssl.rst python/branches/py3k-cdecimal/Doc/library/stdtypes.rst python/branches/py3k-cdecimal/Doc/library/string.rst python/branches/py3k-cdecimal/Doc/library/textwrap.rst python/branches/py3k-cdecimal/Doc/library/threading.rst python/branches/py3k-cdecimal/Doc/library/time.rst python/branches/py3k-cdecimal/Doc/library/tokenize.rst python/branches/py3k-cdecimal/Doc/library/trace.rst python/branches/py3k-cdecimal/Doc/library/unittest.rst python/branches/py3k-cdecimal/Doc/library/uu.rst python/branches/py3k-cdecimal/Doc/library/wave.rst python/branches/py3k-cdecimal/Doc/library/zlib.rst python/branches/py3k-cdecimal/Doc/reference/compound_stmts.rst python/branches/py3k-cdecimal/Doc/reference/executionmodel.rst python/branches/py3k-cdecimal/Doc/tools/sphinxext/download.html python/branches/py3k-cdecimal/Doc/tools/sphinxext/indexcontent.html python/branches/py3k-cdecimal/Doc/whatsnew/3.2.rst python/branches/py3k-cdecimal/Include/abstract.h python/branches/py3k-cdecimal/Include/memoryobject.h python/branches/py3k-cdecimal/Include/object.h python/branches/py3k-cdecimal/Include/objimpl.h python/branches/py3k-cdecimal/Include/typeslots.h python/branches/py3k-cdecimal/Lib/_pyio.py python/branches/py3k-cdecimal/Lib/ast.py python/branches/py3k-cdecimal/Lib/bdb.py python/branches/py3k-cdecimal/Lib/collections.py python/branches/py3k-cdecimal/Lib/concurrent/futures/process.py python/branches/py3k-cdecimal/Lib/contextlib.py python/branches/py3k-cdecimal/Lib/datetime.py python/branches/py3k-cdecimal/Lib/email/charset.py python/branches/py3k-cdecimal/Lib/email/header.py python/branches/py3k-cdecimal/Lib/email/message.py python/branches/py3k-cdecimal/Lib/email/test/test_email.py python/branches/py3k-cdecimal/Lib/encodings/aliases.py python/branches/py3k-cdecimal/Lib/functools.py python/branches/py3k-cdecimal/Lib/imaplib.py python/branches/py3k-cdecimal/Lib/multiprocessing/connection.py python/branches/py3k-cdecimal/Lib/pydoc.py python/branches/py3k-cdecimal/Lib/socket.py python/branches/py3k-cdecimal/Lib/subprocess.py python/branches/py3k-cdecimal/Lib/test/datetimetester.py python/branches/py3k-cdecimal/Lib/test/regrtest.py python/branches/py3k-cdecimal/Lib/test/sha256.pem python/branches/py3k-cdecimal/Lib/test/support.py python/branches/py3k-cdecimal/Lib/test/test_array.py python/branches/py3k-cdecimal/Lib/test/test_ast.py python/branches/py3k-cdecimal/Lib/test/test_atexit.py python/branches/py3k-cdecimal/Lib/test/test_bytes.py python/branches/py3k-cdecimal/Lib/test/test_collections.py python/branches/py3k-cdecimal/Lib/test/test_concurrent_futures.py python/branches/py3k-cdecimal/Lib/test/test_functools.py python/branches/py3k-cdecimal/Lib/test/test_httplib.py python/branches/py3k-cdecimal/Lib/test/test_imaplib.py python/branches/py3k-cdecimal/Lib/test/test_io.py python/branches/py3k-cdecimal/Lib/test/test_os.py python/branches/py3k-cdecimal/Lib/test/test_pyexpat.py python/branches/py3k-cdecimal/Lib/test/test_site.py python/branches/py3k-cdecimal/Lib/test/test_socket.py python/branches/py3k-cdecimal/Lib/test/test_socketserver.py python/branches/py3k-cdecimal/Lib/test/test_ssl.py python/branches/py3k-cdecimal/Lib/test/test_subprocess.py python/branches/py3k-cdecimal/Lib/test/test_sys.py python/branches/py3k-cdecimal/Lib/test/test_threading.py python/branches/py3k-cdecimal/Lib/test/test_threadsignals.py python/branches/py3k-cdecimal/Lib/test/test_time.py python/branches/py3k-cdecimal/Lib/test/test_timeout.py python/branches/py3k-cdecimal/Lib/test/test_ttk_guionly.py python/branches/py3k-cdecimal/Lib/test/test_unicode.py python/branches/py3k-cdecimal/Lib/test/test_urllib2.py python/branches/py3k-cdecimal/Lib/test/test_winreg.py python/branches/py3k-cdecimal/Lib/test/test_with.py python/branches/py3k-cdecimal/Lib/test/test_wsgiref.py python/branches/py3k-cdecimal/Lib/test/test_xml_etree_c.py python/branches/py3k-cdecimal/Lib/test/test_xmlrpc.py python/branches/py3k-cdecimal/Lib/test/test_zipimport_support.py python/branches/py3k-cdecimal/Lib/test/test_zlib.py python/branches/py3k-cdecimal/Lib/threading.py python/branches/py3k-cdecimal/Lib/tkinter/test/test_tkinter/test_loadtk.py python/branches/py3k-cdecimal/Lib/unittest/case.py python/branches/py3k-cdecimal/Lib/unittest/test/test_assertions.py python/branches/py3k-cdecimal/Lib/unittest/test/test_case.py python/branches/py3k-cdecimal/Lib/wsgiref/handlers.py python/branches/py3k-cdecimal/Mac/IDLE/IDLE.app/Contents/Info.plist python/branches/py3k-cdecimal/Mac/Makefile.in python/branches/py3k-cdecimal/Mac/PythonLauncher/Info.plist.in python/branches/py3k-cdecimal/Mac/Resources/app/Info.plist.in python/branches/py3k-cdecimal/Mac/Resources/framework/Info.plist.in python/branches/py3k-cdecimal/Misc/ACKS python/branches/py3k-cdecimal/Misc/NEWS python/branches/py3k-cdecimal/Misc/developers.txt python/branches/py3k-cdecimal/Modules/_collectionsmodule.c python/branches/py3k-cdecimal/Modules/_ctypes/_ctypes.c python/branches/py3k-cdecimal/Modules/_datetimemodule.c python/branches/py3k-cdecimal/Modules/_io/fileio.c python/branches/py3k-cdecimal/Modules/_io/textio.c python/branches/py3k-cdecimal/Modules/_posixsubprocess.c python/branches/py3k-cdecimal/Modules/_testcapimodule.c python/branches/py3k-cdecimal/Modules/atexitmodule.c python/branches/py3k-cdecimal/Modules/audioop.c python/branches/py3k-cdecimal/Modules/gcmodule.c python/branches/py3k-cdecimal/Modules/main.c python/branches/py3k-cdecimal/Modules/md5module.c python/branches/py3k-cdecimal/Modules/posixmodule.c python/branches/py3k-cdecimal/Modules/pyexpat.c python/branches/py3k-cdecimal/Modules/selectmodule.c python/branches/py3k-cdecimal/Modules/sha1module.c python/branches/py3k-cdecimal/Modules/sha256module.c python/branches/py3k-cdecimal/Modules/sha512module.c python/branches/py3k-cdecimal/Modules/timemodule.c python/branches/py3k-cdecimal/Modules/unicodedata.c python/branches/py3k-cdecimal/Modules/zlibmodule.c python/branches/py3k-cdecimal/Objects/codeobject.c python/branches/py3k-cdecimal/Objects/fileobject.c python/branches/py3k-cdecimal/Objects/listobject.c python/branches/py3k-cdecimal/Objects/obmalloc.c python/branches/py3k-cdecimal/Objects/typeobject.c python/branches/py3k-cdecimal/Objects/typeslots.inc python/branches/py3k-cdecimal/Objects/typeslots.py python/branches/py3k-cdecimal/PC/python3.def python/branches/py3k-cdecimal/Parser/tokenizer.c python/branches/py3k-cdecimal/Python/ceval.c python/branches/py3k-cdecimal/Python/getargs.c python/branches/py3k-cdecimal/Python/pythonrun.c python/branches/py3k-cdecimal/Python/sysmodule.c python/branches/py3k-cdecimal/Tools/README python/branches/py3k-cdecimal/configure python/branches/py3k-cdecimal/configure.in Modified: python/branches/py3k-cdecimal/Doc/ACKS.txt ============================================================================== --- python/branches/py3k-cdecimal/Doc/ACKS.txt (original) +++ python/branches/py3k-cdecimal/Doc/ACKS.txt Tue Jan 11 18:07:55 2011 @@ -47,6 +47,7 @@ * L. Peter Deutsch * Robert Donohue * Fred L. Drake, Jr. + * Jacques Ducasse * Josip Dzolonga * Jeff Epler * Michael Ernst Modified: python/branches/py3k-cdecimal/Doc/Makefile ============================================================================== --- python/branches/py3k-cdecimal/Doc/Makefile (original) +++ python/branches/py3k-cdecimal/Doc/Makefile Tue Jan 11 18:07:55 2011 @@ -26,6 +26,7 @@ @echo " htmlhelp to make HTML files and a HTML help project" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " text to make plain text files" + @echo " epub to make EPUB files" @echo " changes to make an overview over all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " coverage to check documentation coverage for library and C API" @@ -81,6 +82,10 @@ text: build @echo "Build finished; the text files are in build/text." +epub: BUILDER = epub +epub: build + @echo "Build finished; the epub files are in build/epub." + changes: BUILDER = changes changes: build @echo "The overview file is in build/changes." @@ -158,6 +163,17 @@ cp build/latex/docs-pdf.zip dist/python-$(DISTVERSION)-docs-pdf-letter.zip cp build/latex/docs-pdf.tar.bz2 dist/python-$(DISTVERSION)-docs-pdf-letter.tar.bz2 + # archive the epub build + rm -rf build/epub + make epub + mkdir -p dist/python-$(DISTVERSION)-docs-epub + cp -pPR build/epub/*.epub dist/python-$(DISTVERSION)-docs-epub/ + tar -C dist -cf dist/python-$(DISTVERSION)-docs-epub.tar python-$(DISTVERSION)-docs-epub + bzip2 -9 -k dist/python-$(DISTVERSION)-docs-epub.tar + (cd dist; zip -q -r -9 python-$(DISTVERSION)-docs-epub.zip python-$(DISTVERSION)-docs-epub) + rm -r dist/python-$(DISTVERSION)-docs-epub + rm dist/python-$(DISTVERSION)-docs-epub.tar + check: $(PYTHON) tools/rstlint.py -i tools Modified: python/branches/py3k-cdecimal/Doc/README.txt ============================================================================== --- python/branches/py3k-cdecimal/Doc/README.txt (original) +++ python/branches/py3k-cdecimal/Doc/README.txt Tue Jan 11 18:07:55 2011 @@ -54,6 +54,9 @@ * "text", which builds a plain text file for each source file. + * "epub", which builds an EPUB document, suitable to be viewed on e-book + readers. + * "linkcheck", which checks all external references to see whether they are broken, redirected or malformed, and outputs this information to stdout as well as a plain-text (.txt) file. Modified: python/branches/py3k-cdecimal/Doc/c-api/arg.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/c-api/arg.rst (original) +++ python/branches/py3k-cdecimal/Doc/c-api/arg.rst Tue Jan 11 18:07:55 2011 @@ -30,9 +30,10 @@ Strings and buffers ------------------- -These formats do not expect you to provide raw storage for the returned string -or bytes. Also, you won't have to release any memory yourself, except with -the ``es``, ``es#``, ``et`` and ``et#`` formats. +These formats allow to access an object as a contiguous chunk of memory. +You don't have to provide raw storage for the returned unicode or bytes +area. Also, you won't have to release any memory yourself, except with the +``es``, ``es#``, ``et`` and ``et#`` formats. However, when a :c:type:`Py_buffer` structure gets filled, the underlying buffer is locked so that the caller can subsequently use the buffer even Modified: python/branches/py3k-cdecimal/Doc/glossary.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/glossary.rst (original) +++ python/branches/py3k-cdecimal/Doc/glossary.rst Tue Jan 11 18:07:55 2011 @@ -102,9 +102,10 @@ See :pep:`343`. CPython - The canonical implementation of the Python programming language. The - term "CPython" is used in contexts when necessary to distinguish this - implementation from others such as Jython or IronPython. + The canonical implementation of the Python programming language, as + distributed on `python.org `_. The term "CPython" + is used when necessary to distinguish this implementation from others + such as Jython or IronPython. decorator A function returning another function, usually applied as a function @@ -263,16 +264,25 @@ See :term:`global interpreter lock`. global interpreter lock - The lock used by Python threads to assure that only one thread - executes in the :term:`CPython` :term:`virtual machine` at a time. - This simplifies the CPython implementation by assuring that no two - processes can access the same memory at the same time. Locking the - entire interpreter makes it easier for the interpreter to be - multi-threaded, at the expense of much of the parallelism afforded by - multi-processor machines. Efforts have been made in the past to - create a "free-threaded" interpreter (one which locks shared data at a - much finer granularity), but so far none have been successful because - performance suffered in the common single-processor case. + The mechanism used by the :term:`CPython` interpreter to assure that + only one thread executes Python :term:`bytecode` at a time. + This simplifies the CPython implementation by making the object model + (including critical built-in types such as :class:`dict`) implicitly + safe against concurrent access. Locking the entire interpreter + makes it easier for the interpreter to be multi-threaded, at the + expense of much of the parallelism afforded by multi-processor + machines. + + However, some extension modules, either standard or third-party, + are designed so as to release the GIL when doing computationally-intensive + tasks such as compression or hashing. Also, the GIL is always released + when doing I/O. + + Past efforts to create a "free-threaded" interpreter (one which locks + shared data at a much finer granularity) have not been successful + because performance suffered in the common single-processor case. It + is believed that overcoming this performance issue would make the + implementation much more complicated and therefore costlier to maintain. hashable An object is *hashable* if it has a hash value which never changes during @@ -339,12 +349,12 @@ iterator An object representing a stream of data. Repeated calls to the iterator's - :meth:`__next__` (or passing it to the built-in function :func:`next`) - method return successive items in the stream. When no more data are - available a :exc:`StopIteration` exception is raised instead. At this + :meth:`__next__` method (or passing it to the built-in function + :func:`next`) return successive items in the stream. When no more data + are available a :exc:`StopIteration` exception is raised instead. At this point, the iterator object is exhausted and any further calls to its - :meth:`next` method just raise :exc:`StopIteration` again. Iterators are - required to have an :meth:`__iter__` method that returns the iterator + :meth:`__next__` method just raise :exc:`StopIteration` again. Iterators + are required to have an :meth:`__iter__` method that returns the iterator object itself so every iterator is also iterable and may be used in most places where other iterables are accepted. One notable exception is code which attempts multiple iteration passes. A container object (such as a @@ -418,9 +428,11 @@ :class:`importlib.abc.Loader` for an :term:`abstract base class`. mapping - A container object (such as :class:`dict`) which supports arbitrary key - lookups using the special method :meth:`__getitem__`. Mappings also - support :meth:`__len__`, :meth:`__iter__`, and :meth:`__contains__`. + A container object that supports arbitrary key lookups and implements the + methods specified in the :class:`Mapping` or :class:`MutableMapping` + :ref:`abstract base classes `. Examples include + :class:`dict`, :class:`collections.defaultdict`, + :class:`collections.OrderedDict` and :class:`collections.Counter`. metaclass The class of a class. Class definitions create a class name, a class Modified: python/branches/py3k-cdecimal/Doc/howto/logging.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/howto/logging.rst (original) +++ python/branches/py3k-cdecimal/Doc/howto/logging.rst Tue Jan 11 18:07:55 2011 @@ -857,50 +857,46 @@ #. :class:`FileHandler` instances send messages to disk files. -.. currentmodule:: logging.handlers - -#. :class:`BaseRotatingHandler` is the base class for handlers that +#. :class:`~handlers.BaseRotatingHandler` is the base class for handlers that rotate log files at a certain point. It is not meant to be instantiated - directly. Instead, use :class:`RotatingFileHandler` or - :class:`TimedRotatingFileHandler`. + directly. Instead, use :class:`~handlers.RotatingFileHandler` or + :class:`~handlers.TimedRotatingFileHandler`. -#. :class:`RotatingFileHandler` instances send messages to disk +#. :class:`~handlers.RotatingFileHandler` instances send messages to disk files, with support for maximum log file sizes and log file rotation. -#. :class:`TimedRotatingFileHandler` instances send messages to +#. :class:`~handlers.TimedRotatingFileHandler` instances send messages to disk files, rotating the log file at certain timed intervals. -#. :class:`SocketHandler` instances send messages to TCP/IP +#. :class:`~handlers.SocketHandler` instances send messages to TCP/IP sockets. -#. :class:`DatagramHandler` instances send messages to UDP +#. :class:`~handlers.DatagramHandler` instances send messages to UDP sockets. -#. :class:`SMTPHandler` instances send messages to a designated +#. :class:`~handlers.SMTPHandler` instances send messages to a designated email address. -#. :class:`SysLogHandler` instances send messages to a Unix +#. :class:`~handlers.SysLogHandler` instances send messages to a Unix syslog daemon, possibly on a remote machine. -#. :class:`NTEventLogHandler` instances send messages to a +#. :class:`~handlers.NTEventLogHandler` instances send messages to a Windows NT/2000/XP event log. -#. :class:`MemoryHandler` instances send messages to a buffer +#. :class:`~handlers.MemoryHandler` instances send messages to a buffer in memory, which is flushed whenever specific criteria are met. -#. :class:`HTTPHandler` instances send messages to an HTTP +#. :class:`~handlers.HTTPHandler` instances send messages to an HTTP server using either ``GET`` or ``POST`` semantics. -#. :class:`WatchedFileHandler` instances watch the file they are +#. :class:`~handlers.WatchedFileHandler` instances watch the file they are logging to. If the file changes, it is closed and reopened using the file name. This handler is only useful on Unix-like systems; Windows does not support the underlying mechanism used. -#. :class:`QueueHandler` instances send messages to a queue, such as +#. :class:`~handlers.QueueHandler` instances send messages to a queue, such as those implemented in the :mod:`queue` or :mod:`multiprocessing` modules. -.. currentmodule:: logging - #. :class:`NullHandler` instances do nothing with error messages. They are used by library developers who want to use logging, but want to avoid the 'No handlers could be found for logger XXX' message which can be displayed if @@ -911,7 +907,7 @@ The :class:`NullHandler` class. .. versionadded:: 3.2 - The :class:`~logging.handlers.QueueHandler` class. + The :class:`~handlers.QueueHandler` class. The :class:`NullHandler`, :class:`StreamHandler` and :class:`FileHandler` classes are defined in the core logging package. The other handlers are Modified: python/branches/py3k-cdecimal/Doc/howto/regex.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/howto/regex.rst (original) +++ python/branches/py3k-cdecimal/Doc/howto/regex.rst Tue Jan 11 18:07:55 2011 @@ -5,7 +5,6 @@ **************************** :Author: A.M. Kuchling -:Release: 0.05 .. TODO: Document lookbehind assertions @@ -24,11 +23,6 @@ Introduction ============ -The :mod:`re` module was added in Python 1.5, and provides Perl-style regular -expression patterns. Earlier versions of Python came with the :mod:`regex` -module, which provided Emacs-style patterns. The :mod:`regex` module was -removed completely in Python 2.5. - Regular expressions (called REs, or regexes, or regex patterns) are essentially a tiny, highly specialized programming language embedded inside Python and made available through the :mod:`re` module. Using this little language, you specify @@ -113,7 +107,10 @@ Some of the special sequences beginning with ``'\'`` represent predefined sets of characters that are often useful, such as the set of digits, the set of letters, or the set of anything that isn't whitespace. The following predefined -special sequences are available: +special sequences are a subset of those available. The equivalent classes are +for bytes patterns. For a complete list of sequences and expanded class +definitions for Unicode string patterns, see the last part of +:ref:`Regular Expression Syntax `. ``\d`` Matches any decimal digit; this is equivalent to the class ``[0-9]``. @@ -264,7 +261,7 @@ >>> import re >>> p = re.compile('ab*') >>> p - <_sre.SRE_Pattern object at 80b4150> + <_sre.SRE_Pattern object at 0x...> :func:`re.compile` also accepts an optional *flags* argument, used to enable various special features and syntax variations. We'll go over the available @@ -362,8 +359,8 @@ and more. You can learn about this by interactively experimenting with the :mod:`re` -module. If you have Tkinter available, you may also want to look at -:file:`Tools/scripts/redemo.py`, a demonstration program included with the +module. If you have :mod:`tkinter` available, you may also want to look at +:file:`Tools/demo/redemo.py`, a demonstration program included with the Python distribution. It allows you to enter REs and strings, and displays whether the RE matches or fails. :file:`redemo.py` can be quite useful when trying to debug a complicated RE. Phil Schwartz's `Kodos @@ -373,11 +370,10 @@ This HOWTO uses the standard Python interpreter for its examples. First, run the Python interpreter, import the :mod:`re` module, and compile a RE:: - Python 2.2.2 (#1, Feb 10 2003, 12:57:01) >>> import re >>> p = re.compile('[a-z]+') >>> p - <_sre.SRE_Pattern object at 80c3c28> + <_sre.SRE_Pattern object at 0x...> Now, you can try matching various strings against the RE ``[a-z]+``. An empty string shouldn't match at all, since ``+`` means 'one or more repetitions'. @@ -395,7 +391,7 @@ >>> m = p.match('tempo') >>> m - <_sre.SRE_Match object at 80c4f68> + <_sre.SRE_Match object at 0x...> Now you can query the :class:`MatchObject` for information about the matching string. :class:`MatchObject` instances also have several methods and @@ -434,7 +430,7 @@ >>> print(p.match('::: message')) None >>> m = p.search('::: message') ; print(m) - + <_sre.SRE_Match object at 0x...> >>> m.group() 'message' >>> m.span() @@ -459,11 +455,11 @@ :meth:`findall` has to create the entire list before it can be returned as the result. The :meth:`finditer` method returns a sequence of :class:`MatchObject` -instances as an :term:`iterator`. [#]_ :: +instances as an :term:`iterator`:: >>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...') >>> iterator - + >>> for match in iterator: ... print(match.span()) ... @@ -485,7 +481,7 @@ >>> print(re.match(r'From\s+', 'Fromage amk')) None >>> re.match(r'From\s+', 'From amk Thu May 14 19:12:10 1998') - + <_sre.SRE_Match object at 0x...> Under the hood, these functions simply create a pattern object for you and call the appropriate method on it. They also store the compiled object in a @@ -687,7 +683,7 @@ line, the RE to use is ``^From``. :: >>> print(re.search('^From', 'From Here to Eternity')) - + <_sre.SRE_Match object at 0x...> >>> print(re.search('^From', 'Reciting From Memory')) None @@ -699,11 +695,11 @@ or any location followed by a newline character. :: >>> print(re.search('}$', '{block}')) - + <_sre.SRE_Match object at 0x...> >>> print(re.search('}$', '{block} ')) None >>> print(re.search('}$', '{block}\n')) - + <_sre.SRE_Match object at 0x...> To match a literal ``'$'``, use ``\$`` or enclose it inside a character class, as in ``[$]``. @@ -728,7 +724,7 @@ >>> p = re.compile(r'\bclass\b') >>> print(p.search('no class at all')) - + <_sre.SRE_Match object at 0x...> >>> print(p.search('the declassified algorithm')) None >>> print(p.search('one subclass is')) @@ -746,7 +742,7 @@ >>> print(p.search('no class at all')) None >>> print(p.search('\b' + 'class' + '\b') ) - + <_sre.SRE_Match object at 0x...> Second, inside a character class, where there's no use for this assertion, ``\b`` represents the backspace character, for compatibility with Python's @@ -1316,8 +1312,8 @@ be *very* complicated. Use an HTML or XML parser module for such tasks.) -Not Using re.VERBOSE --------------------- +Using re.VERBOSE +---------------- By now you've probably noticed that regular expressions are a very compact notation, but they're not terribly readable. REs of moderate complexity can @@ -1366,8 +1362,3 @@ now-removed :mod:`regex` module, which won't help you much.) Consider checking it out from your library. - -.. rubric:: Footnotes - -.. [#] Introduced in Python 2.2.2. - Modified: python/branches/py3k-cdecimal/Doc/library/argparse.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/argparse.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/argparse.rst Tue Jan 11 18:07:55 2011 @@ -120,7 +120,9 @@ ArgumentParser objects ---------------------- -.. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], [argument_default], [parents], [prefix_chars], [conflict_handler], [formatter_class]) +.. class:: ArgumentParser([description], [epilog], [prog], [usage], [add_help], \ + [argument_default], [parents], [prefix_chars], \ + [conflict_handler], [formatter_class]) Create a new :class:`ArgumentParser` object. Each parameter has its own more detailed description below, but in short they are: @@ -563,7 +565,9 @@ The add_argument() method ------------------------- -.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], [const], [default], [type], [choices], [required], [help], [metavar], [dest]) +.. method:: ArgumentParser.add_argument(name or flags..., [action], [nargs], \ + [const], [default], [type], [choices], [required], \ + [help], [metavar], [dest]) Define how a single command line argument should be parsed. Each parameter has its own more detailed description below, but in short they are: @@ -777,9 +781,11 @@ >>> parser.add_argument('outfile', nargs='?', type=argparse.FileType('w'), ... default=sys.stdout) >>> parser.parse_args(['input.txt', 'output.txt']) - Namespace(infile=, outfile=) + Namespace(infile=<_io.TextIOWrapper name='input.txt' encoding='UTF-8'>, + outfile=<_io.TextIOWrapper name='output.txt' encoding='UTF-8'>) >>> parser.parse_args([]) - Namespace(infile=', mode 'r' at 0x...>, outfile=', mode 'w' at 0x...>) + Namespace(infile=<_io.TextIOWrapper name='' encoding='UTF-8'>, + outfile=<_io.TextIOWrapper name='' encoding='UTF-8'>) * ``'*'``. All command-line args present are gathered into a list. Note that it generally doesn't make much sense to have more than one positional argument @@ -875,26 +881,26 @@ By default, ArgumentParser objects read command-line args in as simple strings. However, quite often the command-line string should instead be interpreted as -another type, like a :class:`float`, :class:`int` or :class:`file`. The -``type`` keyword argument of :meth:`add_argument` allows any necessary -type-checking and type-conversions to be performed. Many common built-in types -can be used directly as the value of the ``type`` argument:: +another type, like a :class:`float` or :class:`int`. The ``type`` keyword +argument of :meth:`add_argument` allows any necessary type-checking and +type-conversions to be performed. Common built-in types and functions can be +used directly as the value of the ``type`` argument:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('foo', type=int) - >>> parser.add_argument('bar', type=file) + >>> parser.add_argument('bar', type=open) >>> parser.parse_args('2 temp.txt'.split()) - Namespace(bar=, foo=2) + Namespace(bar=<_io.TextIOWrapper name='temp.txt' encoding='UTF-8'>, foo=2) To ease the use of various types of files, the argparse module provides the factory FileType which takes the ``mode=`` and ``bufsize=`` arguments of the -``file`` object. For example, ``FileType('w')`` can be used to create a +:func:`open` function. For example, ``FileType('w')`` can be used to create a writable file:: >>> parser = argparse.ArgumentParser() >>> parser.add_argument('bar', type=argparse.FileType('w')) >>> parser.parse_args(['out.txt']) - Namespace(bar=) + Namespace(bar=<_io.TextIOWrapper name='out.txt' encoding='UTF-8'>) ``type=`` can take any callable that takes a single string argument and returns the type-converted value:: @@ -1506,7 +1512,7 @@ >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--output', type=argparse.FileType('wb', 0)) >>> parser.parse_args(['--output', 'out']) - Namespace(output=) + Namespace(output=<_io.BufferedWriter name='out'>) FileType objects understand the pseudo-argument ``'-'`` and automatically convert this into ``sys.stdin`` for readable :class:`FileType` objects and @@ -1515,7 +1521,7 @@ >>> parser = argparse.ArgumentParser() >>> parser.add_argument('infile', type=argparse.FileType('r')) >>> parser.parse_args(['-']) - Namespace(infile=', mode 'r' at 0x...>) + Namespace(infile=<_io.TextIOWrapper name='' encoding='UTF-8'>) Argument groups @@ -1753,11 +1759,12 @@ A partial upgrade path from optparse to argparse: -* Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` calls. +* Replace all ``add_option()`` calls with :meth:`ArgumentParser.add_argument` + calls. * Replace ``options, args = parser.parse_args()`` with ``args = - parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` calls for the - positional arguments. + parser.parse_args()`` and add additional :meth:`ArgumentParser.add_argument` + calls for the positional arguments. * Replace callback actions and the ``callback_*`` keyword arguments with ``type`` or ``action`` arguments. Modified: python/branches/py3k-cdecimal/Doc/library/ast.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/ast.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/ast.rst Tue Jan 11 18:07:55 2011 @@ -7,6 +7,9 @@ .. sectionauthor:: Martin v. L?wis .. sectionauthor:: Georg Brandl +**Source code:** :source:`Lib/ast.py` + +-------------- The :mod:`ast` module helps Python applications to process trees of the Python abstract syntax grammar. The abstract syntax itself might change with each @@ -19,9 +22,6 @@ classes all inherit from :class:`ast.AST`. An abstract syntax tree can be compiled into a Python code object using the built-in :func:`compile` function. -.. seealso:: - - Latest version of the :source:`ast module Python source code ` Node classes ------------ @@ -173,9 +173,9 @@ .. function:: walk(node) - Recursively yield all child nodes of *node*, in no specified order. This is - useful if you only want to modify nodes in place and don't care about the - context. + Recursively yield all descendant nodes in the tree starting at *node* + (including *node* itself), in no specified order. This is useful if you only + want to modify nodes in place and don't care about the context. .. class:: NodeVisitor() Modified: python/branches/py3k-cdecimal/Doc/library/atexit.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/atexit.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/atexit.rst Tue Jan 11 18:07:55 2011 @@ -11,11 +11,6 @@ functions. Functions thus registered are automatically executed upon normal interpreter termination. -.. seealso:: - - Latest version of the :source:`atexit Python source code - ` - Note: the functions registered via this module are not called when the program is killed by a signal not handled by Python, when a Python fatal internal error is detected, or when :func:`os._exit` is called. @@ -103,3 +98,4 @@ This obviously only works with functions that don't take arguments. + Modified: python/branches/py3k-cdecimal/Doc/library/bisect.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/bisect.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/bisect.rst Tue Jan 11 18:07:55 2011 @@ -7,6 +7,10 @@ .. sectionauthor:: Raymond Hettinger .. example based on the PyModules FAQ entry by Aaron Watters +**Source code:** :source:`Lib/bisect.py` + +-------------- + This module provides support for maintaining a list in sorted order without having to sort the list after each insertion. For long lists of items with expensive comparison operations, this can be an improvement over the more common @@ -14,11 +18,6 @@ algorithm to do its work. The source code may be most useful as a working example of the algorithm (the boundary conditions are already right!). -.. seealso:: - - Latest version of the :source:`bisect module Python source code - ` - The following functions are provided: Modified: python/branches/py3k-cdecimal/Doc/library/calendar.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/calendar.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/calendar.rst Tue Jan 11 18:07:55 2011 @@ -6,6 +6,9 @@ of the Unix cal program. .. sectionauthor:: Drew Csillag +**Source code:** :source:`Lib/calendar.py` + +-------------- This module allows you to output calendars like the Unix :program:`cal` program, and provides additional useful functions related to the calendar. By default, @@ -21,10 +24,6 @@ calendar in Dershowitz and Reingold's book "Calendrical Calculations", where it's the base calendar for all computations. -.. seealso:: - - Latest version of the :source:`calendar module Python source code - ` .. class:: Calendar(firstweekday=0) @@ -313,4 +312,3 @@ Module :mod:`time` Low-level time related functions. - Modified: python/branches/py3k-cdecimal/Doc/library/cmd.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/cmd.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/cmd.rst Tue Jan 11 18:07:55 2011 @@ -5,16 +5,15 @@ :synopsis: Build line-oriented command interpreters. .. sectionauthor:: Eric S. Raymond +**Source code:** :source:`Lib/cmd.py` + +-------------- The :class:`Cmd` class provides a simple framework for writing line-oriented command interpreters. These are often useful for test harnesses, administrative tools, and prototypes that will later be wrapped in a more sophisticated interface. -.. seealso:: - - Latest version of the :source:`cmd module Python source code ` - .. class:: Cmd(completekey='tab', stdin=None, stdout=None) A :class:`Cmd` instance or subclass instance is a line-oriented interpreter Modified: python/branches/py3k-cdecimal/Doc/library/collections.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/collections.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/collections.rst Tue Jan 11 18:07:55 2011 @@ -12,6 +12,10 @@ import itertools __name__ = '' +**Source code:** :source:`Lib/collections.py` + +-------------- + This module implements specialized container datatypes providing alternatives to Python's general purpose built-in containers, :class:`dict`, :class:`list`, :class:`set`, and :class:`tuple`. @@ -31,11 +35,6 @@ :ref:`abstract-base-classes` that can be used to test whether a class provides a particular interface, for example, whether it is hashable or a mapping. -.. seealso:: - - Latest version of the :source:`collections module Python source code - ` - :class:`Counter` objects ------------------------ Modified: python/branches/py3k-cdecimal/Doc/library/contextlib.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/contextlib.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/contextlib.rst Tue Jan 11 18:07:55 2011 @@ -4,16 +4,14 @@ .. module:: contextlib :synopsis: Utilities for with-statement contexts. +**Source code:** :source:`Lib/contextlib.py` + +-------------- This module provides utilities for common tasks involving the :keyword:`with` statement. For more information see also :ref:`typecontextmanager` and :ref:`context-managers`. -.. seealso:: - - Latest version of the :source:`contextlib Python source code - ` - Functions provided: Modified: python/branches/py3k-cdecimal/Doc/library/csv.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/csv.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/csv.rst Tue Jan 11 18:07:55 2011 @@ -50,7 +50,7 @@ Return a reader object which will iterate over lines in the given *csvfile*. *csvfile* can be any object which supports the :term:`iterator` protocol and returns a - string each time its :meth:`!next` method is called --- :term:`file objects + string each time its :meth:`!__next__` method is called --- :term:`file objects ` and list objects are both suitable. If *csvfile* is a file object, it should be opened with ``newline=''``. [#]_ An optional *dialect* parameter can be given which is used to define a set of parameters Modified: python/branches/py3k-cdecimal/Doc/library/datetime.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/datetime.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/datetime.rst Tue Jan 11 18:07:55 2011 @@ -1661,9 +1661,6 @@ implementation. Note that the 1999 version of the C standard added additional format codes. -The exact range of years for which :meth:`strftime` works also varies across -platforms. Regardless of platform, years before 1900 cannot be used. - +-----------+--------------------------------+-------+ | Directive | Meaning | Notes | +===========+================================+=======+ @@ -1706,7 +1703,7 @@ | | AM or PM. | | +-----------+--------------------------------+-------+ | ``%S`` | Second as a decimal number | \(3) | -| | [00,61]. | | +| | [00,59]. | | +-----------+--------------------------------+-------+ | ``%U`` | Week number of the year | \(4) | | | (Sunday as the first day of | | @@ -1736,10 +1733,11 @@ | ``%y`` | Year without century as a | | | | decimal number [00,99]. | | +-----------+--------------------------------+-------+ -| ``%Y`` | Year with century as a decimal | | -| | number. | | +| ``%Y`` | Year with century as a decimal | \(5) | +| | number [0001,9999] (strptime), | | +| | [1000,9999] (strftime). | | +-----------+--------------------------------+-------+ -| ``%z`` | UTC offset in the form +HHMM | \(5) | +| ``%z`` | UTC offset in the form +HHMM | \(6) | | | or -HHMM (empty string if the | | | | the object is naive). | | +-----------+--------------------------------+-------+ @@ -1763,18 +1761,26 @@ the output hour field if the ``%I`` directive is used to parse the hour. (3) - The range really is ``0`` to ``61``; according to the Posix standard this - accounts for leap seconds and the (very rare) double leap seconds. - The :mod:`time` module may produce and does accept leap seconds since - it is based on the Posix standard, but the :mod:`datetime` module - does not accept leap seconds in :meth:`strptime` input nor will it - produce them in :func:`strftime` output. + Unlike :mod:`time` module, :mod:`datetime` module does not support + leap seconds. (4) When used with the :meth:`strptime` method, ``%U`` and ``%W`` are only used in calculations when the day of the week and the year are specified. (5) + For technical reasons, :meth:`strftime` method does not support + dates before year 1000: ``t.strftime(format)`` will raise a + :exc:`ValueError` when ``t.year < 1000`` even if ``format`` does + not contain ``%Y`` directive. The :meth:`strptime` method can + parse years in the full [1, 9999] range, but years < 1000 must be + zero-filled to 4-digit width. + + .. versionchanged:: 3.2 + In previous versions, :meth:`strftime` method was restricted to + years >= 1900. + +(6) For example, if :meth:`utcoffset` returns ``timedelta(hours=-3, minutes=-30)``, ``%z`` is replaced with the string ``'-0330'``. Modified: python/branches/py3k-cdecimal/Doc/library/decimal.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/decimal.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/decimal.rst Tue Jan 11 18:07:55 2011 @@ -1657,7 +1657,8 @@ build(trailneg) for i in range(places): build(next() if digits else '0') - build(dp) + if places: + build(dp) if not digits: build('0') i = 0 Modified: python/branches/py3k-cdecimal/Doc/library/dis.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/dis.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/dis.rst Tue Jan 11 18:07:55 2011 @@ -4,19 +4,18 @@ .. module:: dis :synopsis: Disassembler for Python bytecode. +**Source code:** :source:`Lib/dis.py` + +-------------- The :mod:`dis` module supports the analysis of CPython :term:`bytecode` by disassembling it. The CPython bytecode which this module takes as an input is defined in the file :file:`Include/opcode.h` and used by the compiler and the interpreter. -.. seealso:: - - Latest version of the :source:`dis module Python source code ` - .. impl-detail:: - Bytecode is an implementation detail of the CPython interpreter! No + Bytecode is an implementation detail of the CPython interpreter. No guarantees are made that bytecode will not be added, removed, or changed between versions of Python. Use of this module should not be considered to work across Python VMs or Python releases. Modified: python/branches/py3k-cdecimal/Doc/library/email.charset.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/email.charset.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/email.charset.rst Tue Jan 11 18:07:55 2011 @@ -142,12 +142,6 @@ it is *input_charset*. - .. method:: encoded_header_len() - - Return the length of the encoded header string, properly calculating for - quoted-printable or base64 encoding. - - .. method:: header_encode(string) Header-encode the string *string*. @@ -156,6 +150,16 @@ *header_encoding* attribute. + .. method:: header_encode_lines(string, maxlengths) + + Header-encode a *string* by converting it first to bytes. + + This is similar to :meth:`header_encode` except that the string is fit + into maximum line lengths as given by the argument *maxlengths*, which + must be an iterator: each element returned from this iterator will provide + the next maximum line length. + + .. method:: body_encode(string) Body-encode the string *string*. Modified: python/branches/py3k-cdecimal/Doc/library/email.generator.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/email.generator.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/email.generator.rst Tue Jan 11 18:07:55 2011 @@ -79,8 +79,8 @@ Messages parsed with a Bytes parser that have a :mailheader:`Content-Transfer-Encoding` of 8bit will be converted to a - use a 7bit Content-Transfer-Encoding. Any other non-ASCII bytes in the - message structure will be converted to '?' characters. + use a 7bit Content-Transfer-Encoding. Non-ASCII bytes in the headers + will be :rfc:`2047` encoded with a charset of `unknown-8bit`. .. versionchanged:: 3.2 Added support for re-encoding 8bit message bodies, and the *linesep* Modified: python/branches/py3k-cdecimal/Doc/library/email.header.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/email.header.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/email.header.rst Tue Jan 11 18:07:55 2011 @@ -94,14 +94,15 @@ decoded with that character set. If *s* is an instance of :class:`str`, then *charset* is a hint specifying - the character set of the characters in the string. In this case, when - producing an :rfc:`2822`\ -compliant header using :rfc:`2047` rules, the - Unicode string will be encoded using the following charsets in order: - ``us-ascii``, the *charset* hint, ``utf-8``. The first character set to - not provoke a :exc:`UnicodeError` is used. + the character set of the characters in the string. - Optional *errors* is passed through to any :func:`encode` or - :func:`ustr.encode` call, and defaults to "strict". + In either case, when producing an :rfc:`2822`\ -compliant header using + :rfc:`2047` rules, the string will be encoded using the output codec of + the charset. If the string cannot be encoded using the output codec, a + UnicodeError will be raised. + + Optional *errors* is passed as the errors argument to the decode call + if *s* is a byte string. .. method:: encode(splitchars=';, \\t', maxlinelen=None, linesep='\\n') @@ -129,13 +130,15 @@ .. method:: __str__() - A synonym for :meth:`Header.encode`. Useful for ``str(aHeader)``. - + Returns an approximation of the :class:`Header` as a string, using an + unlimited line length. All pieces are converted to unicode using the + specified encoding and joined together appropriately. Any pieces with a + charset of `unknown-8bit` are decoded as `ASCII` using the `replace` + error handler. - .. method:: __unicode__() + .. versionchanged:: 3.2 + Added handling for the `unknown-8bit` charset. - A helper for :class:`str`'s :func:`encode` method. Returns the header as - a Unicode string. .. method:: __eq__(other) Modified: python/branches/py3k-cdecimal/Doc/library/email.message.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/email.message.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/email.message.rst Tue Jan 11 18:07:55 2011 @@ -169,9 +169,10 @@ Note that in all cases, any envelope header present in the message is not included in the mapping interface. - In a model generated from bytes, any header values that (in contravention - of the RFCs) contain non-ASCII bytes will have those bytes transformed - into '?' characters when the values are retrieved through this interface. + In a model generated from bytes, any header values that (in contravention of + the RFCs) contain non-ASCII bytes will, when retrieved through this + interface, be represented as :class:`~email.header.Header` objects with + a charset of `unknown-8bit`. .. method:: __len__() Modified: python/branches/py3k-cdecimal/Doc/library/exceptions.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/exceptions.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/exceptions.rst Tue Jan 11 18:07:55 2011 @@ -18,12 +18,10 @@ The built-in exceptions listed below can be generated by the interpreter or built-in functions. Except where mentioned, they have an "associated value" -indicating the detailed cause of the error. This may be a string or a tuple -containing several items of information (e.g., an error code and a string -explaining the code). The associated value is usually passed to the exception -class's constructor. If the exception class is derived from the standard root -class :exc:`BaseException`, the associated value is present as the exception -instance's :attr:`args` attribute. +indicating the detailed cause of the error. This may be a string or a tuple of +several items of information (e.g., an error code and a string explaining the +code). The associated value is usually passed as arguments to the exception +class's constructor. User code can raise built-in exceptions. This can be used to test an exception handler or to report an error condition "just like" the situation in which the @@ -38,16 +36,32 @@ The following exceptions are used mostly as base classes for other exceptions. -.. XXX document with_traceback() - .. exception:: BaseException The base class for all built-in exceptions. It is not meant to be directly - inherited by user-defined classes (for that use :exc:`Exception`). If + inherited by user-defined classes (for that, use :exc:`Exception`). If :func:`bytes` or :func:`str` is called on an instance of this class, the - representation of the argument(s) to the instance are returned or the empty - string when there were no arguments. All arguments are stored in :attr:`args` - as a tuple. + representation of the argument(s) to the instance are returned, or the empty + string when there were no arguments. + + .. attribute:: args + + The tuple of arguments given to the exception constructor. Some built-in + exceptions (like :exc:`IOError`) expect a certain number of arguments and + assign a special meaning to the elements of this tuple, while others are + usually called only with a single string giving an error message. + + .. method:: with_traceback(tb) + + This method sets *tb* as the new traceback for the exception and returns + the exception object. It is usually used in exception handling code like + this:: + + try: + ... + except SomeException: + tb = sys.exc_info()[2] + raise OtherException(...).with_traceback(tb) .. exception:: Exception Modified: python/branches/py3k-cdecimal/Doc/library/filecmp.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/filecmp.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/filecmp.rst Tue Jan 11 18:07:55 2011 @@ -5,16 +5,14 @@ :synopsis: Compare files efficiently. .. sectionauthor:: Moshe Zadka +**Source code:** :source:`Lib/filecmp.py` + +-------------- The :mod:`filecmp` module defines functions to compare files and directories, with various optional time/correctness trade-offs. For comparing files, see also the :mod:`difflib` module. -.. seealso:: - - Latest version of the :source:`filecmp Python source code - ` - The :mod:`filecmp` module defines the following functions: Modified: python/branches/py3k-cdecimal/Doc/library/fileinput.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/fileinput.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/fileinput.rst Tue Jan 11 18:07:55 2011 @@ -6,6 +6,9 @@ .. moduleauthor:: Guido van Rossum .. sectionauthor:: Fred L. Drake, Jr. +**Source code:** :source:`Lib/fileinput.py` + +-------------- This module implements a helper class and functions to quickly write a loop over standard input or a list of files. If you just want to read or @@ -44,11 +47,6 @@ returns an accordingly opened file-like object. Two useful hooks are already provided by this module. -.. seealso:: - - Latest version of the :source:`fileinput Python source code - ` - The following function is the primary interface of this module: Modified: python/branches/py3k-cdecimal/Doc/library/fnmatch.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/fnmatch.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/fnmatch.rst Tue Jan 11 18:07:55 2011 @@ -9,6 +9,10 @@ .. index:: module: re +**Source code:** :source:`Lib/fnmatch.py` + +-------------- + This module provides support for Unix shell-style wildcards, which are *not* the same as regular expressions (which are documented in the :mod:`re` module). The special characters used in shell-style wildcards are: @@ -33,10 +37,6 @@ a period are not special for this module, and are matched by the ``*`` and ``?`` patterns. -.. seealso:: - - Latest version of the :source:`fnmatch Python source code - ` .. function:: fnmatch(filename, pattern) @@ -92,4 +92,3 @@ Module :mod:`glob` Unix shell-style path expansion. - Modified: python/branches/py3k-cdecimal/Doc/library/functools.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/functools.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/functools.rst Tue Jan 11 18:07:55 2011 @@ -8,16 +8,14 @@ .. moduleauthor:: Nick Coghlan .. sectionauthor:: Peter Harris +**Source code:** :source:`Lib/functools.py` + +-------------- The :mod:`functools` module is for higher-order functions: functions that act on or return other functions. In general, any callable object can be treated as a function for the purposes of this module. -.. seealso:: - - Latest version of the :source:`functools Python source code - ` - The :mod:`functools` module defines the following functions: .. function:: cmp_to_key(func) Modified: python/branches/py3k-cdecimal/Doc/library/glob.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/glob.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/glob.rst Tue Jan 11 18:07:55 2011 @@ -7,6 +7,10 @@ .. index:: single: filenames; pathname expansion +**Source code:** :source:`Lib/glob.py` + +-------------- + The :mod:`glob` module finds all the pathnames matching a specified pattern according to the rules used by the Unix shell. No tilde expansion is done, but ``*``, ``?``, and character ranges expressed with ``[]`` will be correctly @@ -15,9 +19,6 @@ subshell. (For tilde and shell variable expansion, use :func:`os.path.expanduser` and :func:`os.path.expandvars`.) -.. seealso:: - - Latest version of the :source:`glob module Python source code ` .. function:: glob(pathname) Modified: python/branches/py3k-cdecimal/Doc/library/heapq.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/heapq.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/heapq.rst Tue Jan 11 18:07:55 2011 @@ -8,13 +8,12 @@ .. sectionauthor:: Fran?ois Pinard .. sectionauthor:: Raymond Hettinger -This module provides an implementation of the heap queue algorithm, also known -as the priority queue algorithm. +**Source code:** :source:`Lib/heapq.py` -.. seealso:: +-------------- - Latest version of the :source:`heapq Python source code - ` +This module provides an implementation of the heap queue algorithm, also known +as the priority queue algorithm. Heaps are binary trees for which every parent node has a value less than or equal to any of its children. This implementation uses arrays for which Modified: python/branches/py3k-cdecimal/Doc/library/index.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/index.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/index.rst Tue Jan 11 18:07:55 2011 @@ -49,6 +49,7 @@ strings.rst datatypes.rst numeric.rst + functional.rst filesys.rst persistence.rst archiving.rst Modified: python/branches/py3k-cdecimal/Doc/library/inspect.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/inspect.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/inspect.rst Tue Jan 11 18:07:55 2011 @@ -176,17 +176,16 @@ .. function:: getmoduleinfo(path) - Returns a :term:`named tuple` ``ModuleInfo(name, suffix, mode, - module_type)`` of values that describe how Python will interpret the file - identified by *path* if it is a module, or ``None`` if it would not be - identified as a module. The return tuple is ``(name, suffix, mode, mtype)``, - where *name* is the name of the module without the name of any enclosing - package, *suffix* is the trailing part of the file name (which may not be a - dot-delimited extension), *mode* is the :func:`open` mode that would be used - (``'r'`` or ``'rb'``), and *mtype* is an integer giving the type of the - module. *mtype* will have a value which can be compared to the constants - defined in the :mod:`imp` module; see the documentation for that module for - more information on module types. + Returns a :term:`named tuple` ``ModuleInfo(name, suffix, mode, module_type)`` + of values that describe how Python will interpret the file identified by + *path* if it is a module, or ``None`` if it would not be identified as a + module. In that tuple, *name* is the name of the module without the name of + any enclosing package, *suffix* is the trailing part of the file name (which + may not be a dot-delimited extension), *mode* is the :func:`open` mode that + would be used (``'r'`` or ``'rb'``), and *module_type* is an integer giving + the type of the module. *module_type* will have a value which can be + compared to the constants defined in the :mod:`imp` module; see the + documentation for that module for more information on module types. .. function:: getmodulename(path) @@ -391,12 +390,12 @@ .. function:: getargspec(func) Get the names and default values of a Python function's arguments. A - :term:`named tuple` ``ArgSpec(args, varargs, keywords, - defaults)`` is returned. *args* is a list of - the argument names. *varargs* and *varkw* are the names of the ``*`` and - ``**`` arguments or ``None``. *defaults* is a tuple of default argument - values or None if there are no default arguments; if this tuple has *n* - elements, they correspond to the last *n* elements listed in *args*. + :term:`named tuple` ``ArgSpec(args, varargs, keywords, defaults)`` is + returned. *args* is a list of the argument names. *varargs* and *keywords* + are the names of the ``*`` and ``**`` arguments or ``None``. *defaults* is a + tuple of default argument values or None if there are no default arguments; + if this tuple has *n* elements, they correspond to the last *n* elements + listed in *args*. .. deprecated:: 3.0 Use :func:`getfullargspec` instead, which provides information about @@ -425,8 +424,8 @@ Get information about arguments passed into a particular frame. A :term:`named tuple` ``ArgInfo(args, varargs, keywords, locals)`` is - returned. *args* is a list of the argument names. *varargs* and *varkw* are - the names of the ``*`` and ``**`` arguments or ``None``. *locals* is the + returned. *args* is a list of the argument names. *varargs* and *keywords* + are the names of the ``*`` and ``**`` arguments or ``None``. *locals* is the locals dictionary of the given frame. Modified: python/branches/py3k-cdecimal/Doc/library/keyword.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/keyword.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/keyword.rst Tue Jan 11 18:07:55 2011 @@ -4,6 +4,9 @@ .. module:: keyword :synopsis: Test whether a string is a keyword in Python. +**Source code:** :source:`Lib/keyword.py` + +-------------- This module allows a Python program to determine if a string is a keyword. @@ -18,9 +21,3 @@ Sequence containing all the keywords defined for the interpreter. If any keywords are defined to only be active when particular :mod:`__future__` statements are in effect, these will be included as well. - - -.. seealso:: - - Latest version of the :source:`keyword module Python source code - ` Modified: python/branches/py3k-cdecimal/Doc/library/linecache.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/linecache.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/linecache.rst Tue Jan 11 18:07:55 2011 @@ -5,17 +5,15 @@ :synopsis: This module provides random access to individual lines from text files. .. sectionauthor:: Moshe Zadka +**Source code:** :source:`Lib/linecache.py` + +-------------- The :mod:`linecache` module allows one to get any line from any file, while attempting to optimize internally, using a cache, the common case where many lines are read from a single file. This is used by the :mod:`traceback` module to retrieve source lines for inclusion in the formatted traceback. -.. seealso:: - - Latest version of the :source:`linecache module Python source code - ` - The :mod:`linecache` module defines the following functions: Modified: python/branches/py3k-cdecimal/Doc/library/numeric.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/numeric.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/numeric.rst Tue Jan 11 18:07:55 2011 @@ -24,6 +24,3 @@ decimal.rst fractions.rst random.rst - itertools.rst - functools.rst - operator.rst Modified: python/branches/py3k-cdecimal/Doc/library/operator.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/operator.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/operator.rst Tue Jan 11 18:07:55 2011 @@ -19,8 +19,7 @@ trailing ``__`` are also provided for convenience. The functions fall into categories that perform object comparisons, logical -operations, mathematical operations, sequence operations, and abstract type -tests. +operations, mathematical operations and sequence operations. The object comparison functions are useful for all objects, and are named after the rich comparison operators they support: @@ -226,91 +225,6 @@ Set the value of *a* at index *b* to *c*. - -Many operations have an "in-place" version. The following functions provide a -more primitive access to in-place operators than the usual syntax does; for -example, the :term:`statement` ``x += y`` is equivalent to -``x = operator.iadd(x, y)``. Another way to put it is to say that -``z = operator.iadd(x, y)`` is equivalent to the compound statement -``z = x; z += y``. - -.. function:: iadd(a, b) - __iadd__(a, b) - - ``a = iadd(a, b)`` is equivalent to ``a += b``. - - -.. function:: iand(a, b) - __iand__(a, b) - - ``a = iand(a, b)`` is equivalent to ``a &= b``. - - -.. function:: iconcat(a, b) - __iconcat__(a, b) - - ``a = iconcat(a, b)`` is equivalent to ``a += b`` for *a* and *b* sequences. - - -.. function:: ifloordiv(a, b) - __ifloordiv__(a, b) - - ``a = ifloordiv(a, b)`` is equivalent to ``a //= b``. - - -.. function:: ilshift(a, b) - __ilshift__(a, b) - - ``a = ilshift(a, b)`` is equivalent to ``a <<= b``. - - -.. function:: imod(a, b) - __imod__(a, b) - - ``a = imod(a, b)`` is equivalent to ``a %= b``. - - -.. function:: imul(a, b) - __imul__(a, b) - - ``a = imul(a, b)`` is equivalent to ``a *= b``. - - -.. function:: ior(a, b) - __ior__(a, b) - - ``a = ior(a, b)`` is equivalent to ``a |= b``. - - -.. function:: ipow(a, b) - __ipow__(a, b) - - ``a = ipow(a, b)`` is equivalent to ``a **= b``. - - -.. function:: irshift(a, b) - __irshift__(a, b) - - ``a = irshift(a, b)`` is equivalent to ``a >>= b``. - - -.. function:: isub(a, b) - __isub__(a, b) - - ``a = isub(a, b)`` is equivalent to ``a -= b``. - - -.. function:: itruediv(a, b) - __itruediv__(a, b) - - ``a = itruediv(a, b)`` is equivalent to ``a /= b``. - - -.. function:: ixor(a, b) - __ixor__(a, b) - - ``a = ixor(a, b)`` is equivalent to ``a ^= b``. - Example: Build a dictionary that maps the ordinals from ``0`` to ``255`` to their character equivalents. @@ -491,3 +405,112 @@ | Ordering | ``a > b`` | ``gt(a, b)`` | +-----------------------+-------------------------+---------------------------------------+ +Inplace Operators +================= + +Many operations have an "in-place" version. Listed below are functions +providing a more primitive access to in-place operators than the usual syntax +does; for example, the :term:`statement` ``x += y`` is equivalent to +``x = operator.iadd(x, y)``. Another way to put it is to say that +``z = operator.iadd(x, y)`` is equivalent to the compound statement +``z = x; z += y``. + +In those examples, note that when an in-place method is called, the computation +and assignment are performed in two separate steps. The in-place functions +listed below only do the first step, calling the in-place method. The second +step, assignment, is not handled. + +For immutable targets such as strings, numbers, and tuples, the updated +value is computed, but not assigned back to the input variable: + +>>> a = 'hello' +>>> iadd(a, ' world') +'hello world' +>>> a +'hello' + +For mutable targets such as lists and dictionaries, the inplace method +will perform the update, so no subsequent assignment is necessary: + +>>> s = ['h', 'e', 'l', 'l', 'o'] +>>> iadd(s, [' ', 'w', 'o', 'r', 'l', 'd']) +['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'] +>>> s +['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'] + +.. function:: iadd(a, b) + __iadd__(a, b) + + ``a = iadd(a, b)`` is equivalent to ``a += b``. + + +.. function:: iand(a, b) + __iand__(a, b) + + ``a = iand(a, b)`` is equivalent to ``a &= b``. + + +.. function:: iconcat(a, b) + __iconcat__(a, b) + + ``a = iconcat(a, b)`` is equivalent to ``a += b`` for *a* and *b* sequences. + + +.. function:: ifloordiv(a, b) + __ifloordiv__(a, b) + + ``a = ifloordiv(a, b)`` is equivalent to ``a //= b``. + + +.. function:: ilshift(a, b) + __ilshift__(a, b) + + ``a = ilshift(a, b)`` is equivalent to ``a <<= b``. + + +.. function:: imod(a, b) + __imod__(a, b) + + ``a = imod(a, b)`` is equivalent to ``a %= b``. + + +.. function:: imul(a, b) + __imul__(a, b) + + ``a = imul(a, b)`` is equivalent to ``a *= b``. + + +.. function:: ior(a, b) + __ior__(a, b) + + ``a = ior(a, b)`` is equivalent to ``a |= b``. + + +.. function:: ipow(a, b) + __ipow__(a, b) + + ``a = ipow(a, b)`` is equivalent to ``a **= b``. + + +.. function:: irshift(a, b) + __irshift__(a, b) + + ``a = irshift(a, b)`` is equivalent to ``a >>= b``. + + +.. function:: isub(a, b) + __isub__(a, b) + + ``a = isub(a, b)`` is equivalent to ``a -= b``. + + +.. function:: itruediv(a, b) + __itruediv__(a, b) + + ``a = itruediv(a, b)`` is equivalent to ``a /= b``. + + +.. function:: ixor(a, b) + __ixor__(a, b) + + ``a = ixor(a, b)`` is equivalent to ``a ^= b``. Modified: python/branches/py3k-cdecimal/Doc/library/optparse.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/optparse.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/optparse.rst Tue Jan 11 18:07:55 2011 @@ -61,9 +61,9 @@ .. code-block:: text - usage: [options] + Usage: [options] - options: + Options: -h, --help show this help message and exit -f FILE, --file=FILE write report to FILE -q, --quiet don't print status messages to stdout @@ -492,9 +492,9 @@ .. code-block:: text - usage: [options] arg1 arg2 + Usage: [options] arg1 arg2 - options: + Options: -h, --help show this help message and exit -v, --verbose make lots of noise [default] -q, --quiet be vewwy quiet (I'm hunting wabbits) @@ -518,7 +518,7 @@ is then printed before the detailed option help. If you don't supply a usage string, :mod:`optparse` uses a bland but sensible - default: ``"usage: %prog [options]"``, which is fine if your script doesn't + default: ``"Usage: %prog [options]"``, which is fine if your script doesn't take any positional arguments. * every option defines a help string, and doesn't worry about line-wrapping--- @@ -550,12 +550,33 @@ default value. If an option has no default value (or the default value is ``None``), ``%default`` expands to ``none``. +Grouping Options +++++++++++++++++ + When dealing with many options, it is convenient to group these options for better help output. An :class:`OptionParser` can contain several option groups, each of which can contain several options. -Continuing with the parser defined above, adding an :class:`OptionGroup` to a -parser is easy:: +An option group is obtained using the class :class:`OptionGroup`: + +.. class:: OptionGroup(parser, title, description=None) + + where + + * parser is the :class:`OptionParser` instance the group will be insterted in + to + * title is the group title + * description, optional, is a long description of the group + +:class:`OptionGroup` inherits from :class:`OptionContainer` (like +:class:`OptionParser`) and so the :meth:`add_option` method can be used to add +an option to the group. + +Once all the options are declared, using the :class:`OptionParser` method +:meth:`add_option_group` the group is added to the previously defined parser. + +Continuing with the parser defined in the previous section, adding an +:class:`OptionGroup` to a parser is easy:: group = OptionGroup(parser, "Dangerous Options", "Caution: use these options at your own risk. " @@ -567,20 +588,73 @@ .. code-block:: text - usage: [options] arg1 arg2 + Usage: [options] arg1 arg2 + + Options: + -h, --help show this help message and exit + -v, --verbose make lots of noise [default] + -q, --quiet be vewwy quiet (I'm hunting wabbits) + -f FILE, --filename=FILE + write output to FILE + -m MODE, --mode=MODE interaction mode: novice, intermediate, or + expert [default: intermediate] + + Dangerous Options: + Caution: use these options at your own risk. It is believed that some + of them bite. + + -g Group option. + +A bit more complete example might invole using more than one group: still +extendind the previous example:: + + group = OptionGroup(parser, "Dangerous Options", + "Caution: use these options at your own risk. " + "It is believed that some of them bite.") + group.add_option("-g", action="store_true", help="Group option.") + parser.add_option_group(group) + + group = OptionGroup(parser, "Debug Options") + group.add_option("-d", "--debug", action="store_true", + help="Print debug information") + group.add_option("-s", "--sql", action="store_true", + help="Print all SQL statements executed") + group.add_option("-e", action="store_true", help="Print every action done") + parser.add_option_group(group) + +that results in the following output: + +.. code-block:: text + + Usage: [options] arg1 arg2 + + Options: + -h, --help show this help message and exit + -v, --verbose make lots of noise [default] + -q, --quiet be vewwy quiet (I'm hunting wabbits) + -f FILE, --filename=FILE + write output to FILE + -m MODE, --mode=MODE interaction mode: novice, intermediate, or expert + [default: intermediate] + + Dangerous Options: + Caution: use these options at your own risk. It is believed that some + of them bite. + + -g Group option. + + Debug Options: + -d, --debug Print debug information + -s, --sql Print all SQL statements executed + -e Print every action done + +Another interesting method, in particular when working programmatically with +option groups is: + +.. method:: OptionParser.get_option_group(opt_str) - options: - -h, --help show this help message and exit - -v, --verbose make lots of noise [default] - -q, --quiet be vewwy quiet (I'm hunting wabbits) - -fFILE, --file=FILE write output to FILE - -mMODE, --mode=MODE interaction mode: one of 'novice', 'intermediate' - [default], 'expert' - - Dangerous Options: - Caution: use of these options is at your own risk. It is believed that - some of them bite. - -g Group option. + Return, if defined, the :class:`OptionGroup` that has the title or the long + description equals to *opt_str* .. _optparse-printing-version-string: @@ -652,14 +726,14 @@ that takes an integer:: $ /usr/bin/foo -n 4x - usage: foo [options] + Usage: foo [options] foo: error: option -n: invalid integer value: '4x' Or, where the user fails to pass a value at all:: $ /usr/bin/foo -n - usage: foo [options] + Usage: foo [options] foo: error: -n option requires an argument @@ -1161,9 +1235,9 @@ .. code-block:: text - usage: foo.py [options] + Usage: foo.py [options] - options: + Options: -h, --help Show this help message and exit -v Be moderately verbose --file=FILENAME Input file to read data from @@ -1358,7 +1432,7 @@ option strings. Now ``--dry-run`` is the only way for the user to activate that option. If the user asks for help, the help message will reflect that:: - options: + Options: --dry-run do no harm [...] -n, --noisy be noisy @@ -1374,7 +1448,7 @@ At this point, the original ``-n``/``--dry-run`` option is no longer accessible, so :mod:`optparse` removes it, leaving this help text:: - options: + Options: [...] -n, --noisy be noisy --dry-run new dry-run option Modified: python/branches/py3k-cdecimal/Doc/library/pprint.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/pprint.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/pprint.rst Tue Jan 11 18:07:55 2011 @@ -6,6 +6,9 @@ .. moduleauthor:: Fred L. Drake, Jr. .. sectionauthor:: Fred L. Drake, Jr. +**Source code:** :source:`Lib/pprint.py` + +-------------- The :mod:`pprint` module provides a capability to "pretty-print" arbitrary Python data structures in a form which can be used as input to the interpreter. @@ -21,11 +24,6 @@ Dictionaries are sorted by key before the display is computed. -.. seealso:: - - Latest version of the :source:`pprint module Python source code - ` - The :mod:`pprint` module defines one class: .. First the implementation class: Modified: python/branches/py3k-cdecimal/Doc/library/pyexpat.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/pyexpat.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/pyexpat.rst Tue Jan 11 18:07:55 2011 @@ -153,6 +153,13 @@ :attr:`ordered_attributes` and :attr:`specified_attributes` set to the values of this parser. +.. method:: xmlparser.SetParamEntityParsing(flag) + + Control parsing of parameter entities (including the external DTD subset). + Possible *flag* values are :const:`XML_PARAM_ENTITY_PARSING_NEVER`, + :const:`XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE` and + :const:`XML_PARAM_ENTITY_PARSING_ALWAYS`. Return true if setting the flag + was successful. .. method:: xmlparser.UseForeignDTD([flag]) Modified: python/branches/py3k-cdecimal/Doc/library/queue.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/queue.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/queue.rst Tue Jan 11 18:07:55 2011 @@ -4,6 +4,9 @@ .. module:: queue :synopsis: A synchronized queue class. +**Source code:** :source:`Lib/queue.py` + +-------------- The :mod:`queue` module implements multi-producer, multi-consumer queues. It is especially useful in threaded programming when information must be @@ -19,10 +22,6 @@ the entries are kept sorted (using the :mod:`heapq` module) and the lowest valued entry is retrieved first. -.. seealso:: - - Latest version of the :source:`queue module Python source code - ` The :mod:`queue` module defines the following classes and exceptions: @@ -64,12 +63,6 @@ Exception raised when non-blocking :meth:`put` (or :meth:`put_nowait`) is called on a :class:`Queue` object which is full. -.. seealso:: - - :class:`collections.deque` is an alternative implementation of unbounded - queues with fast atomic :func:`append` and :func:`popleft` operations that - do not require locking. - .. _queueobjects: @@ -180,3 +173,14 @@ q.join() # block until all tasks are done + +.. seealso:: + + Class :class:`multiprocessing.Queue` + A queue class for use in a multi-processing (rather than multi-threading) + context. + + :class:`collections.deque` is an alternative implementation of unbounded + queues with fast atomic :func:`append` and :func:`popleft` operations that + do not require locking. + Modified: python/branches/py3k-cdecimal/Doc/library/quopri.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/quopri.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/quopri.rst Tue Jan 11 18:07:55 2011 @@ -9,6 +9,10 @@ pair: quoted-printable; encoding single: MIME; quoted-printable encoding +**Source code:** :source:`Lib/quopri.py` + +-------------- + This module performs quoted-printable transport encoding and decoding, as defined in :rfc:`1521`: "MIME (Multipurpose Internet Mail Extensions) Part One: Mechanisms for Specifying and Describing the Format of Internet Message Bodies". @@ -17,11 +21,6 @@ :mod:`base64` module is more compact if there are many such characters, as when sending a graphics file. -.. seealso:: - - Latest version of the :source:`quopri module Python source code - ` - .. function:: decode(input, output, header=False) Decode the contents of the *input* file and write the resulting decoded binary @@ -62,4 +61,3 @@ Module :mod:`base64` Encode and decode MIME base64 data - Modified: python/branches/py3k-cdecimal/Doc/library/random.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/random.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/random.rst Tue Jan 11 18:07:55 2011 @@ -4,15 +4,13 @@ .. module:: random :synopsis: Generate pseudo-random numbers with various common distributions. +**Source code:** :source:`Lib/random.py` + +-------------- This module implements pseudo-random number generators for various distributions. -.. seealso:: - - Latest version of the :source:`random module Python source code - ` - For integers, there is uniform selection from a range. For sequences, there is uniform selection of a random element, a function to generate a random permutation of a list in-place, and a function for random sampling without @@ -45,8 +43,8 @@ uses the system function :func:`os.urandom` to generate random numbers from sources provided by the operating system. -Bookkeeping functions: +Bookkeeping functions: .. function:: seed([x], version=2) Modified: python/branches/py3k-cdecimal/Doc/library/sched.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/sched.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/sched.rst Tue Jan 11 18:07:55 2011 @@ -7,13 +7,12 @@ .. index:: single: event scheduling -The :mod:`sched` module defines a class which implements a general purpose event -scheduler: +**Source code:** :source:`Lib/sched.py` -.. seealso:: +-------------- - Latest version of the :source:`sched module Python source code - ` +The :mod:`sched` module defines a class which implements a general purpose event +scheduler: .. class:: scheduler(timefunc, delayfunc) Modified: python/branches/py3k-cdecimal/Doc/library/shelve.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/shelve.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/shelve.rst Tue Jan 11 18:07:55 2011 @@ -7,16 +7,16 @@ .. index:: module: pickle +**Source code:** :source:`Lib/shelve.py` + +-------------- + A "shelf" is a persistent, dictionary-like object. The difference with "dbm" databases is that the values (not the keys!) in a shelf can be essentially arbitrary Python objects --- anything that the :mod:`pickle` module can handle. This includes most class instances, recursive data types, and objects containing lots of shared sub-objects. The keys are ordinary strings. -.. seealso:: - - Latest version of the :source:`shelve module Python source code - ` .. function:: open(filename, flag='c', protocol=None, writeback=False) Modified: python/branches/py3k-cdecimal/Doc/library/shutil.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/shutil.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/shutil.rst Tue Jan 11 18:07:55 2011 @@ -10,20 +10,19 @@ single: file; copying single: copying files +**Source code:** :source:`Lib/shutil.py` + +-------------- + The :mod:`shutil` module offers a number of high-level operations on files and collections of files. In particular, functions are provided which support file copying and removal. For operations on individual files, see also the :mod:`os` module. -.. seealso:: - - Latest version of the :source:`shutil module Python source code - ` - .. warning:: Even the higher-level file copying functions (:func:`copy`, :func:`copy2`) - can't copy all file metadata. + cannot copy all file metadata. On POSIX platforms, this means that file owner and group are lost as well as ACLs. On Mac OS, the resource fork and other metadata are not used. Modified: python/branches/py3k-cdecimal/Doc/library/socket.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/socket.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/socket.rst Tue Jan 11 18:07:55 2011 @@ -25,6 +25,15 @@ is implicit on send operations. +.. seealso:: + + Module :mod:`socketserver` + Classes that simplify writing network servers. + + Module :mod:`ssl` + A TLS/SSL wrapper for socket objects. + + Socket families --------------- @@ -139,8 +148,8 @@ .. exception:: timeout This exception is raised when a timeout occurs on a socket which has had - timeouts enabled via a prior call to :meth:`settimeout`. The accompanying value - is a string whose value is currently always "timed out". + timeouts enabled via a prior call to :meth:`~socket.settimeout`. The + accompanying value is a string whose value is currently always "timed out". .. data:: AF_UNIX @@ -506,9 +515,10 @@ .. function:: setdefaulttimeout(timeout) - Set the default timeout in floating seconds for new socket objects. A value of - ``None`` indicates that new socket objects have no timeout. When the socket - module is first imported, the default is ``None``. + Set the default timeout in floating seconds for new socket objects. When + the socket module is first imported, the default is ``None``. See + :meth:`~socket.settimeout` for possible values and their respective + meanings. .. data:: SocketType @@ -517,12 +527,6 @@ same as ``type(socket(...))``. -.. seealso:: - - Module :mod:`socketserver` - Classes that simplify writing network servers. - - .. _socket-objects: Socket Objects @@ -552,6 +556,12 @@ remote end will receive no more data (after queued data is flushed). Sockets are automatically closed when they are garbage-collected. + .. note:: + :meth:`close()` releases the resource associated with a connection but + does not necessarily close the connection immediately. If you want + to close the connection in a timely fashion, call :meth:`shutdown()` + before :meth:`close()`. + .. method:: socket.connect(address) @@ -615,6 +625,13 @@ to decode C structures encoded as byte strings). +.. method:: socket.gettimeout() + + Return the timeout in floating seconds associated with socket operations, + or ``None`` if no timeout is set. This reflects the last call to + :meth:`setblocking` or :meth:`settimeout`. + + .. method:: socket.ioctl(control, option) :platform: Windows @@ -644,8 +661,9 @@ interpreted the same way as by the built-in :func:`open` function. Closing the file object won't close the socket unless there are no remaining - references to the socket. The socket must be in blocking mode (it can not - have a timeout). + references to the socket. The socket must be in blocking mode; it can have + a timeout, but the file object's internal buffer may end up in a inconsistent + state if a timeout occurs. .. note:: @@ -725,55 +743,26 @@ .. method:: socket.setblocking(flag) - Set blocking or non-blocking mode of the socket: if *flag* is 0, the socket is - set to non-blocking, else to blocking mode. Initially all sockets are in - blocking mode. In non-blocking mode, if a :meth:`recv` call doesn't find any - data, or if a :meth:`send` call can't immediately dispose of the data, a - :exc:`error` exception is raised; in blocking mode, the calls block until they - can proceed. ``s.setblocking(0)`` is equivalent to ``s.settimeout(0.0)``; - ``s.setblocking(1)`` is equivalent to ``s.settimeout(None)``. - + Set blocking or non-blocking mode of the socket: if *flag* is false, the + socket is set to non-blocking, else to blocking mode. -.. method:: socket.settimeout(value) - - Set a timeout on blocking socket operations. The *value* argument can be a - nonnegative float expressing seconds, or ``None``. If a float is given, - subsequent socket operations will raise a :exc:`timeout` exception if the - timeout period *value* has elapsed before the operation has completed. Setting - a timeout of ``None`` disables timeouts on socket operations. - ``s.settimeout(0.0)`` is equivalent to ``s.setblocking(0)``; - ``s.settimeout(None)`` is equivalent to ``s.setblocking(1)``. + This method is a shorthand for certain :meth:`~socket.settimeout` calls: + * ``sock.setblocking(True)`` is equivalent to ``sock.settimeout(None)`` -.. method:: socket.gettimeout() + * ``sock.setblocking(False)`` is equivalent to ``sock.settimeout(0.0)`` - Return the timeout in floating seconds associated with socket operations, or - ``None`` if no timeout is set. This reflects the last call to - :meth:`setblocking` or :meth:`settimeout`. +.. method:: socket.settimeout(value) -Some notes on socket blocking and timeouts: A socket object can be in one of -three modes: blocking, non-blocking, or timeout. Sockets are always created in -blocking mode. In blocking mode, operations block until complete or -the system returns an error (such as connection timed out). In -non-blocking mode, operations fail (with an error that is unfortunately -system-dependent) if they cannot be completed immediately. In timeout mode, -operations fail if they cannot be completed within the timeout specified for the -socket or if the system returns an error. The :meth:`~socket.setblocking` -method is simply a shorthand for certain :meth:`~socket.settimeout` calls. - -Timeout mode internally sets the socket in non-blocking mode. The blocking and -timeout modes are shared between file descriptors and socket objects that refer -to the same network endpoint. A consequence of this is that file objects -returned by the :meth:`~socket.makefile` method must only be used when the -socket is in blocking mode; in timeout or non-blocking mode file operations -that cannot be completed immediately will fail. + Set a timeout on blocking socket operations. The *value* argument can be a + nonnegative floating point number expressing seconds, or ``None``. + If a non-zero value is given, subsequent socket operations will raise a + :exc:`timeout` exception if the timeout period *value* has elapsed before + the operation has completed. If zero is given, the socket is put in + non-blocking mode. If ``None`` is given, the socket is put in blocking mode. -Note that the :meth:`~socket.connect` operation is subject to the timeout -setting, and in general it is recommended to call :meth:`~socket.settimeout` -before calling :meth:`~socket.connect` or pass a timeout parameter to -:meth:`create_connection`. The system network stack may return a connection -timeout error of its own regardless of any Python socket timeout setting. + For further information, please consult the :ref:`notes on socket timeouts `. .. method:: socket.setsockopt(level, optname, value) @@ -819,6 +808,61 @@ The socket protocol. + +.. _socket-timeouts: + +Notes on socket timeouts +------------------------ + +A socket object can be in one of three modes: blocking, non-blocking, or +timeout. Sockets are by default always created in blocking mode, but this +can be changed by calling :func:`setdefaulttimeout`. + +* In *blocking mode*, operations block until complete or the system returns + an error (such as connection timed out). + +* In *non-blocking mode*, operations fail (with an error that is unfortunately + system-dependent) if they cannot be completed immediately: functions from the + :mod:`select` can be used to know when and whether a socket is available for + reading or writing. + +* In *timeout mode*, operations fail if they cannot be completed within the + timeout specified for the socket (they raise a :exc:`timeout` exception) + or if the system returns an error. + +.. note:: + At the operating system level, sockets in *timeout mode* are internally set + in non-blocking mode. Also, the blocking and timeout modes are shared between + file descriptors and socket objects that refer to the same network endpoint. + This implementation detail can have visible consequences if e.g. you decide + to use the :meth:`~socket.fileno()` of a socket. + +Timeouts and the ``connect`` method +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :meth:`~socket.connect` operation is also subject to the timeout +setting, and in general it is recommended to call :meth:`~socket.settimeout` +before calling :meth:`~socket.connect` or pass a timeout parameter to +:meth:`create_connection`. However, the system network stack may also +return a connection timeout error of its own regardless of any Python socket +timeout setting. + +Timeouts and the ``accept`` method +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If :func:`getdefaulttimeout` is not :const:`None`, sockets returned by +the :meth:`~socket.accept` method inherit that timeout. Otherwise, the +behaviour depends on settings of the listening socket: + +* if the listening socket is in *blocking mode* or in *timeout mode*, + the socket returned by :meth:`~socket.accept` is in *blocking mode*; + +* if the listening socket is in *non-blocking mode*, whether the socket + returned by :meth:`~socket.accept` is in blocking or non-blocking mode + is operating system-dependent. If you want to ensure cross-platform + behaviour, it is recommended you manually override this setting. + + .. _socket-example: Example Modified: python/branches/py3k-cdecimal/Doc/library/ssl.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/ssl.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/ssl.rst Tue Jan 11 18:07:55 2011 @@ -1,8 +1,8 @@ -:mod:`ssl` --- SSL wrapper for socket objects -============================================= +:mod:`ssl` --- TLS/SSL wrapper for socket objects +================================================= .. module:: ssl - :synopsis: SSL wrapper for socket objects + :synopsis: TLS/SSL wrapper for socket objects .. moduleauthor:: Bill Janssen .. sectionauthor:: Bill Janssen @@ -768,11 +768,11 @@ should use the following idiom:: try: - import ssl + import ssl except ImportError: - pass + pass else: - [ do something that requires SSL support ] + ... # do something that requires SSL support Client-side operation ^^^^^^^^^^^^^^^^^^^^^ @@ -883,26 +883,27 @@ method to create a server-side SSL socket for the connection:: while True: - newsocket, fromaddr = bindsocket.accept() - connstream = context.wrap_socket(newsocket, server_side=True) - try: - deal_with_client(connstream) - finally: - connstream.close() + newsocket, fromaddr = bindsocket.accept() + connstream = context.wrap_socket(newsocket, server_side=True) + try: + deal_with_client(connstream) + finally: + connstream.shutdown(socket.SHUT_RDWR) + connstream.close() Then you'll read data from the ``connstream`` and do something with it till you are finished with the client (or the client is finished with you):: def deal_with_client(connstream): - data = connstream.recv(1024) - # empty data means the client is finished with us - while data: - if not do_something(connstream, data): - # we'll assume do_something returns False - # when we're finished with client - break - data = connstream.recv(1024) - # finished with client + data = connstream.recv(1024) + # empty data means the client is finished with us + while data: + if not do_something(connstream, data): + # we'll assume do_something returns False + # when we're finished with client + break + data = connstream.recv(1024) + # finished with client And go back to listening for new client connections (of course, a real server would probably handle each client connection in a separate thread, or put Modified: python/branches/py3k-cdecimal/Doc/library/stdtypes.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/stdtypes.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/stdtypes.rst Tue Jan 11 18:07:55 2011 @@ -2117,8 +2117,20 @@ returned or raised by the ``__missing__(key)`` call if the key is not present. No other operations or methods invoke :meth:`__missing__`. If :meth:`__missing__` is not defined, :exc:`KeyError` is raised. - :meth:`__missing__` must be a method; it cannot be an instance variable. For - an example, see :class:`collections.defaultdict`. + :meth:`__missing__` must be a method; it cannot be an instance variable:: + + >>> class Counter(dict): + ... def __missing__(self, key): + ... return 0 + >>> c = Counter() + >>> c['red'] + 0 + >>> c['red'] += 1 + >>> c['red'] + 1 + + See :class:`collections.Counter` for a complete implementation including + other methods helpful for accumulating and managing tallies. .. describe:: d[key] = value Modified: python/branches/py3k-cdecimal/Doc/library/string.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/string.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/string.rst Tue Jan 11 18:07:55 2011 @@ -5,21 +5,15 @@ :synopsis: Common string operations. -.. index:: module: re +.. seealso:: -The :mod:`string` module contains a number of useful constants and classes -for string formatting. In addition, Python's built-in string classes -support the sequence type methods described in the :ref:`typesseq` -section, and also the string-specific methods described in the -:ref:`string-methods` section. To output formatted strings, see the -:ref:`string-formatting` section. Also, see the :mod:`re` module for -string functions based on regular expressions. + :ref:`typesseq` -.. seealso:: + :ref:`string-methods` - Latest version of the :source:`string module Python source code - ` +**Source code:** :source:`Lib/string.py` +-------------- String constants ---------------- Modified: python/branches/py3k-cdecimal/Doc/library/textwrap.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/textwrap.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/textwrap.rst Tue Jan 11 18:07:55 2011 @@ -6,6 +6,9 @@ .. moduleauthor:: Greg Ward .. sectionauthor:: Greg Ward +**Source code:** :source:`Lib/textwrap.py` + +-------------- The :mod:`textwrap` module provides two convenience functions, :func:`wrap` and :func:`fill`, as well as :class:`TextWrapper`, the class that does all the work, @@ -13,11 +16,6 @@ or two text strings, the convenience functions should be good enough; otherwise, you should use an instance of :class:`TextWrapper` for efficiency. -.. seealso:: - - Latest version of the :source:`textwrap module Python source code - ` - .. function:: wrap(text, width=70, **kwargs) Wraps the single paragraph in *text* (a string) so every line is at most Modified: python/branches/py3k-cdecimal/Doc/library/threading.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/threading.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/threading.rst Tue Jan 11 18:07:55 2011 @@ -4,6 +4,9 @@ .. module:: threading :synopsis: Thread-based parallelism. +**Source code:** :source:`Lib/threading.py` + +-------------- This module constructs higher-level threading interfaces on top of the lower level :mod:`_thread` module. See also the :mod:`queue` module. @@ -17,10 +20,17 @@ methods and functions in this module in the Python 2.x series are still supported by this module. -.. seealso:: +.. impl-detail:: + + Due to the :term:`Global Interpreter Lock`, in CPython only one thread + can execute Python code at once (even though certain performance-oriented + libraries might overcome this limitation). + If you want your application to make better of use of the computational + resources of multi-core machines, you are advised to use + :mod:`multiprocessing` or :class:`concurrent.futures.ProcessPoolExecutor`. + However, threading is still an appropriate model if you want to run + multiple I/O-bound tasks simultaneously. - Latest version of the :source:`threading module Python source code - ` This module defines the following functions and objects: @@ -707,9 +717,9 @@ ^^^^^^^^^^^^^^^^^^^^^^^^^^ Semaphores are often used to guard resources with limited capacity, for example, -a database server. In any situation where the size of the resource size is -fixed, you should use a bounded semaphore. Before spawning any worker threads, -your main thread would initialize the semaphore:: +a database server. In any situation where the size of the resource is fixed, +you should use a bounded semaphore. Before spawning any worker threads, your +main thread would initialize the semaphore:: maxconnections = 5 ... Modified: python/branches/py3k-cdecimal/Doc/library/time.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/time.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/time.rst Tue Jan 11 18:07:55 2011 @@ -24,9 +24,9 @@ .. index:: single: Year 2038 -* The functions in this module do not handle dates and times before the epoch or +* The functions in this module may not handle dates and times before the epoch or far in the future. The cut-off point in the future is determined by the C - library; for Unix, it is typically in 2038. + library; for 32-bit systems, it is typically in 2038. .. index:: single: Year 2000 @@ -34,20 +34,31 @@ .. _time-y2kissues: -* **Year 2000 (Y2K) issues**: Python depends on the platform's C library, which +* **Year 2000 (Y2K) issues**: Python depends on the platform's C library, which generally doesn't have year 2000 issues, since all dates and times are - represented internally as seconds since the epoch. Functions accepting a - :class:`struct_time` (see below) generally require a 4-digit year. For backward - compatibility, 2-digit years are supported if the module variable - ``accept2dyear`` is a non-zero integer; this variable is initialized to ``1`` - unless the environment variable :envvar:`PYTHONY2K` is set to a non-empty - string, in which case it is initialized to ``0``. Thus, you can set - :envvar:`PYTHONY2K` to a non-empty string in the environment to require 4-digit - years for all year input. When 2-digit years are accepted, they are converted - according to the POSIX or X/Open standard: values 69-99 are mapped to 1969-1999, - and values 0--68 are mapped to 2000--2068. Values 100--1899 are always illegal. - Note that this is new as of Python 1.5.2(a2); earlier versions, up to Python - 1.5.1 and 1.5.2a1, would add 1900 to year values below 1900. + represented internally as seconds since the epoch. Function :func:`strptime` + can parse 2-digit years when given ``%y`` format code. When 2-digit years are + parsed, they are converted according to the POSIX and ISO C standards: values + 69--99 are mapped to 1969--1999, and values 0--68 are mapped to 2000--2068. + + For backward compatibility, years with less than 4 digits are treated + specially by :func:`asctime`, :func:`mktime`, and :func:`strftime` functions + that operate on a 9-tuple or :class:`struct_time` values. If year (the first + value in the 9-tuple) is specified with less than 4 digits, its interpretation + depends on the value of ``accept2dyear`` variable. + + If ``accept2dyear`` is true (default), a backward compatibility behavior is + invoked as follows: + + - for 2-digit year, century is guessed according to POSIX rules for + ``%y`` strptime format. A deprecation warning is issued when century + information is guessed in this way. + + - for 3-digit or negative year, a :exc:`ValueError` exception is raised. + + If ``accept2dyear`` is false (set by the program or as a result of a + non-empty value assigned to ``PYTHONY2K`` environment variable) all year + values are interpreted as given. .. index:: single: UTC @@ -109,10 +120,19 @@ .. data:: accept2dyear - Boolean value indicating whether two-digit year values will be accepted. This - is true by default, but will be set to false if the environment variable - :envvar:`PYTHONY2K` has been set to a non-empty string. It may also be modified - at run time. + Boolean value indicating whether two-digit year values will be + mapped to 1969--2068 range by :func:`asctime`, :func:`mktime`, and + :func:`strftime` functions. This is true by default, but will be + set to false if the environment variable :envvar:`PYTHONY2K` has + been set to a non-empty string. It may also be modified at run + time. + + .. deprecated:: 3.2 + Mapping of 2-digit year values by :func:`asctime`, + :func:`mktime`, and :func:`strftime` functions to 1969--2068 + range is deprecated. Programs that need to process 2-digit + years should use ``%y`` code available in :func:`strptime` + function or convert 2-digit year values to 4-digit themselves. .. data:: altzone @@ -125,7 +145,7 @@ .. function:: asctime([t]) Convert a tuple or :class:`struct_time` representing a time as returned by - :func:`gmtime` or :func:`localtime` to a 24-character string of the following + :func:`gmtime` or :func:`localtime` to a string of the following form: ``'Sun Jun 20 23:21:05 1993'``. If *t* is not provided, the current time as returned by :func:`localtime` is used. Locale information is not used by :func:`asctime`. @@ -288,7 +308,7 @@ | ``%y`` | Year without century as a decimal number | | | | [00,99]. | | +-----------+------------------------------------------------+-------+ - | ``%Y`` | Year with century as a decimal number. | | + | ``%Y`` | Year with century as a decimal number. | \(4) | | | | | +-----------+------------------------------------------------+-------+ | ``%Z`` | Time zone name (no characters if no time zone | | @@ -304,13 +324,20 @@ the output hour field if the ``%I`` directive is used to parse the hour. (2) - The range really is ``0`` to ``61``; this accounts for leap seconds and the - (very rare) double leap seconds. + The range really is ``0`` to ``61``; value ``60`` is valid in + timestamps representing leap seconds and value ``61`` is supported + for historical reasons. (3) When used with the :func:`strptime` function, ``%U`` and ``%W`` are only used in calculations when the day of the week and the year are specified. + (4) + Produces different results depending on the value of + ``time.accept2dyear`` variable. See :ref:`Year 2000 (Y2K) + issues ` for details. + + Here is an example, a format for dates compatible with that specified in the :rfc:`2822` Internet email standard. [#]_ :: @@ -380,7 +407,7 @@ +-------+-------------------+---------------------------------+ | 4 | :attr:`tm_min` | range [0, 59] | +-------+-------------------+---------------------------------+ - | 5 | :attr:`tm_sec` | range [0, 61]; see **(1)** in | + | 5 | :attr:`tm_sec` | range [0, 61]; see **(2)** in | | | | :func:`strftime` description | +-------+-------------------+---------------------------------+ | 6 | :attr:`tm_wday` | range [0, 6], Monday is 0 | Modified: python/branches/py3k-cdecimal/Doc/library/tokenize.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/tokenize.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/tokenize.rst Tue Jan 11 18:07:55 2011 @@ -6,17 +6,15 @@ .. moduleauthor:: Ka Ping Yee .. sectionauthor:: Fred L. Drake, Jr. +**Source code:** :source:`Lib/tokenize.py` + +-------------- The :mod:`tokenize` module provides a lexical scanner for Python source code, implemented in Python. The scanner in this module returns comments as tokens as well, making it useful for implementing "pretty-printers," including colorizers for on-screen displays. -.. seealso:: - - Latest version of the :source:`tokenize module Python source code - ` - The primary entry point is a :term:`generator`: .. function:: tokenize(readline) Modified: python/branches/py3k-cdecimal/Doc/library/trace.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/trace.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/trace.rst Tue Jan 11 18:07:55 2011 @@ -4,17 +4,15 @@ .. module:: trace :synopsis: Trace or track Python statement execution. +**Source code:** :source:`Lib/trace.py` + +-------------- The :mod:`trace` module allows you to trace program execution, generate annotated statement coverage listings, print caller/callee relationships and list functions executed during a program run. It can be used in another program or from the command line. -.. seealso:: - - Latest version of the :source:`trace module Python source code - ` - .. _trace-cli: Command-Line Usage Modified: python/branches/py3k-cdecimal/Doc/library/unittest.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/unittest.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/unittest.rst Tue Jan 11 18:07:55 2011 @@ -97,6 +97,13 @@ A special-interest-group for discussion of testing, and testing tools, in Python. + The script :file:`Tools/unittestgui/unittestgui.py` in the Python source distribution is + a GUI tool for test discovery and execution. This is intended largely for ease of use + for those new to unit testing. For production environments it is recommended that + tests be driven by a continuous integration system such as `Hudson `_ + or `Buildbot `_. + + .. _unittest-minimal-example: Basic example @@ -714,6 +721,11 @@ Here, we create two instances of :class:`WidgetTestCase`, each of which runs a single test. + .. versionchanged:: + `TestCase` can be instantiated successfully without providing a method + name. This makes it easier to experiment with `TestCase` from the + interactive interpreter. + *methodName* defaults to :meth:`runTest`. :class:`TestCase` instances provide three groups of methods: one group used @@ -1870,9 +1882,10 @@ instead of repeatedly creating new instances. -.. class:: TextTestRunner(stream=sys.stderr, descriptions=True, verbosity=1, runnerclass=None, warnings=None) +.. class:: TextTestRunner(stream=None, descriptions=True, verbosity=1, runnerclass=None, warnings=None) - A basic test runner implementation which prints results on standard error. It + A basic test runner implementation that outputs results to a stream. If *stream* + is `None`, the default, `sys.stderr` is used as the output stream. This class has a few configurable parameters, but is essentially very simple. Graphical applications which run test suites should provide alternate implementations. @@ -1885,6 +1898,13 @@ messages. This behavior can be overridden using the :option:`-Wd` or :option:`-Wa` options and leaving *warnings* to ``None``. + .. versionchanged:: 3.2 + Added the ``warnings`` argument. + + .. versionchanged:: 3.2 + The default stream is set to `sys.stderr` at instantiation time rather + than import time. + .. method:: _makeResult() This method returns the instance of ``TestResult`` used by :meth:`run`. @@ -1898,8 +1918,6 @@ stream, descriptions, verbosity - .. versionchanged:: 3.2 - Added the ``warnings`` argument. .. function:: main(module='__main__', defaultTest=None, argv=None, testRunner=None, \ testLoader=unittest.loader.defaultTestLoader, exit=True, verbosity=1, \ Modified: python/branches/py3k-cdecimal/Doc/library/uu.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/uu.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/uu.rst Tue Jan 11 18:07:55 2011 @@ -5,6 +5,9 @@ :synopsis: Encode and decode files in uuencode format. .. moduleauthor:: Lance Ellinghouse +**Source code:** :source:`Lib/uu.py` + +-------------- This module encodes and decodes files in uuencode format, allowing arbitrary binary data to be transferred over ASCII-only connections. Wherever a file @@ -21,10 +24,6 @@ This code was contributed by Lance Ellinghouse, and modified by Jack Jansen. -.. seealso:: - - Latest version of the :source:`uu module Python source code ` - The :mod:`uu` module defines the following functions: @@ -60,4 +59,3 @@ Module :mod:`binascii` Support module containing ASCII-to-binary and binary-to-ASCII conversions. - Modified: python/branches/py3k-cdecimal/Doc/library/wave.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/wave.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/wave.rst Tue Jan 11 18:07:55 2011 @@ -14,8 +14,8 @@ .. function:: open(file, mode=None) - If *file* is a string, open the file by that name, other treat it as a seekable - file-like object. *mode* can be any of + If *file* is a string, open the file by that name, otherwise treat it as a + seekable file-like object. *mode* can be any of ``'r'``, ``'rb'`` Read only mode. @@ -26,9 +26,14 @@ Note that it does not allow read/write WAV files. A *mode* of ``'r'`` or ``'rb'`` returns a :class:`Wave_read` object, while a - *mode* of ``'w'`` or ``'wb'`` returns a :class:`Wave_write` object. If *mode* - is omitted and a file-like object is passed as *file*, ``file.mode`` is used as - the default value for *mode* (the ``'b'`` flag is still added if necessary). + *mode* of ``'w'`` or ``'wb'`` returns a :class:`Wave_write` object. If + *mode* is omitted and a file-like object is passed as *file*, ``file.mode`` + is used as the default value for *mode* (the ``'b'`` flag is still added if + necessary). + + If you pass in a file-like object, the wave object will not close it when its + :meth:`close` method is called; it is the caller's responsibility to close + the file object. .. function:: openfp(file, mode) @@ -52,8 +57,8 @@ .. method:: Wave_read.close() - Close the stream, and make the instance unusable. This is called automatically - on object collection. + Close the stream if it was opened by :mod:`wave`, and make the instance + unusable. This is called automatically on object collection. .. method:: Wave_read.getnchannels() @@ -139,8 +144,8 @@ .. method:: Wave_write.close() - Make sure *nframes* is correct, and close the file. This method is called upon - deletion. + Make sure *nframes* is correct, and close the file if it was opened by + :mod:`wave`. This method is called upon object collection. .. method:: Wave_write.setnchannels(n) @@ -196,6 +201,7 @@ Write audio frames and make sure *nframes* is correct. + Note that it is invalid to set any parameters after calling :meth:`writeframes` or :meth:`writeframesraw`, and any attempt to do so will raise :exc:`wave.Error`. Modified: python/branches/py3k-cdecimal/Doc/library/zlib.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/library/zlib.rst (original) +++ python/branches/py3k-cdecimal/Doc/library/zlib.rst Tue Jan 11 18:07:55 2011 @@ -51,9 +51,9 @@ regardless of sign. -.. function:: compress(string[, level]) +.. function:: compress(data[, level]) - Compresses the data in *string*, returning a string contained compressed data. + Compresses the bytes in *data*, returning a bytes object containing compressed data. *level* is an integer from ``1`` to ``9`` controlling the level of compression; ``1`` is fastest and produces the least compression, ``9`` is slowest and produces the most. The default value is ``6``. Raises the :exc:`error` @@ -92,9 +92,9 @@ regardless of sign. -.. function:: decompress(string[, wbits[, bufsize]]) +.. function:: decompress(data[, wbits[, bufsize]]) - Decompresses the data in *string*, returning a string containing the + Decompresses the bytes in *data*, returning a bytes object containing the uncompressed data. The *wbits* parameter controls the size of the window buffer, and is discussed further below. If *bufsize* is given, it is used as the initial size of the output @@ -125,21 +125,21 @@ Compression objects support the following methods: -.. method:: Compress.compress(string) +.. method:: Compress.compress(data) - Compress *string*, returning a string containing compressed data for at least - part of the data in *string*. This data should be concatenated to the output + Compress *data*, returning a bytes object containing compressed data for at least + part of the data in *data*. This data should be concatenated to the output produced by any preceding calls to the :meth:`compress` method. Some input may be kept in internal buffers for later processing. .. method:: Compress.flush([mode]) - All pending input is processed, and a string containing the remaining compressed + All pending input is processed, and a bytes object containing the remaining compressed output is returned. *mode* can be selected from the constants :const:`Z_SYNC_FLUSH`, :const:`Z_FULL_FLUSH`, or :const:`Z_FINISH`, defaulting to :const:`Z_FINISH`. :const:`Z_SYNC_FLUSH` and - :const:`Z_FULL_FLUSH` allow compressing further strings of data, while + :const:`Z_FULL_FLUSH` allow compressing further bytestrings of data, while :const:`Z_FINISH` finishes the compressed stream and prevents compressing any more data. After calling :meth:`flush` with *mode* set to :const:`Z_FINISH`, the :meth:`compress` method cannot be called again; the only realistic action is @@ -157,31 +157,31 @@ .. attribute:: Decompress.unused_data - A string which contains any bytes past the end of the compressed data. That is, + A bytes object which contains any bytes past the end of the compressed data. That is, this remains ``""`` until the last byte that contains compression data is - available. If the whole string turned out to contain compressed data, this is - ``""``, the empty string. + available. If the whole bytestring turned out to contain compressed data, this is + ``b""``, an empty bytes object. - The only way to determine where a string of compressed data ends is by actually + The only way to determine where a bytestring of compressed data ends is by actually decompressing it. This means that when compressed data is contained part of a larger file, you can only find the end of it by reading data and feeding it - followed by some non-empty string into a decompression object's + followed by some non-empty bytestring into a decompression object's :meth:`decompress` method until the :attr:`unused_data` attribute is no longer - the empty string. + empty. .. attribute:: Decompress.unconsumed_tail - A string that contains any data that was not consumed by the last + A bytes object that contains any data that was not consumed by the last :meth:`decompress` call because it exceeded the limit for the uncompressed data buffer. This data has not yet been seen by the zlib machinery, so you must feed it (possibly with further data concatenated to it) back to a subsequent :meth:`decompress` method call in order to get correct output. -.. method:: Decompress.decompress(string[, max_length]) +.. method:: Decompress.decompress(data[, max_length]) - Decompress *string*, returning a string containing the uncompressed data + Decompress *data*, returning a bytes object containing the uncompressed data corresponding to at least part of the data in *string*. This data should be concatenated to the output produced by any preceding calls to the :meth:`decompress` method. Some of the input data may be preserved in internal @@ -190,15 +190,15 @@ If the optional parameter *max_length* is supplied then the return value will be no longer than *max_length*. This may mean that not all of the compressed input can be processed; and unconsumed data will be stored in the attribute - :attr:`unconsumed_tail`. This string must be passed to a subsequent call to + :attr:`unconsumed_tail`. This bytestring must be passed to a subsequent call to :meth:`decompress` if decompression is to continue. If *max_length* is not - supplied then the whole input is decompressed, and :attr:`unconsumed_tail` is an - empty string. + supplied then the whole input is decompressed, and :attr:`unconsumed_tail` is + empty. .. method:: Decompress.flush([length]) - All pending input is processed, and a string containing the remaining + All pending input is processed, and a bytes object containing the remaining uncompressed output is returned. After calling :meth:`flush`, the :meth:`decompress` method cannot be called again; the only realistic action is to delete the object. Modified: python/branches/py3k-cdecimal/Doc/reference/compound_stmts.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/reference/compound_stmts.rst (original) +++ python/branches/py3k-cdecimal/Doc/reference/compound_stmts.rst Tue Jan 11 18:07:55 2011 @@ -285,12 +285,11 @@ Before an except clause's suite is executed, details about the exception are stored in the :mod:`sys` module and can be access via :func:`sys.exc_info`. -:func:`sys.exc_info` returns a 3-tuple consisting of: ``exc_type``, the -exception class; ``exc_value``, the exception instance; ``exc_traceback``, a -traceback object (see section :ref:`types`) identifying the point in the program -where the exception occurred. :func:`sys.exc_info` values are restored to their -previous values (before the call) when returning from a function that handled an -exception. +:func:`sys.exc_info` returns a 3-tuple consisting of the exception class, the +exception instance and a traceback object (see section :ref:`types`) identifying +the point in the program where the exception occurred. :func:`sys.exc_info` +values are restored to their previous values (before the call) when returning +from a function that handled an exception. .. index:: keyword: else Modified: python/branches/py3k-cdecimal/Doc/reference/executionmodel.rst ============================================================================== --- python/branches/py3k-cdecimal/Doc/reference/executionmodel.rst (original) +++ python/branches/py3k-cdecimal/Doc/reference/executionmodel.rst Tue Jan 11 18:07:55 2011 @@ -141,9 +141,9 @@ The namespace for a module is automatically created the first time a module is imported. The main module for a script is always called :mod:`__main__`. -The global statement has the same scope as a name binding operation in the same -block. If the nearest enclosing scope for a free variable contains a global -statement, the free variable is treated as a global. +The :keyword:`global` statement has the same scope as a name binding operation +in the same block. If the nearest enclosing scope for a free variable contains +a global statement, the free variable is treated as a global. A class definition is an executable statement that may use and define names. These references follow the normal rules for name resolution. The namespace of Modified: python/branches/py3k-cdecimal/Doc/tools/sphinxext/download.html ============================================================================== --- python/branches/py3k-cdecimal/Doc/tools/sphinxext/download.html (original) +++ python/branches/py3k-cdecimal/Doc/tools/sphinxext/download.html Tue Jan 11 18:07:55 2011 @@ -33,6 +33,10 @@
Download (ca. 2 MB) Download (ca. 1.5 MB) + EPUB + Download (ca. 3.5 MB) + Download (ca. 3.5 MB) + Modified: python/branches/py3k-cdecimal/Doc/tools/sphinxext/indexcontent.html ============================================================================== --- python/branches/py3k-cdecimal/Doc/tools/sphinxext/indexcontent.html (original) +++ python/branches/py3k-cdecimal/Doc/tools/sphinxext/indexcontent.html Tue Jan 11 18:07:55 2011 @@ -4,7 +4,7 @@
+ or all "What's new" documents since 2.0

[^]]+?) *\]") + >>> custom.read_string(config) + >>> custom.sections() + ['Section 1', 'Section 2'] + + .. note:: + + While ConfigParser objects also use an ``OPTCRE`` attribute for recognizing + option lines, it's not recommended to override it because that would + interfere with constructor options *allow_no_value* and *delimiters*. + Legacy API Examples ------------------- From python-checkins at python.org Fri Jan 28 16:31:11 2011 From: python-checkins at python.org (tarek.ziade) Date: Fri, 28 Jan 2011 16:31:11 +0100 Subject: [Python-checkins] distutils2: fixed #11038. Add strict parameter to metadata.check() and use the strict mode Message-ID: tarek.ziade pushed da2f3527ef02 to distutils2: http://hg.python.org/distutils2/rev/da2f3527ef02 changeset: 897:da2f3527ef02 user: Gael Pasgrimaud date: Fri Jan 28 12:37:44 2011 +0100 summary: fixed #11038. Add strict parameter to metadata.check() and use the strict mode in check command files: distutils2/command/check.py distutils2/errors.py distutils2/metadata.py distutils2/tests/test_command_check.py distutils2/tests/test_command_sdist.py diff --git a/distutils2/command/check.py b/distutils2/command/check.py --- a/distutils2/command/check.py +++ b/distutils2/command/check.py @@ -57,7 +57,7 @@ Warns if any are missing. """ - missing, __ = self.distribution.metadata.check() + missing, __ = self.distribution.metadata.check(strict=True) if missing != []: self.warn("missing required metadata: %s" % ', '.join(missing)) diff --git a/distutils2/errors.py b/distutils2/errors.py --- a/distutils2/errors.py +++ b/distutils2/errors.py @@ -110,6 +110,10 @@ """Attempt to process an unknown file type.""" +class MetadataMissingError(DistutilsError): + """A required metadata is missing""" + + class MetadataConflictError(DistutilsError): """Attempt to read or write metadata fields that are conflictual.""" diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -14,7 +14,8 @@ from distutils2 import logger from distutils2.version import (is_valid_predicate, is_valid_version, is_valid_versions) -from distutils2.errors import (MetadataConflictError, +from distutils2.errors import (MetadataMissingError, + MetadataConflictError, MetadataUnrecognizedVersionError) try: @@ -82,6 +83,7 @@ _ALL_FIELDS.update(_314_FIELDS) _ALL_FIELDS.update(_345_FIELDS) +_345_REQUIRED = ('Name', 'Version') def _version2fieldlist(version): if version == '1.0': @@ -451,11 +453,20 @@ return None return value - def check(self): + def check(self, strict=False): """Check if the metadata is compliant.""" # XXX should check the versions (if the file was loaded) missing, warnings = [], [] - for attr in ('Name', 'Version', 'Home-page'): + + for attr in ('Name', 'Version'): + if attr not in self: + missing.append(attr) + + if strict and missing != []: + msg = "missing required metadata: %s" % ', '.join(missing) + raise MetadataMissingError(msg) + + for attr in ('Home-page',): if attr not in self: missing.append(attr) diff --git a/distutils2/tests/test_command_check.py b/distutils2/tests/test_command_check.py --- a/distutils2/tests/test_command_check.py +++ b/distutils2/tests/test_command_check.py @@ -4,6 +4,7 @@ from distutils2.metadata import _HAS_DOCUTILS from distutils2.tests import unittest, support from distutils2.errors import DistutilsSetupError +from distutils2.errors import MetadataMissingError class CheckTestCase(support.LoggingCatcher, support.TempdirManager, @@ -11,7 +12,7 @@ def _run(self, metadata=None, **options): if metadata is None: - metadata = {} + metadata = {'name':'xxx', 'version':'xxx'} pkg_info, dist = self.create_dist(**metadata) cmd = check(dist) cmd.initialize_options() @@ -40,7 +41,8 @@ # now with the strict mode, we should # get an error if there are missing metadata - self.assertRaises(DistutilsSetupError, self._run, {}, **{'strict': 1}) + self.assertRaises(MetadataMissingError, self._run, {}, **{'strict': 1}) + self.assertRaises(DistutilsSetupError, self._run, {'name':'xxx', 'version':'xxx'}, **{'strict': 1}) # and of course, no error when all metadata fields are present cmd = self._run(metadata, strict=1) @@ -63,6 +65,9 @@ def test_check_all(self): self.assertRaises(DistutilsSetupError, self._run, + {'name':'xxx', 'version':'xxx'}, **{'strict': 1, + 'all': 1}) + self.assertRaises(MetadataMissingError, self._run, {}, **{'strict': 1, 'all': 1}) diff --git a/distutils2/tests/test_command_sdist.py b/distutils2/tests/test_command_sdist.py --- a/distutils2/tests/test_command_sdist.py +++ b/distutils2/tests/test_command_sdist.py @@ -245,7 +245,7 @@ @unittest.skipUnless(zlib, "requires zlib") def test_metadata_check_option(self): # testing the `check-metadata` option - dist, cmd = self.get_cmd(metadata={}) + dist, cmd = self.get_cmd(metadata={'name':'xxx', 'version':'xxx'}) # this should raise some warnings ! # with the `check` subcommand -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Fri Jan 28 16:31:12 2011 From: python-checkins at python.org (tarek.ziade) Date: Fri, 28 Jan 2011 16:31:12 +0100 Subject: [Python-checkins] distutils2: Fix a test following last Gael's commit. Message-ID: tarek.ziade pushed 06870bf6581a to distutils2: http://hg.python.org/distutils2/rev/06870bf6581a changeset: 898:06870bf6581a user: Alexis Metaireau date: Fri Jan 28 12:58:06 2011 +0100 summary: Fix a test following last Gael's commit. files: distutils2/tests/test_command_register.py diff --git a/distutils2/tests/test_command_register.py b/distutils2/tests/test_command_register.py --- a/distutils2/tests/test_command_register.py +++ b/distutils2/tests/test_command_register.py @@ -195,7 +195,7 @@ # long_description is not reSt compliant # empty metadata - cmd = self._get_cmd({}) + cmd = self._get_cmd({'name': 'xxx', 'version': 'xxx'}) cmd.ensure_finalized() cmd.strict = 1 inputs = RawInputs('1', 'tarek', 'y') -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Fri Jan 28 16:31:12 2011 From: python-checkins at python.org (tarek.ziade) Date: Fri, 28 Jan 2011 16:31:12 +0100 Subject: [Python-checkins] distutils2: try to use setuptools Message-ID: tarek.ziade pushed 93c02eaba941 to distutils2: http://hg.python.org/distutils2/rev/93c02eaba941 changeset: 899:93c02eaba941 tag: tip user: Gael Pasgrimaud date: Fri Jan 28 13:07:12 2011 +0100 summary: try to use setuptools files: setup.py diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -7,11 +7,15 @@ from distutils2 import __version__ as VERSION from distutils2.util import find_packages from distutils import log -from distutils.core import setup, Extension from distutils.ccompiler import new_compiler from distutils.command.sdist import sdist from distutils.command.install import install +try: + from setuptools import setup, Extension +except ImportError: + from distutils.core import setup, Extension + f = open('README.txt') try: README = f.read() -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Fri Jan 28 18:56:26 2011 From: python-checkins at python.org (brett.cannon) Date: Fri, 28 Jan 2011 18:56:26 +0100 Subject: [Python-checkins] devguide: Grammatical error caught by Eli Bendersky. Message-ID: brett.cannon pushed 1d7038f38b88 to devguide: http://hg.python.org/devguide/rev/1d7038f38b88 changeset: 212:1d7038f38b88 parent: 210:97f3111d8872 user: Brett Cannon date: Fri Jan 28 09:55:57 2011 -0800 summary: Grammatical error caught by Eli Bendersky. files: setup.rst diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -150,7 +150,7 @@ sufficient. To build from the Visual Studio GUI, load the project files and press F7. Make -sure have chosen the "Debug" build first. +sure you have chosen the "Debug" build first. Once built you might want to set Python as a startup project. Pressing F5 in Visual Studio will launch the interpreter. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Jan 28 18:56:27 2011 From: python-checkins at python.org (brett.cannon) Date: Fri, 28 Jan 2011 18:56:27 +0100 Subject: [Python-checkins] devguide: Automated merge with ssh://hg.python.org/devguide Message-ID: brett.cannon pushed 5783b65d965e to devguide: http://hg.python.org/devguide/rev/5783b65d965e changeset: 213:5783b65d965e tag: tip parent: 211:5a191cfa4a0a parent: 212:1d7038f38b88 user: Brett Cannon date: Fri Jan 28 09:56:17 2011 -0800 summary: Automated merge with ssh://hg.python.org/devguide files: diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -150,7 +150,7 @@ sufficient. To build from the Visual Studio GUI, load the project files and press F7. Make -sure have chosen the "Debug" build first. +sure you have chosen the "Debug" build first. Once built you might want to set Python as a startup project. Pressing F5 in Visual Studio will launch the interpreter. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Jan 28 19:48:05 2011 From: python-checkins at python.org (brett.cannon) Date: Fri, 28 Jan 2011 19:48:05 +0100 Subject: [Python-checkins] devguide: Minor tweaks based on Eli Bendersky's feedback. Message-ID: brett.cannon pushed 50499e8c925a to devguide: http://hg.python.org/devguide/rev/50499e8c925a changeset: 214:50499e8c925a tag: tip user: Brett Cannon date: Fri Jan 28 10:47:59 2011 -0800 summary: Minor tweaks based on Eli Bendersky's feedback. files: setup.rst diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -48,8 +48,8 @@ 2.7). Do note that CPython will notice that it is being run from a source checkout. -This means that it if you edit Python source code in your checkout the changes -will be picked up by the interpreter for immediate testing. +This means that it if you edit Python's source code in your checkout the +changes will be picked up by the interpreter for immediate testing. Compiling (for debugging) @@ -73,7 +73,7 @@ Build dependencies '''''''''''''''''' -The core CPython interpreter only needs a C compiler to build itself; if +The core CPython interpreter only needs a C compiler to be built; if you get compile errors with a C89 or C99-compliant compiler, please `open a bug report `_. However, some of the extension modules will need development headers -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Fri Jan 28 20:51:48 2011 From: python-checkins at python.org (michael.foord) Date: Fri, 28 Jan 2011 20:51:48 +0100 (CET) Subject: [Python-checkins] r88221 - in python/branches/py3k: Doc/library/unittest.rst Lib/unittest/case.py Message-ID: <20110128195148.32209EE9BB@mail.python.org> Author: michael.foord Date: Fri Jan 28 20:51:48 2011 New Revision: 88221 Log: Issue 10573: revert unittest docs to first / second Minor internal change to unittest.TestCase.assertCountEqual Reviewed by R. David Murray Modified: python/branches/py3k/Doc/library/unittest.rst python/branches/py3k/Lib/unittest/case.py Modified: python/branches/py3k/Doc/library/unittest.rst ============================================================================== --- python/branches/py3k/Doc/library/unittest.rst (original) +++ python/branches/py3k/Doc/library/unittest.rst Fri Jan 28 20:51:48 2011 @@ -860,12 +860,12 @@ accept a *msg* argument that, if specified, is used as the error message on failure (see also :data:`longMessage`). - .. method:: assertEqual(actual, expected, msg=None) + .. method:: assertEqual(first, second, msg=None) - Test that *actual* and *expected* are equal. If the values do not + Test that *first* and *second* are equal. If the values do not compare equal, the test will fail. - In addition, if *actual* and *expected* are the exact same type and one of + In addition, if *first* and *second* are the exact same type and one of list, tuple, dict, set, frozenset or str or any type that a subclass registers with :meth:`addTypeEqualityFunc` the type specific equality function will be called in order to generate a more useful default @@ -880,9 +880,9 @@ function for comparing strings. - .. method:: assertNotEqual(actual, expected, msg=None) + .. method:: assertNotEqual(first, second, msg=None) - Test that *actual* and *expected* are not equal. If the values do + Test that *first* and *second* are not equal. If the values do compare equal, the test will fail. .. method:: assertTrue(expr, msg=None) @@ -897,10 +897,10 @@ provide a better error message in case of failure. - .. method:: assertIs(actual, expected, msg=None) - assertIsNot(actual, expected, msg=None) + .. method:: assertIs(first, second, msg=None) + assertIsNot(first, second, msg=None) - Test that *actual* and *expected* evaluate (or don't evaluate) to the + Test that *first* and *second* evaluate (or don't evaluate) to the same object. .. versionadded:: 3.1 @@ -1096,17 +1096,17 @@ +---------------------------------------+--------------------------------+--------------+ - .. method:: assertAlmostEqual(actual, expected, places=7, msg=None, delta=None) - assertNotAlmostEqual(actual, expected, places=7, msg=None, delta=None) + .. method:: assertAlmostEqual(first, second, places=7, msg=None, delta=None) + assertNotAlmostEqual(first, second, places=7, msg=None, delta=None) - Test that *actual* and *expected* are approximately (or not approximately) + Test that *first* and *second* are approximately (or not approximately) equal by computing the difference, rounding to the given number of decimal *places* (default 7), and comparing to zero. Note that these methods round the values to the given number of *decimal places* (i.e. like the :func:`round` function) and not *significant digits*. If *delta* is supplied instead of *places* then the difference - between *actual* and *expected* must be less (or more) than *delta*. + between *first* and *second* must be less (or more) than *delta*. Supplying both *delta* and *places* raises a ``TypeError``. @@ -1116,12 +1116,12 @@ if the objects compare equal. Added the *delta* keyword argument. - .. method:: assertGreater(actual, expected, msg=None) - assertGreaterEqual(actual, expected, msg=None) - assertLess(actual, expected, msg=None) - assertLessEqual(actual, expected, msg=None) + .. method:: assertGreater(first, second, msg=None) + assertGreaterEqual(first, second, msg=None) + assertLess(first, second, msg=None) + assertLessEqual(first, second, msg=None) - Test that *actual* is respectively >, >=, < or <= than *expected* depending + Test that *first* is respectively >, >=, < or <= than *second* depending on the method name. If not, the test will fail:: >>> self.assertGreaterEqual(3, 4) @@ -1177,14 +1177,14 @@ .. versionadded:: 3.2 - .. method:: assertSameElements(actual, expected, msg=None) + .. method:: assertSameElements(first, second, msg=None) - Test that sequence *actual* contains the same elements as *expected*, + Test that sequence *first* contains the same elements as *second*, regardless of their order. When they don't, an error message listing the differences between the sequences will be generated. - Duplicate elements are ignored when comparing *actual* and *expected*. - It is the equivalent of ``assertEqual(set(actual), set(expected))`` + Duplicate elements are ignored when comparing *first* and *second*. + It is the equivalent of ``assertEqual(set(first), set(second))`` but it works with sequences of unhashable objects as well. Because duplicates are ignored, this method has been deprecated in favour of :meth:`assertCountEqual`. @@ -1241,9 +1241,9 @@ - .. method:: assertMultiLineEqual(actual, expected, msg=None) + .. method:: assertMultiLineEqual(first, second, msg=None) - Test that the multiline string *actual* is equal to the string *expected*. + Test that the multiline string *first* is equal to the string *second*. When not equal a diff of the two strings highlighting the differences will be included in the error message. This method is used by default when comparing strings with :meth:`assertEqual`. @@ -1251,10 +1251,10 @@ .. versionadded:: 3.1 - .. method:: assertSequenceEqual(actual, expected, msg=None, seq_type=None) + .. method:: assertSequenceEqual(first, second, msg=None, seq_type=None) Tests that two sequences are equal. If a *seq_type* is supplied, both - *actual* and *expected* must be instances of *seq_type* or a failure will + *first* and *second* must be instances of *seq_type* or a failure will be raised. If the sequences are different an error message is constructed that shows the difference between the two. @@ -1265,8 +1265,8 @@ .. versionadded:: 3.1 - .. method:: assertListEqual(actual, expected, msg=None) - assertTupleEqual(actual, expected, msg=None) + .. method:: assertListEqual(first, second, msg=None) + assertTupleEqual(first, second, msg=None) Tests that two lists or tuples are equal. If not an error message is constructed that shows only the differences between the two. An error @@ -1277,19 +1277,19 @@ .. versionadded:: 3.1 - .. method:: assertSetEqual(actual, expected, msg=None) + .. method:: assertSetEqual(first, second, msg=None) Tests that two sets are equal. If not, an error message is constructed that lists the differences between the sets. This method is used by default when comparing sets or frozensets with :meth:`assertEqual`. - Fails if either of *actual* or *expected* does not have a :meth:`set.difference` + Fails if either of *first* or *second* does not have a :meth:`set.difference` method. .. versionadded:: 3.1 - .. method:: assertDictEqual(actual, expected, msg=None) + .. method:: assertDictEqual(first, second, msg=None) Test that two dictionaries are equal. If not, an error message is constructed that shows the differences in the dictionaries. This Modified: python/branches/py3k/Lib/unittest/case.py ============================================================================== --- python/branches/py3k/Lib/unittest/case.py (original) +++ python/branches/py3k/Lib/unittest/case.py Fri Jan 28 20:51:48 2011 @@ -1022,17 +1022,17 @@ - [0, 0, 1] and [0, 1] compare unequal. """ - actual_seq, expected_seq = list(first), list(second) + first_seq, second_seq = list(first), list(second) try: - actual = collections.Counter(actual_seq) - expected = collections.Counter(expected_seq) + first = collections.Counter(first_seq) + second = collections.Counter(second_seq) except TypeError: # Handle case with unhashable elements - differences = _count_diff_all_purpose(actual_seq, expected_seq) + differences = _count_diff_all_purpose(first_seq, second_seq) else: - if actual == expected: + if first == second: return - differences = _count_diff_hashable(actual_seq, expected_seq) + differences = _count_diff_hashable(first_seq, second_seq) if differences: standardMsg = 'Element counts were not equal:\n' From python-checkins at python.org Fri Jan 28 21:23:25 2011 From: python-checkins at python.org (eric.smith) Date: Fri, 28 Jan 2011 21:23:25 +0100 (CET) Subject: [Python-checkins] r88222 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110128202325.835EDEE988@mail.python.org> Author: eric.smith Date: Fri Jan 28 21:23:25 2011 New Revision: 88222 Log: Added a placeholder for str.format_map, as discussed with Raymond. My prose is horrible, some cleanup is required. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Fri Jan 28 21:23:25 2011 @@ -442,6 +442,26 @@ (Suggested by Mark Dickinson and implemented by Eric Smith in :issue:`7094`.) +.. XXX * :meth:`str.format_map` was added, allowing an arbitrary mapping object + to be passed in to :meth:`str.format`. `somestring.format_map(mapping)` + is similar to `somestring.format(**mapping)`, except that in the latter + case `mapping` is convert to a `dict` and in the former case `mapping` + is used without modification. For example, to use a `defaultdict` with + formatting:: + + >>> from collections import defaultdict + >>> mapping = defaultdict(lambda: 'Europe', name='Guido') + >>> '{name} was born in {country}'.format_map(mapping) + 'Guido was born in Europe' + + This is similar to %-formatting with a single mapping argument:: + + >>> '%(name)s was born in %(country)s' % mapping + 'Guido was born in Europe' + + (Suggested by Raymond Hettinger and implemented by Eric Smith in + :issue:`6081`.) + * The interpreter can now be started with a quiet option, ``-q``, to suppress the copyright and version information from being displayed in the interactive mode. The option can be introspected using the :attr:`sys.flags` attribute:: From python-checkins at python.org Sat Jan 29 01:00:35 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 29 Jan 2011 01:00:35 +0100 Subject: [Python-checkins] devguide: Mention that -p1 is sometimes needed for 'patch'. Message-ID: brett.cannon pushed 4c4413b841d6 to devguide: http://hg.python.org/devguide/rev/4c4413b841d6 changeset: 215:4c4413b841d6 user: Brett Cannon date: Fri Jan 28 15:34:05 2011 -0800 summary: Mention that -p1 is sometimes needed for 'patch'. files: patch.rst diff --git a/patch.rst b/patch.rst --- a/patch.rst +++ b/patch.rst @@ -79,6 +79,10 @@ patch -p0 < patch.diff +If a developer is using something other than svn to manage their code (e.g., +the mq extension for Mercurial), the number passed to ``-p`` may need to be +changed to ``1``. + To undo a patch, you can revert **all** changes made in your checkout:: svn revert -R . -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 29 01:00:37 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 29 Jan 2011 01:00:37 +0100 Subject: [Python-checkins] devguide: Link to more issues related to coverage testing. Message-ID: brett.cannon pushed d010a2ade6d2 to devguide: http://hg.python.org/devguide/rev/d010a2ade6d2 changeset: 216:d010a2ade6d2 user: Brett Cannon date: Fri Jan 28 15:39:33 2011 -0800 summary: Link to more issues related to coverage testing. files: coverage.rst diff --git a/coverage.rst b/coverage.rst --- a/coverage.rst +++ b/coverage.rst @@ -43,10 +43,11 @@ .. warning:: Running the entire test suite under coverage (using either technique listed below) currently fails as some tests are resetting the trace function; - see http://bugs.python.org/issue10990 + see http://bugs.python.org/issue10990 for a patch There are also various tests that simply fail as they have not been made - robust in the face of coverage measuring/having a trace function set. + robust in the face of coverage measuring/having a trace function set; + see http://bugs.python.org/issue10992 for a patch Using coverage.py ----------------- @@ -103,7 +104,7 @@ But one of the strengths of coverage.py is its HTML-based reports which lets you visually see what lines of code were not tested:: - ./python -m coverage -d coverage_html html + ./python -m coverage -d coverage_html html -i You can then open the ``coverage_html/index.html`` file in a web browser to view the coverage results in a nicely formatted page. -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 29 01:00:37 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 29 Jan 2011 01:00:37 +0100 Subject: [Python-checkins] devguide: Point out that I maintain a fork of coverage.py to try to make sure some Message-ID: brett.cannon pushed bbfdc4b794ab to devguide: http://hg.python.org/devguide/rev/bbfdc4b794ab changeset: 217:bbfdc4b794ab user: Brett Cannon date: Fri Jan 28 15:45:18 2011 -0800 summary: Point out that I maintain a fork of coverage.py to try to make sure some version always works against py3k. files: coverage.rst diff --git a/coverage.rst b/coverage.rst --- a/coverage.rst +++ b/coverage.rst @@ -68,7 +68,14 @@ hg clone https://bitbucket.org/ned/coveragepy ln -s coveragepy/coverage -Otherwise you can use the latest release of coverage.py. One option is to +If you are still having issues with generating coverage, a fork of coverage.py +can be found at https://bitbucket.org/brettsky/coverage.py which will always +try to be patched to work against the latest in-development version of Python +(all patches are submitted upstream so this should only be used as a temporary +solution). Otherwise you can use the latest release of coverage.py if you +already have it installed. + +One option is to download the source distribution of coverage.py and copy the ``coverage`` directory into your Python checkout. The other option is to use your checkout copy of Python to install coverage.py (but use the ``--user`` flag to -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 29 01:00:38 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 29 Jan 2011 01:00:38 +0100 Subject: [Python-checkins] devguide: For generating HTML reports for coverage.py, omit test modules to speed up Message-ID: brett.cannon pushed 037eda83ab17 to devguide: http://hg.python.org/devguide/rev/037eda83ab17 changeset: 218:037eda83ab17 user: Brett Cannon date: Fri Jan 28 15:57:15 2011 -0800 summary: For generating HTML reports for coverage.py, omit test modules to speed up generation. files: coverage.rst diff --git a/coverage.rst b/coverage.rst --- a/coverage.rst +++ b/coverage.rst @@ -72,10 +72,9 @@ can be found at https://bitbucket.org/brettsky/coverage.py which will always try to be patched to work against the latest in-development version of Python (all patches are submitted upstream so this should only be used as a temporary -solution). Otherwise you can use the latest release of coverage.py if you -already have it installed. +solution). -One option is to +Another option is to download the source distribution of coverage.py and copy the ``coverage`` directory into your Python checkout. The other option is to use your checkout copy of Python to install coverage.py (but use the ``--user`` flag to @@ -92,7 +91,7 @@ ./python -m coverage run --pylib Lib/test/regrtest.py -If you want to run only a single test, specify the module/package being tested +To run only a single test, specify the module/package being tested in the ``--source`` flag (so as to prune the coverage reporting to only the module/package you are interested in) and then append the name of the test you wish to run to the command:: @@ -111,10 +110,12 @@ But one of the strengths of coverage.py is its HTML-based reports which lets you visually see what lines of code were not tested:: - ./python -m coverage -d coverage_html html -i + ./python -m coverage -d coverage_html html -i --omit="*/test/*,*/tests/*" -You can then open the ``coverage_html/index.html`` file in a web browser to -view the coverage results in a nicely formatted page. +This will generate an HTML report which ignores any errors that may arise and +ignores test modules. You can then open the ``coverage_html/index.html`` file +in a web browser to view the coverage results along with pages that visibly +show what lines of code were not executed. .. _branch_coverage: -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 29 01:00:38 2011 From: python-checkins at python.org (brett.cannon) Date: Sat, 29 Jan 2011 01:00:38 +0100 Subject: [Python-checkins] devguide: Mention that coverage should always be run for a module in isolation to get a Message-ID: brett.cannon pushed dfa3335be30d to devguide: http://hg.python.org/devguide/rev/dfa3335be30d changeset: 219:dfa3335be30d tag: tip user: Brett Cannon date: Fri Jan 28 16:00:24 2011 -0800 summary: Mention that coverage should always be run for a module in isolation to get a more accurate measurement of the effectiveness of the module's tests. files: coverage.rst diff --git a/coverage.rst b/coverage.rst --- a/coverage.rst +++ b/coverage.rst @@ -36,6 +36,11 @@ takes some time to complete, but you will have an accurate, up-to-date notion of what modules need the most work. +Do make sure, though, that for any module you do decide to work that you run +coverage for just that module. This wll make sure you know how good the +explicit coverage of the module is from its own set of tests instead of from +implicit testing by other code that happens to use the module. + Measuring Coverage """""""""""""""""" -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sat Jan 29 01:31:51 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 29 Jan 2011 01:31:51 +0100 Subject: [Python-checkins] devguide: Mercurial is enough Message-ID: antoine.pitrou pushed 844762dc304c to devguide: http://hg.python.org/devguide/rev/844762dc304c changeset: 220:844762dc304c tag: tip user: Antoine Pitrou date: Sat Jan 29 01:31:46 2011 +0100 summary: Mercurial is enough files: patch.rst diff --git a/patch.rst b/patch.rst --- a/patch.rst +++ b/patch.rst @@ -79,9 +79,8 @@ patch -p0 < patch.diff -If a developer is using something other than svn to manage their code (e.g., -the mq extension for Mercurial), the number passed to ``-p`` may need to be -changed to ``1``. +If the developer is using something other than svn to manage their code (e.g., +Mercurial), you might have to use ``-p1`` instead of ``-p0``. To undo a patch, you can revert **all** changes made in your checkout:: -- Repository URL: http://hg.python.org/devguide From solipsis at pitrou.net Sat Jan 29 05:09:39 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sat, 29 Jan 2011 05:09:39 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r88222): sum=0 Message-ID: py3k results for svn r88222 (hg cset 89c2fae4f3d5) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflogsFn2DP', '-x'] From python-checkins at python.org Sat Jan 29 09:51:57 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sat, 29 Jan 2011 09:51:57 +0100 (CET) Subject: [Python-checkins] r88223 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110129085157.96091EE998@mail.python.org> Author: raymond.hettinger Date: Sat Jan 29 09:51:57 2011 New Revision: 88223 Log: Add entry for str.format_map(). Add bullet list and reference to documentation section. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Sat Jan 29 09:51:57 2011 @@ -442,25 +442,35 @@ (Suggested by Mark Dickinson and implemented by Eric Smith in :issue:`7094`.) -.. XXX * :meth:`str.format_map` was added, allowing an arbitrary mapping object - to be passed in to :meth:`str.format`. `somestring.format_map(mapping)` - is similar to `somestring.format(**mapping)`, except that in the latter - case `mapping` is convert to a `dict` and in the former case `mapping` - is used without modification. For example, to use a `defaultdict` with - formatting:: - - >>> from collections import defaultdict - >>> mapping = defaultdict(lambda: 'Europe', name='Guido') - >>> '{name} was born in {country}'.format_map(mapping) - 'Guido was born in Europe' +* There is also a new :meth:`str.format_map` method that extends the + capabilities of the existing :meth:`str.format` method by accepting arbitrary + :term:`mapping` objects. This new method makes it possible to use string + formatting with any of one of Python's many dictionary-like tools such as + :class:`~collections.defaultdict`, :class:`~shelve.Shelf`, + :class:`~configparser.ConfigParser`, or :mod:`dbm`. It also useful with + custom :class:`dict` subclasses that normalize keys before look-up or that + supply a :meth:`__missing__` method for unknown keys:: + + >>> import shelve + >>> d = shelve.open('tmp.shl') + >>> 'The {project_name} status is {status} as of {date}'.format_map(d) + 'The testing project status is green as of February 15, 2011' + + >>> class LowerCasedDict(dict): + def __getitem__(self, key): + return dict.__getitem__(self, key.lower()) + >>> lcd = LowerCasedDict(part='widgets', quantity=10) + >>> 'There are {QUANTITY} {Part} in stock'.format_map(lcd) + 'There are 10 widgets in stock' + + >>> class PlaceholderDict(dict): + def __missing__(self, key): + return '<{}>'.format(key) + >>> 'Hello {name}, welcome to {location}'.format_map(PlaceholderDict()) + 'Hello , welcome to ' - This is similar to %-formatting with a single mapping argument:: - - >>> '%(name)s was born in %(country)s' % mapping - 'Guido was born in Europe' - - (Suggested by Raymond Hettinger and implemented by Eric Smith in - :issue:`6081`.) + (Suggested by Raymond Hettinger and implemented by Eric Smith in + :issue:`6081`.) * The interpreter can now be started with a quiet option, ``-q``, to suppress the copyright and version information from being displayed in the interactive @@ -2267,28 +2277,37 @@ The documentation continues to be improved. -A table of quick links has been added to the top of lengthy sections such as -:ref:`built-in-funcs`. In the case of :mod:`itertools`, the links are -accompanied by tables of cheatsheet-style summaries to provide an overview and -memory jog without having to read all of the docs. - -In some cases, the pure Python source code can be a helpful adjunct to the -documentation, so now many modules now feature quick links to the latest version -of the source code. For example, the :mod:`functools` module documentation has -a quick link at the top labeled: **Source code** :source:`Lib/functools.py`. -(Contributed by Raymond Hettinger.) - -The docs now contain more examples and recipes. In particular, :mod:`re` module -has an extensive section, :ref:`re-examples`. Likewise, the :mod:`itertools` -module continues to be updated with new :ref:`itertools-recipes`. - -The :mod:`datetime` module now has an auxiliary implementation in pure Python. -No functionality was changed. This just provides an easier-to-read -alternate implementation. (Contributed by Alexander Belopolsky.) - -The unmaintained :file:`Demo` directory has been removed. Some demos were -integrated into the documentation, some were moved to the :file:`Tools/demo` -directory, and others were removed altogether. (Contributed by Georg Brandl.) +* A table of quick links has been added to the top of lengthy sections such as + :ref:`built-in-funcs`. In the case of :mod:`itertools`, the links are + accompanied by tables of cheatsheet-style summaries to provide an overview and + memory jog without having to read all of the docs. + +* In some cases, the pure Python source code can be a helpful adjunct to the + documentation, so now many modules now feature quick links to the latest + version of the source code. For example, the :mod:`functools` module + documentation has a quick link at the top labeled: + + **Source code** :source:`Lib/functools.py`. + + (Contributed by Raymond Hettinger; see + `rationale `_.) + +* The docs now contain more examples and recipes. In particular, :mod:`re` + module has an extensive section, :ref:`re-examples`. Likewise, the + :mod:`itertools` module continues to be updated with new + :ref:`itertools-recipes`. + +* The :mod:`datetime` module now has an auxiliary implementation in pure Python. + No functionality was changed. This just provides an easier-to-read alternate + implementation. + + (Contributed by Alexander Belopolsky in :issue:`9528`.) + +* The unmaintained :file:`Demo` directory has been removed. Some demos were + integrated into the documentation, some were moved to the :file:`Tools/demo` + directory, and others were removed altogether. + + (Contributed by Georg Brandl in :issue:`7962`.) IDLE From python-checkins at python.org Sat Jan 29 11:09:15 2011 From: python-checkins at python.org (antoine.pitrou) Date: Sat, 29 Jan 2011 11:09:15 +0100 (CET) Subject: [Python-checkins] r88224 - python/branches/test_subprocess_10826/Lib/test/subprocessdata/fd_status.py Message-ID: <20110129100915.DDDDBEE983@mail.python.org> Author: antoine.pitrou Date: Sat Jan 29 11:09:15 2011 New Revision: 88224 Log: Try to ignore Solaris door files in fd_status.py Modified: python/branches/test_subprocess_10826/Lib/test/subprocessdata/fd_status.py Modified: python/branches/test_subprocess_10826/Lib/test/subprocessdata/fd_status.py ============================================================================== --- python/branches/test_subprocess_10826/Lib/test/subprocessdata/fd_status.py (original) +++ python/branches/test_subprocess_10826/Lib/test/subprocessdata/fd_status.py Sat Jan 29 11:09:15 2011 @@ -3,32 +3,22 @@ import errno import os -import fcntl -import subprocess -import sys try: _MAXFD = os.sysconf("SC_OPEN_MAX") except: _MAXFD = 256 -def isopen(fd): - """Return True if the fd is open, and False otherwise""" - try: - fcntl.fcntl(fd, fcntl.F_GETFD, 0) - except IOError as e: - if e.errno == errno.EBADF: - return False - raise - return True - if __name__ == "__main__": - fds = [fd for fd in range(0, _MAXFD) if isopen(fd)] + fds = [] + for fd in range(0, _MAXFD): + try: + st = os.fstat(fd) + except OSError as e: + if e.errno == errno.EBADF: + continue + raise + # Ignore Solaris door files + if st.st_mode & 0xF000 != 0xd000: + fds.append(fd) print(','.join(map(str, fds))) - if '--debug' in sys.argv[1:]: - for fd in fds: - print(fd, fcntl.fcntl(fd, fcntl.F_GETFL), os.fstat(fd)) - sys.stdout.flush() - subprocess.call("ls -la /proc/{}/fd/".format(os.getpid()), shell=True) - if 5 in fds: - subprocess.call("stat /proc/{}/fd/{}".format(os.getpid(), 5), shell=True) From python-checkins at python.org Sat Jan 29 12:15:35 2011 From: python-checkins at python.org (eric.smith) Date: Sat, 29 Jan 2011 12:15:35 +0100 (CET) Subject: [Python-checkins] r88226 - in python/branches/py3k: Lib/test/test_unicode.py Objects/stringlib/string_format.h Message-ID: <20110129111535.CE303EE9B1@mail.python.org> Author: eric.smith Date: Sat Jan 29 12:15:35 2011 New Revision: 88226 Log: Issue #11302: missing type check on _string.formatter_field_name_split and _string.formatter_parser caused crash. Originial patch by haypo, reviewed by me, okayed by Georg. Modified: python/branches/py3k/Lib/test/test_unicode.py python/branches/py3k/Objects/stringlib/string_format.h Modified: python/branches/py3k/Lib/test/test_unicode.py ============================================================================== --- python/branches/py3k/Lib/test/test_unicode.py (original) +++ python/branches/py3k/Lib/test/test_unicode.py Sat Jan 29 12:15:35 2011 @@ -11,6 +11,7 @@ import unittest import warnings from test import support, string_tests +import _string # Error handling (bad decoder return) def search_function(encoding): @@ -1516,6 +1517,57 @@ self.assertEqual(wchar, nonbmp + '\0') +class StringModuleTest(unittest.TestCase): + def test_formatter_parser(self): + def parse(format): + return list(_string.formatter_parser(format)) + + formatter = parse("prefix {2!s}xxx{0:^+10.3f}{obj.attr!s} {z[0]!s:10}") + self.assertEqual(formatter, [ + ('prefix ', '2', '', 's'), + ('xxx', '0', '^+10.3f', None), + ('', 'obj.attr', '', 's'), + (' ', 'z[0]', '10', 's'), + ]) + + formatter = parse("prefix {} suffix") + self.assertEqual(formatter, [ + ('prefix ', '', '', None), + (' suffix', None, None, None), + ]) + + formatter = parse("str") + self.assertEqual(formatter, [ + ('str', None, None, None), + ]) + + formatter = parse("") + self.assertEqual(formatter, []) + + formatter = parse("{0}") + self.assertEqual(formatter, [ + ('', '0', '', None), + ]) + + self.assertRaises(TypeError, _string.formatter_parser, 1) + + def test_formatter_field_name_split(self): + def split(name): + items = list(_string.formatter_field_name_split(name)) + items[1] = list(items[1]) + return items + self.assertEqual(split("obj"), ["obj", []]) + self.assertEqual(split("obj.arg"), ["obj", [(True, 'arg')]]) + self.assertEqual(split("obj[key]"), ["obj", [(False, 'key')]]) + self.assertEqual(split("obj.arg[key1][key2]"), [ + "obj", + [(True, 'arg'), + (False, 'key1'), + (False, 'key2'), + ]]) + self.assertRaises(TypeError, _string.formatter_field_name_split, 1) + + def test_main(): support.run_unittest(__name__) Modified: python/branches/py3k/Objects/stringlib/string_format.h ============================================================================== --- python/branches/py3k/Objects/stringlib/string_format.h (original) +++ python/branches/py3k/Objects/stringlib/string_format.h Sat Jan 29 12:15:35 2011 @@ -1192,6 +1192,11 @@ { formatteriterobject *it; + if (!PyUnicode_Check(self)) { + PyErr_Format(PyExc_TypeError, "expected str, got %s", Py_TYPE(self)->tp_name); + return NULL; + } + it = PyObject_New(formatteriterobject, &PyFormatterIter_Type); if (it == NULL) return NULL; @@ -1332,6 +1337,11 @@ PyObject *first_obj = NULL; PyObject *result = NULL; + if (!PyUnicode_Check(self)) { + PyErr_Format(PyExc_TypeError, "expected str, got %s", Py_TYPE(self)->tp_name); + return NULL; + } + it = PyObject_New(fieldnameiterobject, &PyFieldNameIter_Type); if (it == NULL) return NULL; From python-checkins at python.org Sat Jan 29 12:31:20 2011 From: python-checkins at python.org (victor.stinner) Date: Sat, 29 Jan 2011 12:31:20 +0100 (CET) Subject: [Python-checkins] r88228 - in python/branches/py3k: Lib/test/test_ssl.py Misc/NEWS Modules/_ssl.c Message-ID: <20110129113120.E0F25EE9CE@mail.python.org> Author: victor.stinner Date: Sat Jan 29 12:31:20 2011 New Revision: 88228 Log: Issue #10989: Fix a crash on SSLContext.load_verify_locations(None, True). Patch reviewed by Antoine Pitrou, okayed by Georg Brandl. Modified: python/branches/py3k/Lib/test/test_ssl.py python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/_ssl.c Modified: python/branches/py3k/Lib/test/test_ssl.py ============================================================================== --- python/branches/py3k/Lib/test/test_ssl.py (original) +++ python/branches/py3k/Lib/test/test_ssl.py Sat Jan 29 12:31:20 2011 @@ -394,6 +394,9 @@ ctx.load_verify_locations(CERTFILE, CAPATH) ctx.load_verify_locations(CERTFILE, capath=BYTES_CAPATH) + # Issue #10989: crash if the second argument type is invalid + self.assertRaises(TypeError, ctx.load_verify_locations, None, True) + @skip_if_broken_ubuntu_ssl def test_session_stats(self): for proto in PROTOCOLS: Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 29 12:31:20 2011 @@ -16,6 +16,8 @@ Library ------- +- Issue #10989: Fix a crash on SSLContext.load_verify_locations(None, True). + - Issue #11020: Command-line pyclbr was broken because of missing 2-to-3 conversion. Modified: python/branches/py3k/Modules/_ssl.c ============================================================================== --- python/branches/py3k/Modules/_ssl.c (original) +++ python/branches/py3k/Modules/_ssl.c Sat Jan 29 12:31:20 2011 @@ -1683,7 +1683,7 @@ return NULL; } if (capath && !PyUnicode_FSConverter(capath, &capath_bytes)) { - Py_DECREF(cafile_bytes); + Py_XDECREF(cafile_bytes); PyErr_SetString(PyExc_TypeError, "capath should be a valid filesystem path"); return NULL; From python-checkins at python.org Sat Jan 29 12:33:25 2011 From: python-checkins at python.org (eric.smith) Date: Sat, 29 Jan 2011 12:33:25 +0100 (CET) Subject: [Python-checkins] r88229 - python/branches/release31-maint Message-ID: <20110129113325.EA221EE983@mail.python.org> Author: eric.smith Date: Sat Jan 29 12:33:25 2011 New Revision: 88229 Log: Blocked revisions 88226 via svnmerge ........ r88226 | eric.smith | 2011-01-29 06:15:35 -0500 (Sat, 29 Jan 2011) | 3 lines Issue #11302: missing type check on _string.formatter_field_name_split and _string.formatter_parser caused crash. Originial patch by haypo, reviewed by me, okayed by Georg. ........ Modified: python/branches/release31-maint/ (props changed) From python-checkins at python.org Sat Jan 29 12:59:10 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 12:59:10 +0100 Subject: [Python-checkins] distutils2: Allow to have more than one file in description-file. Also check that those Message-ID: tarek.ziade pushed c8dfb3c63894 to distutils2: http://hg.python.org/distutils2/rev/c8dfb3c63894 changeset: 901:c8dfb3c63894 user: Gael Pasgrimaud date: Fri Jan 28 17:48:07 2011 +0100 summary: Allow to have more than one file in description-file. Also check that those files are added to MANIFEST files: distutils2/command/sdist.py distutils2/config.py distutils2/metadata.py distutils2/tests/test_config.py diff --git a/distutils2/command/sdist.py b/distutils2/command/sdist.py --- a/distutils2/command/sdist.py +++ b/distutils2/command/sdist.py @@ -18,7 +18,8 @@ from distutils2.command import get_command_names from distutils2.command.cmd import Command from distutils2.errors import (DistutilsPlatformError, DistutilsOptionError, - DistutilsTemplateError, DistutilsModuleError) + DistutilsTemplateError, DistutilsModuleError, + DistutilsFileError) from distutils2.manifest import Manifest from distutils2 import logger from distutils2.util import convert_path, resolve_name @@ -319,6 +320,12 @@ logger.warn("no files to distribute -- empty manifest?") else: logger.info(msg) + + for file in self.distribution.metadata.requires_files: + if file not in files: + msg = "'%s' must be included explicitly extra-files metadata" % file + raise DistutilsFileError(msg) + for file in files: if not os.path.isfile(file): logger.warn("'%s' not a regular file -- skipping" % file) diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -112,11 +112,23 @@ "mutually exclusive") raise DistutilsOptionError(msg) - f = open(value) # will raise if file not found - try: - value = f.read() - finally: - f.close() + if isinstance(value, list): + filenames = value + else: + filenames = value.split() + + # concatenate each files + value = '' + for filename in filenames: + f = open(filename) # will raise if file not found + try: + value += f.read().strip() + '\n' + finally: + f.close() + # add filename as a required file + if filename not in metadata.requires_files: + metadata.requires_files.append(filename) + value = value.strip() key = 'description' if metadata.is_metadata_field(key): diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -202,6 +202,7 @@ self._fields = {} self.display_warnings = display_warnings self.version = None + self.requires_files = [] self.docutils_support = _HAS_DOCUTILS self.platform_dependent = platform_dependent self.execution_context = execution_context diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -5,6 +5,8 @@ from StringIO import StringIO from distutils2.tests import unittest, support, run_unittest +from distutils2.command.sdist import sdist +from distutils2.errors import DistutilsFileError SETUP_CFG = """ @@ -16,7 +18,7 @@ maintainer = ??ric Araujo maintainer_email = merwok at netwok.org summary = A sample project demonstrating distutils2 packaging -description-file = README +description-file = %(description-file)s keywords = distutils2, packaging, sample project classifier = @@ -66,6 +68,8 @@ config = cfg/data.cfg /etc/init.d = init-script +extra_files = %(extra-files)s + # Replaces MANIFEST.in sdist_extra = include THANKS HACKING @@ -130,22 +134,32 @@ self.addCleanup(setattr, sys, 'stderr', sys.stderr) self.addCleanup(os.chdir, os.getcwd()) - def test_config(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) - self.write_file('setup.cfg', SETUP_CFG) - self.write_file('README', 'yeah') + def write_setup(self, kwargs=None): + opts = {'description-file': 'README', 'extra-files':''} + if kwargs: + opts.update(kwargs) + self.write_file('setup.cfg', SETUP_CFG % opts) - # try to load the metadata now + def run_setup(self, *args): + # run setup with args sys.stdout = StringIO() - sys.argv[:] = ['setup.py', '--version'] + sys.argv[:] = [''] + list(args) old_sys = sys.argv[:] - try: from distutils2.run import commands_main dist = commands_main() finally: sys.argv[:] = old_sys + return dist + + def test_config(self): + tempdir = self.mkdtemp() + os.chdir(tempdir) + self.write_setup() + self.write_file('README', 'yeah') + + # try to load the metadata now + dist = self.run_setup('--version') # sanity check self.assertEqual(sys.stdout.getvalue(), '0.6.4.dev1' + os.linesep) @@ -213,10 +227,80 @@ d = new_compiler(compiler='d') self.assertEqual(d.description, 'D Compiler') + + def test_multiple_description_file(self): + tempdir = self.mkdtemp() + os.chdir(tempdir) + + self.write_setup({'description-file': 'README CHANGES'}) + self.write_file('README', 'yeah') + self.write_file('CHANGES', 'changelog2') + dist = self.run_setup('--version') + self.assertEqual(dist.metadata.requires_files, ['README', 'CHANGES']) + + def test_multiline_description_file(self): + tempdir = self.mkdtemp() + os.chdir(tempdir) + + self.write_setup({'description-file': 'README\n CHANGES'}) + self.write_file('README', 'yeah') + self.write_file('CHANGES', 'changelog') + dist = self.run_setup('--version') + self.assertEqual(dist.metadata['description'], 'yeah\nchangelog') + self.assertEqual(dist.metadata.requires_files, ['README', 'CHANGES']) + + def test_metadata_requires_description_files_missing(self): + tempdir = self.mkdtemp() + os.chdir(tempdir) + self.write_setup({'description-file': 'README\n README2'}) + self.write_file('README', 'yeah') + self.write_file('README2', 'yeah') + self.write_file('haven.py', '#') + self.write_file('script1.py', '#') + os.mkdir('scripts') + self.write_file(os.path.join('scripts', 'find-coconuts'), '#') + os.mkdir('bin') + self.write_file(os.path.join('bin', 'taunt'), '#') + + for pkg in ('one', 'src', 'src2'): + os.mkdir(pkg) + self.write_file(os.path.join(pkg, '__init__.py'), '#') + + dist = self.run_setup('--version') + cmd = sdist(dist) + cmd.finalize_options() + cmd.get_file_list() + self.assertRaises(DistutilsFileError, cmd.make_distribution) + + def test_metadata_requires_description_files(self): + tempdir = self.mkdtemp() + os.chdir(tempdir) + self.write_setup({'description-file': 'README\n README2', 'extra-files':'\n README2'}) + self.write_file('README', 'yeah') + self.write_file('README2', 'yeah') + self.write_file('haven.py', '#') + self.write_file('script1.py', '#') + os.mkdir('scripts') + self.write_file(os.path.join('scripts', 'find-coconuts'), '#') + os.mkdir('bin') + self.write_file(os.path.join('bin', 'taunt'), '#') + + for pkg in ('one', 'src', 'src2'): + os.mkdir(pkg) + self.write_file(os.path.join(pkg, '__init__.py'), '#') + + dist = self.run_setup('--version') + cmd = sdist(dist) + cmd.finalize_options() + cmd.get_file_list() + cmd.make_distribution() + self.assertIn('README\nREADME2\n', open('MANIFEST').read()) + + def test_sub_commands(self): tempdir = self.mkdtemp() os.chdir(tempdir) - self.write_file('setup.cfg', SETUP_CFG) + self.write_setup() self.write_file('README', 'yeah') self.write_file('haven.py', '#') self.write_file('script1.py', '#') @@ -230,14 +314,7 @@ self.write_file(os.path.join(pkg, '__init__.py'), '#') # try to run the install command to see if foo is called - sys.stdout = sys.stderr = StringIO() - sys.argv[:] = ['', 'install_dist'] - old_sys = sys.argv[:] - try: - from distutils2.run import main - dist = main() - finally: - sys.argv[:] = old_sys + dist = self.run_setup('install_dist') self.assertEqual(dist.foo_was_here, 1) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 12:59:10 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 12:59:10 +0100 Subject: [Python-checkins] distutils2: move line Message-ID: tarek.ziade pushed f14bdaf3a95d to distutils2: http://hg.python.org/distutils2/rev/f14bdaf3a95d changeset: 900:f14bdaf3a95d user: Gael Pasgrimaud date: Fri Jan 28 15:24:57 2011 +0100 summary: move line files: distutils2/metadata.py diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -78,13 +78,13 @@ 'Obsoletes-Dist', 'Requires-External', 'Maintainer', 'Maintainer-email', 'Project-URL') +_345_REQUIRED = ('Name', 'Version') + _ALL_FIELDS = set() _ALL_FIELDS.update(_241_FIELDS) _ALL_FIELDS.update(_314_FIELDS) _ALL_FIELDS.update(_345_FIELDS) -_345_REQUIRED = ('Name', 'Version') - def _version2fieldlist(version): if version == '1.0': return _241_FIELDS -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 12:59:10 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 12:59:10 +0100 Subject: [Python-checkins] distutils2: add DistributionMetadata to apiref. fix directives in modules documentation Message-ID: tarek.ziade pushed bfd11fb015af to distutils2: http://hg.python.org/distutils2/rev/bfd11fb015af changeset: 902:bfd11fb015af user: Gael Pasgrimaud date: Fri Jan 28 18:33:45 2011 +0100 summary: add DistributionMetadata to apiref. fix directives in modules documentation files: distutils2/metadata.py docs/source/distutils/apiref.rst docs/source/distutils/examples.rst docs/source/library/distutils2.metadata.rst diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -181,7 +181,12 @@ _UNICODEFIELDS = ('Author', 'Maintainer', 'Summary', 'Description') -_MISSING = object() +class NoDefault(object): + """Marker object used for clean representation""" + def __repr__(self): + return '' + +_MISSING = NoDefault() class DistributionMetadata(object): """The metadata of a release. @@ -455,7 +460,8 @@ return value def check(self, strict=False): - """Check if the metadata is compliant.""" + """Check if the metadata is compliant. If strict is False then raise if + no Name or Version are provided""" # XXX should check the versions (if the file was loaded) missing, warnings = [], [] diff --git a/docs/source/distutils/apiref.rst b/docs/source/distutils/apiref.rst --- a/docs/source/distutils/apiref.rst +++ b/docs/source/distutils/apiref.rst @@ -1055,6 +1055,13 @@ Create a file called *filename* and write *contents* (a sequence of strings without line terminators) to it. +:mod:`distutils2.metadata` --- Metadata handling +================================================================ + +.. module:: distutils2.metadata + +.. autoclass:: distutils2.metadata.DistributionMetadata + :members: :mod:`distutils2.util` --- Miscellaneous other utility functions ================================================================ diff --git a/docs/source/distutils/examples.rst b/docs/source/distutils/examples.rst --- a/docs/source/distutils/examples.rst +++ b/docs/source/distutils/examples.rst @@ -301,7 +301,7 @@ :class:`distutils2.dist.DistributionMetadata` class and its :func:`read_pkg_file` method:: - >>> from distutils2.dist import DistributionMetadata + >>> from distutils2.metadata import DistributionMetadata >>> metadata = DistributionMetadata() >>> metadata.read_pkg_file(open('distribute-0.6.8-py2.7.egg-info')) >>> metadata.name diff --git a/docs/source/library/distutils2.metadata.rst b/docs/source/library/distutils2.metadata.rst --- a/docs/source/library/distutils2.metadata.rst +++ b/docs/source/library/distutils2.metadata.rst @@ -2,7 +2,9 @@ Metadata ======== -Distutils2 provides a :class:`DistributionMetadata` class that can read and +.. module:: distutils2.metadata + +Distutils2 provides a :class:`~distutils2.metadata.DistributionMetadata` class that can read and write metadata files. This class is compatible with all metadata versions: * 1.0: :PEP:`241` @@ -17,7 +19,7 @@ Reading metadata ================ -The :class:`DistributionMetadata` class can be instantiated with the path of +The :class:`~distutils2.metadata.DistributionMetadata` class can be instantiated with the path of the metadata file, and provides a dict-like interface to the values:: >>> from distutils2.metadata import DistributionMetadata @@ -33,7 +35,7 @@ The fields that supports environment markers can be automatically ignored if the object is instantiated using the ``platform_dependent`` option. -:class:`DistributionMetadata` will interpret in the case the markers and will +:class:`~distutils2.metadata.DistributionMetadata` will interpret in the case the markers and will automatically remove the fields that are not compliant with the running environment. Here's an example under Mac OS X. The win32 dependency we saw earlier is ignored:: -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 12:59:10 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 12:59:10 +0100 Subject: [Python-checkins] distutils2: assume --description work Message-ID: tarek.ziade pushed f9a4f658ba67 to distutils2: http://hg.python.org/distutils2/rev/f9a4f658ba67 changeset: 904:f9a4f658ba67 user: Gael Pasgrimaud date: Sat Jan 29 11:09:11 2011 +0100 summary: assume --description work files: distutils2/tests/test_config.py diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -289,7 +289,9 @@ os.mkdir(pkg) self.write_file(os.path.join(pkg, '__init__.py'), '#') - dist = self.run_setup('--version') + dist = self.run_setup('--description') + self.assertIn('yeah\nyeah\n', sys.stdout.getvalue()) + cmd = sdist(dist) cmd.finalize_options() cmd.get_file_list() -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 12:59:10 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 12:59:10 +0100 Subject: [Python-checkins] distutils2: add docstring to all public api of DistributionMetadata Message-ID: tarek.ziade pushed c3cf81fc64db to distutils2: http://hg.python.org/distutils2/rev/c3cf81fc64db changeset: 903:c3cf81fc64db user: Gael Pasgrimaud date: Fri Jan 28 18:39:05 2011 +0100 summary: add docstring to all public api of DistributionMetadata files: distutils2/metadata.py diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -300,13 +300,16 @@ # Public API # def get_fullname(self): + """Return the distribution name with version""" return '%s-%s' % (self['Name'], self['Version']) def is_metadata_field(self, name): + """return True if name is a valid metadata key""" name = self._convert_name(name) return name in _ALL_FIELDS def read(self, filepath): + """Read the metadata values from a file path.""" self.read_file(open(filepath)) def read_file(self, fileob): @@ -501,12 +504,15 @@ return missing, warnings def keys(self): + """Dict like api""" return _version2fieldlist(self.version) def values(self): + """Dict like api""" return [self[key] for key in self.keys()] def items(self): + """Dict like api""" return [(key, self[key]) for key in self.keys()] -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 12:59:10 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 12:59:10 +0100 Subject: [Python-checkins] distutils2: add --metadata option Message-ID: tarek.ziade pushed 35838832577a to distutils2: http://hg.python.org/distutils2/rev/35838832577a changeset: 905:35838832577a user: Gael Pasgrimaud date: Sat Jan 29 12:33:00 2011 +0100 summary: add --metadata option files: distutils2/run.py diff --git a/distutils2/run.py b/distutils2/run.py --- a/distutils2/run.py +++ b/distutils2/run.py @@ -124,6 +124,10 @@ action="store_true", dest="version", default=False, help="Prints out the version of Distutils2 and exits.") + parser.add_option("-m", "--metadata", + action="append", dest="metadata", default=[], + help="List METADATA metadata or 'all' for all metadatas.") + parser.add_option("-s", "--search", action="store", dest="search", default=None, help="Search for installed distributions.") @@ -141,6 +145,31 @@ print('Distutils2 %s' % __version__) # sys.exit(0) + if len(options.metadata): + from distutils2.dist import Distribution + dist = Distribution() + dist.parse_config_files() + metadata = dist.metadata + + if 'all' in options.metadata: + keys = metadata.keys() + else: + keys = options.metadata + if len(keys) == 1: + print metadata[keys[0]] + sys.exit(0) + + for key in keys: + if key in metadata: + print(metadata._convert_name(key)+':') + value = metadata[key] + if isinstance(value, list): + for v in value: + print(' '+v) + else: + print(' '+value.replace('\n', '\n ')) + sys.exit(0) + if options.search is not None: search = options.search.lower() for dist in get_distributions(use_egg_info=True): -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 12:59:10 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 12:59:10 +0100 Subject: [Python-checkins] distutils2: simplified the package_dir option - just one root dir allowed Message-ID: tarek.ziade pushed f7b8081c17fc to distutils2: http://hg.python.org/distutils2/rev/f7b8081c17fc changeset: 906:f7b8081c17fc tag: tip user: Tarek Ziade date: Sat Jan 29 12:59:03 2011 +0100 summary: simplified the package_dir option - just one root dir allowed files: distutils2/command/build_py.py distutils2/config.py distutils2/install.py distutils2/run.py distutils2/tests/test_command_build_ext.py distutils2/tests/test_command_build_py.py distutils2/tests/test_config.py diff --git a/distutils2/command/build_py.py b/distutils2/command/build_py.py --- a/distutils2/command/build_py.py +++ b/distutils2/command/build_py.py @@ -66,10 +66,9 @@ self.packages = self.distribution.packages self.py_modules = self.distribution.py_modules self.package_data = self.distribution.package_data - self.package_dir = {} - if self.distribution.package_dir: - for name, path in self.distribution.package_dir.iteritems(): - self.package_dir[name] = convert_path(path) + self.package_dir = None + if self.distribution.package_dir is not None: + self.package_dir = convert_path(self.distribution.package_dir) self.data_files = self.get_data_files() # Ick, copied straight from install_lib.py (fancy_getopt needs a @@ -179,41 +178,14 @@ """Return the directory, relative to the top of the source distribution, where package 'package' should be found (at least according to the 'package_dir' option, if any).""" + path = package.split('.') + if self.package_dir is not None: + path.insert(0, self.package_dir) - path = package.split('.') + if len(path) > 0: + return os.path.join(*path) - if not self.package_dir: - if path: - return os.path.join(*path) - else: - return '' - else: - tail = [] - while path: - try: - pdir = self.package_dir['.'.join(path)] - except KeyError: - tail.insert(0, path[-1]) - del path[-1] - else: - tail.insert(0, pdir) - return os.path.join(*tail) - else: - # Oops, got all the way through 'path' without finding a - # match in package_dir. If package_dir defines a directory - # for the root (nameless) package, then fallback on it; - # otherwise, we might as well have not consulted - # package_dir at all, as we just use the directory implied - # by 'tail' (which should be the same as the original value - # of 'path' at this point). - pdir = self.package_dir.get('') - if pdir is not None: - tail.insert(0, pdir) - - if tail: - return os.path.join(*tail) - else: - return '' + return '' def check_package(self, package, package_dir): """Helper function for `find_package_modules()` and `find_modules()'. diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -138,16 +138,12 @@ files = dict([(key, self._multiline(value)) for key, value in content['files'].iteritems()]) self.dist.packages = [] - self.dist.package_dir = {} - + self.dist.package_dir = pkg_dir = files.get('packages_root') packages = files.get('packages', []) if isinstance(packages, str): packages = [packages] for package in packages: - if ':' in package: - dir_, package = package.split(':') - self.dist.package_dir[package] = dir_ self.dist.packages.append(package) self.dist.py_modules = files.get('modules', []) diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -208,6 +208,13 @@ infos[key].extend(new_infos[key]) +def remove(project_name): + """Removes a single project from the installation""" + pass + + + + def main(**attrs): if 'script_args' not in attrs: import sys diff --git a/distutils2/run.py b/distutils2/run.py --- a/distutils2/run.py +++ b/distutils2/run.py @@ -109,6 +109,7 @@ except (DistutilsError, CCompilerError), msg: + raise raise SystemExit, "error: " + str(msg) return dist diff --git a/distutils2/tests/test_command_build_ext.py b/distutils2/tests/test_command_build_ext.py --- a/distutils2/tests/test_command_build_ext.py +++ b/distutils2/tests/test_command_build_ext.py @@ -289,7 +289,7 @@ # inplace = 0, cmd.package = 'bar' build_py = cmd.get_finalized_command('build_py') - build_py.package_dir = {'': 'bar'} + build_py.package_dir = 'bar' path = cmd.get_ext_fullpath('foo') # checking that the last directory is the build_dir path = os.path.split(path)[0] @@ -318,7 +318,7 @@ dist = Distribution() cmd = build_ext(dist) cmd.inplace = 1 - cmd.distribution.package_dir = {'': 'src'} + cmd.distribution.package_dir = 'src' cmd.distribution.packages = ['lxml', 'lxml.html'] curdir = os.getcwd() wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext) @@ -334,7 +334,7 @@ # building twisted.runner.portmap not inplace build_py = cmd.get_finalized_command('build_py') - build_py.package_dir = {} + build_py.package_dir = None cmd.distribution.packages = ['twisted', 'twisted.runner.portmap'] path = cmd.get_ext_fullpath('twisted.runner.portmap') wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner', diff --git a/distutils2/tests/test_command_build_py.py b/distutils2/tests/test_command_build_py.py --- a/distutils2/tests/test_command_build_py.py +++ b/distutils2/tests/test_command_build_py.py @@ -17,12 +17,14 @@ def test_package_data(self): sources = self.mkdtemp() - f = open(os.path.join(sources, "__init__.py"), "w") + pkg_dir = os.path.join(sources, 'pkg') + os.mkdir(pkg_dir) + f = open(os.path.join(pkg_dir, "__init__.py"), "w") try: f.write("# Pretend this is a package.") finally: f.close() - f = open(os.path.join(sources, "README.txt"), "w") + f = open(os.path.join(pkg_dir, "README.txt"), "w") try: f.write("Info about this package") finally: @@ -31,8 +33,9 @@ destination = self.mkdtemp() dist = Distribution({"packages": ["pkg"], - "package_dir": {"pkg": sources}}) + "package_dir": sources}) # script_name need not exist, it just need to be initialized + dist.script_name = os.path.join(sources, "setup.py") dist.command_obj["build"] = support.DummyCommand( force=0, @@ -42,7 +45,7 @@ use_2to3=False) dist.packages = ["pkg"] dist.package_data = {"pkg": ["README.txt"]} - dist.package_dir = {"pkg": sources} + dist.package_dir = sources cmd = build_py(dist) cmd.compile = 1 @@ -68,19 +71,20 @@ # create the distribution files. sources = self.mkdtemp() - open(os.path.join(sources, "__init__.py"), "w").close() - - testdir = os.path.join(sources, "doc") + pkg = os.path.join(sources, 'pkg') + os.mkdir(pkg) + open(os.path.join(pkg, "__init__.py"), "w").close() + testdir = os.path.join(pkg, "doc") os.mkdir(testdir) open(os.path.join(testdir, "testfile"), "w").close() os.chdir(sources) old_stdout = sys.stdout - sys.stdout = StringIO.StringIO() + #sys.stdout = StringIO.StringIO() try: dist = Distribution({"packages": ["pkg"], - "package_dir": {"pkg": ""}, + "package_dir": sources, "package_data": {"pkg": ["doc/*"]}}) # script_name need not exist, it just need to be initialized dist.script_name = os.path.join(sources, "setup.py") @@ -89,7 +93,7 @@ try: dist.run_commands() - except DistutilsFileError: + except DistutilsFileError, e: self.fail("failed package_data test when package_dir is ''") finally: # Restore state. diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -49,9 +49,11 @@ Fork in progress, http://bitbucket.org/Merwok/sample-distutils2-project [files] +packages_root = src + packages = one - src:two - src2:three + two + three modules = haven @@ -140,6 +142,7 @@ opts.update(kwargs) self.write_file('setup.cfg', SETUP_CFG % opts) + def run_setup(self, *args): # run setup with args sys.stdout = StringIO() @@ -198,7 +201,6 @@ 'http://bitbucket.org/Merwok/sample-distutils2-project')] self.assertEqual(dist.metadata['Project-Url'], urls) - self.assertEqual(dist.packages, ['one', 'two', 'three']) self.assertEqual(dist.py_modules, ['haven']) self.assertEqual(dist.package_data, {'cheese': 'data/templates/*'}) @@ -206,7 +208,8 @@ [('bitmaps ', ['bm/b1.gif', 'bm/b2.gif']), ('config ', ['cfg/data.cfg']), ('/etc/init.d ', ['init-script'])]) - self.assertEqual(dist.package_dir['two'], 'src') + + self.assertEqual(dist.package_dir, 'src') # Make sure we get the foo command loaded. We use a string comparison # instead of assertIsInstance because the class is not the same when @@ -262,7 +265,9 @@ os.mkdir('bin') self.write_file(os.path.join('bin', 'taunt'), '#') - for pkg in ('one', 'src', 'src2'): + os.mkdir('src') + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) os.mkdir(pkg) self.write_file(os.path.join(pkg, '__init__.py'), '#') @@ -285,7 +290,9 @@ os.mkdir('bin') self.write_file(os.path.join('bin', 'taunt'), '#') - for pkg in ('one', 'src', 'src2'): + os.mkdir('src') + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) os.mkdir(pkg) self.write_file(os.path.join(pkg, '__init__.py'), '#') @@ -310,8 +317,10 @@ self.write_file(os.path.join('scripts', 'find-coconuts'), '#') os.mkdir('bin') self.write_file(os.path.join('bin', 'taunt'), '#') + os.mkdir('src') - for pkg in ('one', 'src', 'src2'): + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) os.mkdir(pkg) self.write_file(os.path.join(pkg, '__init__.py'), '#') -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 14:21:48 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 14:21:48 +0100 Subject: [Python-checkins] distutils2: Better handling of multi lines fields of the setup.cfg. Message-ID: tarek.ziade pushed a342826d7308 to distutils2: http://hg.python.org/distutils2/rev/a342826d7308 changeset: 907:a342826d7308 parent: 896:272155a17d56 user: Julien Miotte date: Fri Jan 28 12:15:54 2011 +0100 summary: Better handling of multi lines fields of the setup.cfg. Now single line values can be written on the same line as the field name. For instance, the line: project_url = spam,http://spam.spam Was causing python -m distutils.run sdist with this error: ValueError: need more than 1 value to unpack Now, every field that should be of multiple use is handled as a list. files: distutils2/config.py distutils2/metadata.py diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -76,10 +76,9 @@ return value def _multiline(self, value): - if '\n' in value: - value = [v for v in - [v.strip() for v in value.split('\n')] - if v != ''] + value = [v for v in + [v.strip() for v in value.split('\n')] + if v != ''] return value def _read_setup_cfg(self, parser): @@ -100,7 +99,9 @@ if 'metadata' in content: for key, value in content['metadata'].iteritems(): key = key.replace('_', '-') - value = self._multiline(value) + if metadata.is_multi_field(key): + value = self._multiline(value) + if key == 'project-url': value = [(label.strip(), url.strip()) for label, url in diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -298,6 +298,10 @@ name = self._convert_name(name) return name in _ALL_FIELDS + def is_multi_field(self, name): + name = self._convert_name(name) + return name in _LISTFIELDS + def read(self, filepath): self.read_file(open(filepath)) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 14:21:48 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 14:21:48 +0100 Subject: [Python-checkins] distutils2: Adding methods to generate a distutils setup.py file reading the setup.cfg. Message-ID: tarek.ziade pushed 0b44306763cf to distutils2: http://hg.python.org/distutils2/rev/0b44306763cf changeset: 908:0b44306763cf user: Julien Miotte date: Fri Jan 28 17:53:42 2011 +0100 summary: Adding methods to generate a distutils setup.py file reading the setup.cfg. That way, distribution maintainers will be able to offer distutils & distutils2 compatibility, without having to maintain the same information in two files. The only that needs to be maintained is the setup.cfg. Indeed, the setup.py reads the setup.cfg file every time it is called, to determine which are the correct args to pass on to distutils.core.setup(). files: distutils2/util.py diff --git a/distutils2/util.py b/distutils2/util.py --- a/distutils2/util.py +++ b/distutils2/util.py @@ -15,6 +15,7 @@ from copy import copy from fnmatch import fnmatchcase from ConfigParser import RawConfigParser +from inspect import getsource from distutils2.errors import (DistutilsPlatformError, DistutilsFileError, DistutilsByteCompileError, DistutilsExecError) @@ -1127,3 +1128,116 @@ """ Issues a call to util.run_2to3. """ return run_2to3(files, doctests_only, self.fixer_names, self.options, self.explicit) + + +def generate_distutils_kwargs_from_setup_cfg(file='setup.cfg'): + """ Distutils2 to distutils1 compatibility util. + + This method uses an existing setup.cfg to generate a dictionnary of + keywords that can be used by distutils.core.setup(kwargs**). + + :param file: + The setup.cfg path. + :raises DistutilsFileError: + When the setup.cfg file is not found. + + """ + # We need to declare the following constants here so that it's easier to + # generate the setup.py afterwards, using inspect.getsource. + D1_D2_SETUP_ARGS = { + # D1 name : (D2_section, D2_name) + "name" : ("metadata",), + "version" : ("metadata",), + "author" : ("metadata",), + "author_email" : ("metadata",), + "maintainer" : ("metadata",), + "maintainer_email" : ("metadata",), + "url" : ("metadata", "home_page"), + "description" : ("metadata", "summary"), + "long_description" : ("metadata", "description"), + "download-url" : ("metadata",), + "classifiers" : ("metadata", "classifier"), + "platforms" : ("metadata", "platform"), # Needs testing + "license" : ("metadata",), + "requires" : ("metadata", "requires_dist"), + "provides" : ("metadata", "provides_dist"), # Needs testing + "obsoletes" : ("metadata", "obsoletes_dist"), # Needs testing + + "packages" : ("files",), + "scripts" : ("files",), + "py_modules" : ("files", "modules"), # Needs testing + } + + MULTI_FIELDS = ("classifiers", + "requires", + "platforms", + "packages", + "scripts") + + def has_get_option(config, section, option): + if config.has_option(section, option): + return config.get(section, option) + elif config.has_option(section, option.replace('_', '-')): + return config.get(section, option.replace('_', '-')) + else: + return False + + # The method source code really starts here. + config = RawConfigParser() + if not os.path.exists(file): + raise DistutilsFileError("file '%s' does not exist" % + os.path.abspath(file)) + config.read(file) + + kwargs = {} + for arg in D1_D2_SETUP_ARGS: + if len(D1_D2_SETUP_ARGS[arg]) == 2: + # The distutils field name is different than distutils2's. + section, option = D1_D2_SETUP_ARGS[arg] + + elif len(D1_D2_SETUP_ARGS[arg]) == 1: + # The distutils field name is the same thant distutils2's. + section = D1_D2_SETUP_ARGS[arg][0] + option = arg + + in_cfg_value = has_get_option(config, section, option) + if not in_cfg_value: + # There is no such option in the setup.cfg + continue + + if arg == "long_description": + filename = has_get_option("description_file") + if filename: + in_cfg_value = open(filename).read() + + if arg in MULTI_FIELDS: + # Special behaviour when we have a multi line option + if "\n" in in_cfg_value: + in_cfg_value = in_cfg_value.strip().split('\n') + else: + in_cfg_value = list((in_cfg_value,)) + + kwargs[arg] = in_cfg_value + + return kwargs + + +def generate_distutils_setup_py(): + """ Generate a distutils compatible setup.py using an existing setup.cfg. + + :raises DistutilsFileError: + When a setup.py already exists. + """ + if os.path.exists("setup.py"): + raise DistutilsFileError("A pre existing setup.py file exists") + + handle = open("setup.py", "w") + handle.write("# Distutils script using distutils2 setup.cfg to call the\n") + handle.write("# distutils.core.setup() with the right args.\n\n\n") + handle.write("import os\n") + handle.write("from distutils.core import setup\n") + handle.write("from ConfigParser import RawConfigParser\n\n") + handle.write(getsource(generate_distutils_kwargs_from_setup_cfg)) + handle.write("\n\nkwargs = generate_distutils_kwargs_from_setup_cfg()\n") + handle.write("setup(**kwargs)") + handle.close() -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 14:21:48 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 14:21:48 +0100 Subject: [Python-checkins] distutils2: 'Supported-Platform' was missing from the list of multiple use fields. Message-ID: tarek.ziade pushed 5603e1bc5442 to distutils2: http://hg.python.org/distutils2/rev/5603e1bc5442 changeset: 909:5603e1bc5442 user: Julien Miotte date: Fri Jan 28 18:42:44 2011 +0100 summary: 'Supported-Platform' was missing from the list of multiple use fields. files: distutils2/metadata.py diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -172,7 +172,7 @@ _LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes', 'Requires', 'Provides', 'Obsoletes-Dist', 'Provides-Dist', 'Requires-Dist', 'Requires-External', - 'Project-URL') + 'Project-URL', 'Supported-Platform') _LISTTUPLEFIELDS = ('Project-URL',) _ELEMENTSFIELD = ('Keywords',) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 14:21:48 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 14:21:48 +0100 Subject: [Python-checkins] distutils2: Fixing: the long-description field was never taken into account Message-ID: tarek.ziade pushed 7b032f44cf80 to distutils2: http://hg.python.org/distutils2/rev/7b032f44cf80 changeset: 910:7b032f44cf80 user: Julien Miotte date: Sat Jan 29 02:48:08 2011 +0100 summary: Fixing: the long-description field was never taken into account files: distutils2/util.py patch diff --git a/distutils2/util.py b/distutils2/util.py --- a/distutils2/util.py +++ b/distutils2/util.py @@ -1203,12 +1203,13 @@ in_cfg_value = has_get_option(config, section, option) if not in_cfg_value: # There is no such option in the setup.cfg - continue - - if arg == "long_description": - filename = has_get_option("description_file") - if filename: - in_cfg_value = open(filename).read() + if arg == "long_description": + filename = has_get_option(config, section, "description_file") + print "We have a filename", filename + if filename: + in_cfg_value = open(filename).read() + else: + continue if arg in MULTI_FIELDS: # Special behaviour when we have a multi line option diff --git a/patch b/patch new file mode 100644 --- /dev/null +++ b/patch @@ -0,0 +1,23 @@ +diff -r 5603e1bc5442 distutils2/util.py +--- a/distutils2/util.py Fri Jan 28 18:42:44 2011 +0100 ++++ b/distutils2/util.py Sat Jan 29 02:39:55 2011 +0100 +@@ -1203,12 +1203,13 @@ + in_cfg_value = has_get_option(config, section, option) + if not in_cfg_value: + # There is no such option in the setup.cfg +- continue +- +- if arg == "long_description": +- filename = has_get_option("description_file") +- if filename: +- in_cfg_value = open(filename).read() ++ if arg == "long_description": ++ filename = has_get_option(config, section, "description_file") ++ print "We have a filename", filename ++ if filename: ++ in_cfg_value = open(filename).read() ++ else: ++ continue + + if arg in MULTI_FIELDS: + # Special behaviour when we have a multi line option -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 14:21:48 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 14:21:48 +0100 Subject: [Python-checkins] distutils2: merge Julien's clone Message-ID: tarek.ziade pushed efe36550d8cc to distutils2: http://hg.python.org/distutils2/rev/efe36550d8cc changeset: 911:efe36550d8cc parent: 905:35838832577a parent: 910:7b032f44cf80 user: Gael Pasgrimaud date: Sat Jan 29 14:02:17 2011 +0100 summary: merge Julien's clone files: distutils2/config.py distutils2/metadata.py diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -76,10 +76,9 @@ return value def _multiline(self, value): - if '\n' in value: - value = [v for v in - [v.strip() for v in value.split('\n')] - if v != ''] + value = [v for v in + [v.strip() for v in value.split('\n')] + if v != ''] return value def _read_setup_cfg(self, parser): @@ -100,7 +99,9 @@ if 'metadata' in content: for key, value in content['metadata'].iteritems(): key = key.replace('_', '-') - value = self._multiline(value) + if metadata.is_multi_field(key): + value = self._multiline(value) + if key == 'project-url': value = [(label.strip(), url.strip()) for label, url in diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -174,7 +174,7 @@ _LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes', 'Requires', 'Provides', 'Obsoletes-Dist', 'Provides-Dist', 'Requires-Dist', 'Requires-External', - 'Project-URL') + 'Project-URL', 'Supported-Platform') _LISTTUPLEFIELDS = ('Project-URL',) _ELEMENTSFIELD = ('Keywords',) @@ -308,6 +308,10 @@ name = self._convert_name(name) return name in _ALL_FIELDS + def is_multi_field(self, name): + name = self._convert_name(name) + return name in _LISTFIELDS + def read(self, filepath): """Read the metadata values from a file path.""" self.read_file(open(filepath)) diff --git a/distutils2/util.py b/distutils2/util.py --- a/distutils2/util.py +++ b/distutils2/util.py @@ -15,6 +15,7 @@ from copy import copy from fnmatch import fnmatchcase from ConfigParser import RawConfigParser +from inspect import getsource from distutils2.errors import (DistutilsPlatformError, DistutilsFileError, DistutilsByteCompileError, DistutilsExecError) @@ -1127,3 +1128,117 @@ """ Issues a call to util.run_2to3. """ return run_2to3(files, doctests_only, self.fixer_names, self.options, self.explicit) + + +def generate_distutils_kwargs_from_setup_cfg(file='setup.cfg'): + """ Distutils2 to distutils1 compatibility util. + + This method uses an existing setup.cfg to generate a dictionnary of + keywords that can be used by distutils.core.setup(kwargs**). + + :param file: + The setup.cfg path. + :raises DistutilsFileError: + When the setup.cfg file is not found. + + """ + # We need to declare the following constants here so that it's easier to + # generate the setup.py afterwards, using inspect.getsource. + D1_D2_SETUP_ARGS = { + # D1 name : (D2_section, D2_name) + "name" : ("metadata",), + "version" : ("metadata",), + "author" : ("metadata",), + "author_email" : ("metadata",), + "maintainer" : ("metadata",), + "maintainer_email" : ("metadata",), + "url" : ("metadata", "home_page"), + "description" : ("metadata", "summary"), + "long_description" : ("metadata", "description"), + "download-url" : ("metadata",), + "classifiers" : ("metadata", "classifier"), + "platforms" : ("metadata", "platform"), # Needs testing + "license" : ("metadata",), + "requires" : ("metadata", "requires_dist"), + "provides" : ("metadata", "provides_dist"), # Needs testing + "obsoletes" : ("metadata", "obsoletes_dist"), # Needs testing + + "packages" : ("files",), + "scripts" : ("files",), + "py_modules" : ("files", "modules"), # Needs testing + } + + MULTI_FIELDS = ("classifiers", + "requires", + "platforms", + "packages", + "scripts") + + def has_get_option(config, section, option): + if config.has_option(section, option): + return config.get(section, option) + elif config.has_option(section, option.replace('_', '-')): + return config.get(section, option.replace('_', '-')) + else: + return False + + # The method source code really starts here. + config = RawConfigParser() + if not os.path.exists(file): + raise DistutilsFileError("file '%s' does not exist" % + os.path.abspath(file)) + config.read(file) + + kwargs = {} + for arg in D1_D2_SETUP_ARGS: + if len(D1_D2_SETUP_ARGS[arg]) == 2: + # The distutils field name is different than distutils2's. + section, option = D1_D2_SETUP_ARGS[arg] + + elif len(D1_D2_SETUP_ARGS[arg]) == 1: + # The distutils field name is the same thant distutils2's. + section = D1_D2_SETUP_ARGS[arg][0] + option = arg + + in_cfg_value = has_get_option(config, section, option) + if not in_cfg_value: + # There is no such option in the setup.cfg + if arg == "long_description": + filename = has_get_option(config, section, "description_file") + print "We have a filename", filename + if filename: + in_cfg_value = open(filename).read() + else: + continue + + if arg in MULTI_FIELDS: + # Special behaviour when we have a multi line option + if "\n" in in_cfg_value: + in_cfg_value = in_cfg_value.strip().split('\n') + else: + in_cfg_value = list((in_cfg_value,)) + + kwargs[arg] = in_cfg_value + + return kwargs + + +def generate_distutils_setup_py(): + """ Generate a distutils compatible setup.py using an existing setup.cfg. + + :raises DistutilsFileError: + When a setup.py already exists. + """ + if os.path.exists("setup.py"): + raise DistutilsFileError("A pre existing setup.py file exists") + + handle = open("setup.py", "w") + handle.write("# Distutils script using distutils2 setup.cfg to call the\n") + handle.write("# distutils.core.setup() with the right args.\n\n\n") + handle.write("import os\n") + handle.write("from distutils.core import setup\n") + handle.write("from ConfigParser import RawConfigParser\n\n") + handle.write(getsource(generate_distutils_kwargs_from_setup_cfg)) + handle.write("\n\nkwargs = generate_distutils_kwargs_from_setup_cfg()\n") + handle.write("setup(**kwargs)") + handle.close() diff --git a/patch b/patch new file mode 100644 --- /dev/null +++ b/patch @@ -0,0 +1,23 @@ +diff -r 5603e1bc5442 distutils2/util.py +--- a/distutils2/util.py Fri Jan 28 18:42:44 2011 +0100 ++++ b/distutils2/util.py Sat Jan 29 02:39:55 2011 +0100 +@@ -1203,12 +1203,13 @@ + in_cfg_value = has_get_option(config, section, option) + if not in_cfg_value: + # There is no such option in the setup.cfg +- continue +- +- if arg == "long_description": +- filename = has_get_option("description_file") +- if filename: +- in_cfg_value = open(filename).read() ++ if arg == "long_description": ++ filename = has_get_option(config, section, "description_file") ++ print "We have a filename", filename ++ if filename: ++ in_cfg_value = open(filename).read() ++ else: ++ continue + + if arg in MULTI_FIELDS: + # Special behaviour when we have a multi line option -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 14:21:48 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 14:21:48 +0100 Subject: [Python-checkins] distutils2: merge to lastest head Message-ID: tarek.ziade pushed edda0a74267a to distutils2: http://hg.python.org/distutils2/rev/edda0a74267a changeset: 912:edda0a74267a parent: 911:efe36550d8cc parent: 906:f7b8081c17fc user: Gael Pasgrimaud date: Sat Jan 29 14:03:03 2011 +0100 summary: merge to lastest head files: distutils2/config.py diff --git a/distutils2/command/build_py.py b/distutils2/command/build_py.py --- a/distutils2/command/build_py.py +++ b/distutils2/command/build_py.py @@ -66,10 +66,9 @@ self.packages = self.distribution.packages self.py_modules = self.distribution.py_modules self.package_data = self.distribution.package_data - self.package_dir = {} - if self.distribution.package_dir: - for name, path in self.distribution.package_dir.iteritems(): - self.package_dir[name] = convert_path(path) + self.package_dir = None + if self.distribution.package_dir is not None: + self.package_dir = convert_path(self.distribution.package_dir) self.data_files = self.get_data_files() # Ick, copied straight from install_lib.py (fancy_getopt needs a @@ -179,41 +178,14 @@ """Return the directory, relative to the top of the source distribution, where package 'package' should be found (at least according to the 'package_dir' option, if any).""" + path = package.split('.') + if self.package_dir is not None: + path.insert(0, self.package_dir) - path = package.split('.') + if len(path) > 0: + return os.path.join(*path) - if not self.package_dir: - if path: - return os.path.join(*path) - else: - return '' - else: - tail = [] - while path: - try: - pdir = self.package_dir['.'.join(path)] - except KeyError: - tail.insert(0, path[-1]) - del path[-1] - else: - tail.insert(0, pdir) - return os.path.join(*tail) - else: - # Oops, got all the way through 'path' without finding a - # match in package_dir. If package_dir defines a directory - # for the root (nameless) package, then fallback on it; - # otherwise, we might as well have not consulted - # package_dir at all, as we just use the directory implied - # by 'tail' (which should be the same as the original value - # of 'path' at this point). - pdir = self.package_dir.get('') - if pdir is not None: - tail.insert(0, pdir) - - if tail: - return os.path.join(*tail) - else: - return '' + return '' def check_package(self, package, package_dir): """Helper function for `find_package_modules()` and `find_modules()'. diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -139,16 +139,12 @@ files = dict([(key, self._multiline(value)) for key, value in content['files'].iteritems()]) self.dist.packages = [] - self.dist.package_dir = {} - + self.dist.package_dir = pkg_dir = files.get('packages_root') packages = files.get('packages', []) if isinstance(packages, str): packages = [packages] for package in packages: - if ':' in package: - dir_, package = package.split(':') - self.dist.package_dir[package] = dir_ self.dist.packages.append(package) self.dist.py_modules = files.get('modules', []) diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -208,6 +208,13 @@ infos[key].extend(new_infos[key]) +def remove(project_name): + """Removes a single project from the installation""" + pass + + + + def main(**attrs): if 'script_args' not in attrs: import sys diff --git a/distutils2/run.py b/distutils2/run.py --- a/distutils2/run.py +++ b/distutils2/run.py @@ -109,6 +109,7 @@ except (DistutilsError, CCompilerError), msg: + raise raise SystemExit, "error: " + str(msg) return dist diff --git a/distutils2/tests/test_command_build_ext.py b/distutils2/tests/test_command_build_ext.py --- a/distutils2/tests/test_command_build_ext.py +++ b/distutils2/tests/test_command_build_ext.py @@ -289,7 +289,7 @@ # inplace = 0, cmd.package = 'bar' build_py = cmd.get_finalized_command('build_py') - build_py.package_dir = {'': 'bar'} + build_py.package_dir = 'bar' path = cmd.get_ext_fullpath('foo') # checking that the last directory is the build_dir path = os.path.split(path)[0] @@ -318,7 +318,7 @@ dist = Distribution() cmd = build_ext(dist) cmd.inplace = 1 - cmd.distribution.package_dir = {'': 'src'} + cmd.distribution.package_dir = 'src' cmd.distribution.packages = ['lxml', 'lxml.html'] curdir = os.getcwd() wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext) @@ -334,7 +334,7 @@ # building twisted.runner.portmap not inplace build_py = cmd.get_finalized_command('build_py') - build_py.package_dir = {} + build_py.package_dir = None cmd.distribution.packages = ['twisted', 'twisted.runner.portmap'] path = cmd.get_ext_fullpath('twisted.runner.portmap') wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner', diff --git a/distutils2/tests/test_command_build_py.py b/distutils2/tests/test_command_build_py.py --- a/distutils2/tests/test_command_build_py.py +++ b/distutils2/tests/test_command_build_py.py @@ -17,12 +17,14 @@ def test_package_data(self): sources = self.mkdtemp() - f = open(os.path.join(sources, "__init__.py"), "w") + pkg_dir = os.path.join(sources, 'pkg') + os.mkdir(pkg_dir) + f = open(os.path.join(pkg_dir, "__init__.py"), "w") try: f.write("# Pretend this is a package.") finally: f.close() - f = open(os.path.join(sources, "README.txt"), "w") + f = open(os.path.join(pkg_dir, "README.txt"), "w") try: f.write("Info about this package") finally: @@ -31,8 +33,9 @@ destination = self.mkdtemp() dist = Distribution({"packages": ["pkg"], - "package_dir": {"pkg": sources}}) + "package_dir": sources}) # script_name need not exist, it just need to be initialized + dist.script_name = os.path.join(sources, "setup.py") dist.command_obj["build"] = support.DummyCommand( force=0, @@ -42,7 +45,7 @@ use_2to3=False) dist.packages = ["pkg"] dist.package_data = {"pkg": ["README.txt"]} - dist.package_dir = {"pkg": sources} + dist.package_dir = sources cmd = build_py(dist) cmd.compile = 1 @@ -68,19 +71,20 @@ # create the distribution files. sources = self.mkdtemp() - open(os.path.join(sources, "__init__.py"), "w").close() - - testdir = os.path.join(sources, "doc") + pkg = os.path.join(sources, 'pkg') + os.mkdir(pkg) + open(os.path.join(pkg, "__init__.py"), "w").close() + testdir = os.path.join(pkg, "doc") os.mkdir(testdir) open(os.path.join(testdir, "testfile"), "w").close() os.chdir(sources) old_stdout = sys.stdout - sys.stdout = StringIO.StringIO() + #sys.stdout = StringIO.StringIO() try: dist = Distribution({"packages": ["pkg"], - "package_dir": {"pkg": ""}, + "package_dir": sources, "package_data": {"pkg": ["doc/*"]}}) # script_name need not exist, it just need to be initialized dist.script_name = os.path.join(sources, "setup.py") @@ -89,7 +93,7 @@ try: dist.run_commands() - except DistutilsFileError: + except DistutilsFileError, e: self.fail("failed package_data test when package_dir is ''") finally: # Restore state. diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -49,9 +49,11 @@ Fork in progress, http://bitbucket.org/Merwok/sample-distutils2-project [files] +packages_root = src + packages = one - src:two - src2:three + two + three modules = haven @@ -140,6 +142,7 @@ opts.update(kwargs) self.write_file('setup.cfg', SETUP_CFG % opts) + def run_setup(self, *args): # run setup with args sys.stdout = StringIO() @@ -198,7 +201,6 @@ 'http://bitbucket.org/Merwok/sample-distutils2-project')] self.assertEqual(dist.metadata['Project-Url'], urls) - self.assertEqual(dist.packages, ['one', 'two', 'three']) self.assertEqual(dist.py_modules, ['haven']) self.assertEqual(dist.package_data, {'cheese': 'data/templates/*'}) @@ -206,7 +208,8 @@ [('bitmaps ', ['bm/b1.gif', 'bm/b2.gif']), ('config ', ['cfg/data.cfg']), ('/etc/init.d ', ['init-script'])]) - self.assertEqual(dist.package_dir['two'], 'src') + + self.assertEqual(dist.package_dir, 'src') # Make sure we get the foo command loaded. We use a string comparison # instead of assertIsInstance because the class is not the same when @@ -262,7 +265,9 @@ os.mkdir('bin') self.write_file(os.path.join('bin', 'taunt'), '#') - for pkg in ('one', 'src', 'src2'): + os.mkdir('src') + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) os.mkdir(pkg) self.write_file(os.path.join(pkg, '__init__.py'), '#') @@ -285,7 +290,9 @@ os.mkdir('bin') self.write_file(os.path.join('bin', 'taunt'), '#') - for pkg in ('one', 'src', 'src2'): + os.mkdir('src') + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) os.mkdir(pkg) self.write_file(os.path.join(pkg, '__init__.py'), '#') @@ -310,8 +317,10 @@ self.write_file(os.path.join('scripts', 'find-coconuts'), '#') os.mkdir('bin') self.write_file(os.path.join('bin', 'taunt'), '#') + os.mkdir('src') - for pkg in ('one', 'src', 'src2'): + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) os.mkdir(pkg) self.write_file(os.path.join(pkg, '__init__.py'), '#') -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 14:21:48 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 14:21:48 +0100 Subject: [Python-checkins] distutils2: make sure we don't convert packages_root into a multiline value Message-ID: tarek.ziade pushed 317bff9e4495 to distutils2: http://hg.python.org/distutils2/rev/317bff9e4495 changeset: 913:317bff9e4495 tag: tip user: Tarek Ziade date: Sat Jan 29 14:21:43 2011 +0100 summary: make sure we don't convert packages_root into a multiline value files: distutils2/config.py diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -135,11 +135,18 @@ if metadata.is_metadata_field(key): metadata[key] = self._convert_metadata(key, value) + if 'files' in content: - files = dict([(key, self._multiline(value)) + def _convert(key, value): + if key not in ('packages_root',): + value = self._multiline(value) + return value + + files = dict([(key, _convert(key, value)) for key, value in content['files'].iteritems()]) self.dist.packages = [] self.dist.package_dir = pkg_dir = files.get('packages_root') + packages = files.get('packages', []) if isinstance(packages, str): packages = [packages] -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 14:24:34 2011 From: python-checkins at python.org (giampaolo.rodola) Date: Sat, 29 Jan 2011 14:24:34 +0100 (CET) Subject: [Python-checkins] r88230 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110129132434.203EEEE9BD@mail.python.org> Author: giampaolo.rodola Date: Sat Jan 29 14:24:33 2011 New Revision: 88230 Log: fix reference to issue where the addition of select.PIPE_BUF was discussed Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Sat Jan 29 14:24:33 2011 @@ -1314,7 +1314,7 @@ >>> select.PIPE_BUF 512 -(Available on Unix systems. Patch by S?bastien Sabl? in :issue:`85554`) +(Available on Unix systems. Patch by S?bastien Sabl? in :issue:`9862`) gzip and zipfile ---------------- From python-checkins at python.org Sat Jan 29 14:24:53 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 14:24:53 +0100 Subject: [Python-checkins] distutils2: doc about the packages_root option Message-ID: tarek.ziade pushed e050062fe83b to distutils2: http://hg.python.org/distutils2/rev/e050062fe83b changeset: 914:e050062fe83b tag: tip user: Tarek Ziade date: Sat Jan 29 14:24:45 2011 +0100 summary: doc about the packages_root option files: docs/source/setupcfg.rst diff --git a/docs/source/setupcfg.rst b/docs/source/setupcfg.rst --- a/docs/source/setupcfg.rst +++ b/docs/source/setupcfg.rst @@ -128,6 +128,8 @@ This section describes the files included in the project. +- **packages_root**: the root directory containing all packages. If not provided + Distutils2 will use the current directory. *\*optional* - **packages**: a list of packages the project includes *\*optional* *\*multi* - **modules**: a list of packages the project includes *\*optional* *\*multi* - **scripts**: a list of scripts the project includes *\*optional* *\*multi* @@ -136,6 +138,7 @@ Example:: [files] + packages_root = src packages = pypi2rpm pypi2rpm.command -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 14:54:16 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 14:54:16 +0100 Subject: [Python-checkins] distutils2: merged + fixed tests : now README is to be added explicitely in extra_files Message-ID: tarek.ziade pushed 88b453387537 to distutils2: http://hg.python.org/distutils2/rev/88b453387537 changeset: 916:88b453387537 tag: tip parent: 914:e050062fe83b parent: 915:374f93ab103c user: Tarek Ziade date: Sat Jan 29 14:54:02 2011 +0100 summary: merged + fixed tests : now README is to be added explicitely in extra_files files: distutils2/command/sdist.py distutils2/tests/test_config.py diff --git a/distutils2/command/sdist.py b/distutils2/command/sdist.py --- a/distutils2/command/sdist.py +++ b/distutils2/command/sdist.py @@ -215,8 +215,6 @@ def add_defaults(self): """Add all the default files to self.filelist: - - README or README.txt - - test/test*.py - all pure Python modules mentioned in setup script - all files pointed by package_data (build_py) - all files defined in data_files. @@ -226,32 +224,6 @@ Warns if (README or README.txt) or setup.py are missing; everything else is optional. """ - standards = [('README', 'README.txt')] - for fn in standards: - if isinstance(fn, tuple): - alts = fn - got_it = 0 - for fn in alts: - if os.path.exists(fn): - got_it = 1 - self.filelist.append(fn) - break - - if not got_it: - self.warn("standard file not found: should have one of " + - string.join(alts, ', ')) - else: - if os.path.exists(fn): - self.filelist.append(fn) - else: - self.warn("standard file '%s' not found" % fn) - - optional = ['test/test*.py', 'setup.cfg'] - for pattern in optional: - files = filter(os.path.isfile, glob(pattern)) - if files: - self.filelist.extend(files) - for cmd_name in get_command_names(): try: cmd_obj = self.get_finalized_command(cmd_name) @@ -323,7 +295,7 @@ for file in self.distribution.metadata.requires_files: if file not in files: - msg = "'%s' must be included explicitly extra-files metadata" % file + msg = "'%s' must be included explicitly in 'extra_files'" % file raise DistutilsFileError(msg) for file in files: @@ -383,4 +355,3 @@ # Now create them for dir in need_dirs: self.mkpath(dir, mode, verbose=verbose, dry_run=dry_run) - diff --git a/distutils2/tests/test_command_sdist.py b/distutils2/tests/test_command_sdist.py --- a/distutils2/tests/test_command_sdist.py +++ b/distutils2/tests/test_command_sdist.py @@ -45,7 +45,6 @@ MANIFEST = """\ # file GENERATED by distutils, do NOT edit -README inroot.txt data%(sep)sdata.dt scripts%(sep)sscript.py @@ -141,7 +140,7 @@ zip_file.close() # making sure everything has been pruned correctly - self.assertEqual(len(content), 3) + self.assertEqual(len(content), 2) @unittest.skipUnless(zlib, "requires zlib") def test_make_distribution(self): @@ -236,7 +235,7 @@ zip_file.close() # making sure everything was added - self.assertEqual(len(content), 10) + self.assertEqual(len(content), 9) # checking the MANIFEST manifest = open(join(self.tmp_dir, 'MANIFEST')).read() @@ -362,8 +361,7 @@ if line.strip() != ''] finally: f.close() - - self.assertEqual(len(manifest), 4) + self.assertEqual(len(manifest), 3) # adding a file self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#') @@ -383,7 +381,7 @@ f.close() # do we have the new file in MANIFEST ? - self.assertEqual(len(manifest2), 5) + self.assertEqual(len(manifest2), 4) self.assertIn('doc2.txt', manifest2[-1]) def test_manifest_marker(self): diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -280,7 +280,8 @@ def test_metadata_requires_description_files(self): tempdir = self.mkdtemp() os.chdir(tempdir) - self.write_setup({'description-file': 'README\n README2', 'extra-files':'\n README2'}) + self.write_setup({'description-file': 'README\n README2', + 'extra-files':'\n README2'}) self.write_file('README', 'yeah') self.write_file('README2', 'yeah') self.write_file('haven.py', '#') @@ -302,10 +303,17 @@ cmd = sdist(dist) cmd.finalize_options() cmd.get_file_list() + self.assertRaises(DistutilsFileError, cmd.make_distribution) + + self.write_setup({'description-file': 'README\n README2', + 'extra-files': '\n README2\n README'}) + dist = self.run_setup('--description') + cmd = sdist(dist) + cmd.finalize_options() + cmd.get_file_list() cmd.make_distribution() self.assertIn('README\nREADME2\n', open('MANIFEST').read()) - def test_sub_commands(self): tempdir = self.mkdtemp() os.chdir(tempdir) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 14:54:16 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 14:54:16 +0100 Subject: [Python-checkins] distutils2: avoid inclusion of README or test/*.py Message-ID: tarek.ziade pushed 374f93ab103c to distutils2: http://hg.python.org/distutils2/rev/374f93ab103c changeset: 915:374f93ab103c parent: 899:93c02eaba941 user: Godefroid Chapelle date: Fri Jan 28 18:40:08 2011 +0100 summary: avoid inclusion of README or test/*.py files: distutils2/command/sdist.py distutils2/tests/test_command_sdist.py diff --git a/distutils2/command/sdist.py b/distutils2/command/sdist.py --- a/distutils2/command/sdist.py +++ b/distutils2/command/sdist.py @@ -214,8 +214,6 @@ def add_defaults(self): """Add all the default files to self.filelist: - - README or README.txt - - test/test*.py - all pure Python modules mentioned in setup script - all files pointed by package_data (build_py) - all files defined in data_files. @@ -225,32 +223,6 @@ Warns if (README or README.txt) or setup.py are missing; everything else is optional. """ - standards = [('README', 'README.txt')] - for fn in standards: - if isinstance(fn, tuple): - alts = fn - got_it = 0 - for fn in alts: - if os.path.exists(fn): - got_it = 1 - self.filelist.append(fn) - break - - if not got_it: - self.warn("standard file not found: should have one of " + - string.join(alts, ', ')) - else: - if os.path.exists(fn): - self.filelist.append(fn) - else: - self.warn("standard file '%s' not found" % fn) - - optional = ['test/test*.py', 'setup.cfg'] - for pattern in optional: - files = filter(os.path.isfile, glob(pattern)) - if files: - self.filelist.extend(files) - for cmd_name in get_command_names(): try: cmd_obj = self.get_finalized_command(cmd_name) @@ -376,4 +348,3 @@ # Now create them for dir in need_dirs: self.mkpath(dir, mode, verbose=verbose, dry_run=dry_run) - diff --git a/distutils2/tests/test_command_sdist.py b/distutils2/tests/test_command_sdist.py --- a/distutils2/tests/test_command_sdist.py +++ b/distutils2/tests/test_command_sdist.py @@ -45,7 +45,6 @@ MANIFEST = """\ # file GENERATED by distutils, do NOT edit -README inroot.txt data%(sep)sdata.dt scripts%(sep)sscript.py @@ -141,7 +140,7 @@ zip_file.close() # making sure everything has been pruned correctly - self.assertEqual(len(content), 3) + self.assertEqual(len(content), 2) @unittest.skipUnless(zlib, "requires zlib") def test_make_distribution(self): @@ -236,7 +235,7 @@ zip_file.close() # making sure everything was added - self.assertEqual(len(content), 10) + self.assertEqual(len(content), 9) # checking the MANIFEST manifest = open(join(self.tmp_dir, 'MANIFEST')).read() @@ -362,8 +361,7 @@ if line.strip() != ''] finally: f.close() - - self.assertEqual(len(manifest), 4) + self.assertEqual(len(manifest), 3) # adding a file self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#') @@ -383,7 +381,7 @@ f.close() # do we have the new file in MANIFEST ? - self.assertEqual(len(manifest2), 5) + self.assertEqual(len(manifest2), 4) self.assertIn('doc2.txt', manifest2[-1]) def test_manifest_marker(self): -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 15:19:05 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 15:19:05 +0100 Subject: [Python-checkins] distutils2: split the micro-language for PEP 345 in markers Message-ID: tarek.ziade pushed 608317e1a8b4 to distutils2: http://hg.python.org/distutils2/rev/608317e1a8b4 changeset: 917:608317e1a8b4 tag: tip user: Tarek Ziade date: Sat Jan 29 15:18:54 2011 +0100 summary: split the micro-language for PEP 345 in markers files: distutils2/markers.py distutils2/metadata.py distutils2/tests/test_markers.py distutils2/tests/test_metadata.py diff --git a/distutils2/markers.py b/distutils2/markers.py new file mode 100644 --- /dev/null +++ b/distutils2/markers.py @@ -0,0 +1,194 @@ +""" Micro-language for PEP 345 environment markers +""" +import sys +import platform +import os +from tokenize import tokenize, NAME, OP, STRING, ENDMARKER +from StringIO import StringIO + +__all__ = ['interpret'] + + +# allowed operators +_OPERATORS = {'==': lambda x, y: x == y, + '!=': lambda x, y: x != y, + '>': lambda x, y: x > y, + '>=': lambda x, y: x >= y, + '<': lambda x, y: x < y, + '<=': lambda x, y: x <= y, + 'in': lambda x, y: x in y, + 'not in': lambda x, y: x not in y} + + +def _operate(operation, x, y): + return _OPERATORS[operation](x, y) + + +# restricted set of variables +_VARS = {'sys.platform': sys.platform, + 'python_version': sys.version[:3], + 'python_full_version': sys.version.split(' ', 1)[0], + 'os.name': os.name, + 'platform.version': platform.version(), + 'platform.machine': platform.machine()} + + +class _Operation(object): + + def __init__(self, execution_context=None): + self.left = None + self.op = None + self.right = None + if execution_context is None: + execution_context = {} + self.execution_context = execution_context + + def _get_var(self, name): + if name in self.execution_context: + return self.execution_context[name] + return _VARS[name] + + def __repr__(self): + return '%s %s %s' % (self.left, self.op, self.right) + + def _is_string(self, value): + if value is None or len(value) < 2: + return False + for delimiter in '"\'': + if value[0] == value[-1] == delimiter: + return True + return False + + def _is_name(self, value): + return value in _VARS + + def _convert(self, value): + if value in _VARS: + return self._get_var(value) + return value.strip('"\'') + + def _check_name(self, value): + if value not in _VARS: + raise NameError(value) + + def _nonsense_op(self): + msg = 'This operation is not supported : "%s"' % self + raise SyntaxError(msg) + + def __call__(self): + # make sure we do something useful + if self._is_string(self.left): + if self._is_string(self.right): + self._nonsense_op() + self._check_name(self.right) + else: + if not self._is_string(self.right): + self._nonsense_op() + self._check_name(self.left) + + if self.op not in _OPERATORS: + raise TypeError('Operator not supported "%s"' % self.op) + + left = self._convert(self.left) + right = self._convert(self.right) + return _operate(self.op, left, right) + + +class _OR(object): + def __init__(self, left, right=None): + self.left = left + self.right = right + + def filled(self): + return self.right is not None + + def __repr__(self): + return 'OR(%r, %r)' % (self.left, self.right) + + def __call__(self): + return self.left() or self.right() + + +class _AND(object): + def __init__(self, left, right=None): + self.left = left + self.right = right + + def filled(self): + return self.right is not None + + def __repr__(self): + return 'AND(%r, %r)' % (self.left, self.right) + + def __call__(self): + return self.left() and self.right() + + +class _CHAIN(object): + + def __init__(self, execution_context=None): + self.ops = [] + self.op_starting = True + self.execution_context = execution_context + + def eat(self, toktype, tokval, rowcol, line, logical_line): + if toktype not in (NAME, OP, STRING, ENDMARKER): + raise SyntaxError('Type not supported "%s"' % tokval) + + if self.op_starting: + op = _Operation(self.execution_context) + if len(self.ops) > 0: + last = self.ops[-1] + if isinstance(last, (_OR, _AND)) and not last.filled(): + last.right = op + else: + self.ops.append(op) + else: + self.ops.append(op) + self.op_starting = False + else: + op = self.ops[-1] + + if (toktype == ENDMARKER or + (toktype == NAME and tokval in ('and', 'or'))): + if toktype == NAME and tokval == 'and': + self.ops.append(_AND(self.ops.pop())) + elif toktype == NAME and tokval == 'or': + self.ops.append(_OR(self.ops.pop())) + self.op_starting = True + return + + if isinstance(op, (_OR, _AND)) and op.right is not None: + op = op.right + + if ((toktype in (NAME, STRING) and tokval not in ('in', 'not')) + or (toktype == OP and tokval == '.')): + if op.op is None: + if op.left is None: + op.left = tokval + else: + op.left += tokval + else: + if op.right is None: + op.right = tokval + else: + op.right += tokval + elif toktype == OP or tokval in ('in', 'not'): + if tokval == 'in' and op.op == 'not': + op.op = 'not in' + else: + op.op = tokval + + def result(self): + for op in self.ops: + if not op(): + return False + return True + + +def interpret(marker, execution_context=None): + """Interpret a marker and return a result depending on environment.""" + marker = marker.strip() + operations = _CHAIN(execution_context) + tokenize(StringIO(marker).readline, operations.eat) + return operations.result() diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -5,13 +5,12 @@ import os import sys -import platform import re from StringIO import StringIO from email import message_from_file -from tokenize import tokenize, NAME, OP, STRING, ENDMARKER from distutils2 import logger +from distutils2.markers import interpret from distutils2.version import (is_valid_predicate, is_valid_version, is_valid_versions) from distutils2.errors import (MetadataMissingError, @@ -291,7 +290,7 @@ if not self.platform_dependent or ';' not in value: return True, value value, marker = value.split(';') - return _interpret(marker, self.execution_context), value + return interpret(marker, self.execution_context), value def _remove_line_prefix(self, value): return _LINE_PREFIX.sub('\n', value) @@ -518,191 +517,3 @@ def items(self): """Dict like api""" return [(key, self[key]) for key in self.keys()] - - -# -# micro-language for PEP 345 environment markers -# - -# allowed operators -_OPERATORS = {'==': lambda x, y: x == y, - '!=': lambda x, y: x != y, - '>': lambda x, y: x > y, - '>=': lambda x, y: x >= y, - '<': lambda x, y: x < y, - '<=': lambda x, y: x <= y, - 'in': lambda x, y: x in y, - 'not in': lambda x, y: x not in y} - - -def _operate(operation, x, y): - return _OPERATORS[operation](x, y) - -# restricted set of variables -_VARS = {'sys.platform': sys.platform, - 'python_version': sys.version[:3], - 'python_full_version': sys.version.split(' ', 1)[0], - 'os.name': os.name, - 'platform.version': platform.version(), - 'platform.machine': platform.machine()} - - -class _Operation(object): - - def __init__(self, execution_context=None): - self.left = None - self.op = None - self.right = None - if execution_context is None: - execution_context = {} - self.execution_context = execution_context - - def _get_var(self, name): - if name in self.execution_context: - return self.execution_context[name] - return _VARS[name] - - def __repr__(self): - return '%s %s %s' % (self.left, self.op, self.right) - - def _is_string(self, value): - if value is None or len(value) < 2: - return False - for delimiter in '"\'': - if value[0] == value[-1] == delimiter: - return True - return False - - def _is_name(self, value): - return value in _VARS - - def _convert(self, value): - if value in _VARS: - return self._get_var(value) - return value.strip('"\'') - - def _check_name(self, value): - if value not in _VARS: - raise NameError(value) - - def _nonsense_op(self): - msg = 'This operation is not supported : "%s"' % self - raise SyntaxError(msg) - - def __call__(self): - # make sure we do something useful - if self._is_string(self.left): - if self._is_string(self.right): - self._nonsense_op() - self._check_name(self.right) - else: - if not self._is_string(self.right): - self._nonsense_op() - self._check_name(self.left) - - if self.op not in _OPERATORS: - raise TypeError('Operator not supported "%s"' % self.op) - - left = self._convert(self.left) - right = self._convert(self.right) - return _operate(self.op, left, right) - - -class _OR(object): - def __init__(self, left, right=None): - self.left = left - self.right = right - - def filled(self): - return self.right is not None - - def __repr__(self): - return 'OR(%r, %r)' % (self.left, self.right) - - def __call__(self): - return self.left() or self.right() - - -class _AND(object): - def __init__(self, left, right=None): - self.left = left - self.right = right - - def filled(self): - return self.right is not None - - def __repr__(self): - return 'AND(%r, %r)' % (self.left, self.right) - - def __call__(self): - return self.left() and self.right() - - -class _CHAIN(object): - - def __init__(self, execution_context=None): - self.ops = [] - self.op_starting = True - self.execution_context = execution_context - - def eat(self, toktype, tokval, rowcol, line, logical_line): - if toktype not in (NAME, OP, STRING, ENDMARKER): - raise SyntaxError('Type not supported "%s"' % tokval) - - if self.op_starting: - op = _Operation(self.execution_context) - if len(self.ops) > 0: - last = self.ops[-1] - if isinstance(last, (_OR, _AND)) and not last.filled(): - last.right = op - else: - self.ops.append(op) - else: - self.ops.append(op) - self.op_starting = False - else: - op = self.ops[-1] - - if (toktype == ENDMARKER or - (toktype == NAME and tokval in ('and', 'or'))): - if toktype == NAME and tokval == 'and': - self.ops.append(_AND(self.ops.pop())) - elif toktype == NAME and tokval == 'or': - self.ops.append(_OR(self.ops.pop())) - self.op_starting = True - return - - if isinstance(op, (_OR, _AND)) and op.right is not None: - op = op.right - - if ((toktype in (NAME, STRING) and tokval not in ('in', 'not')) - or (toktype == OP and tokval == '.')): - if op.op is None: - if op.left is None: - op.left = tokval - else: - op.left += tokval - else: - if op.right is None: - op.right = tokval - else: - op.right += tokval - elif toktype == OP or tokval in ('in', 'not'): - if tokval == 'in' and op.op == 'not': - op.op = 'not in' - else: - op.op = tokval - - def result(self): - for op in self.ops: - if not op(): - return False - return True - - -def _interpret(marker, execution_context=None): - """Interpret a marker and return a result depending on environment.""" - marker = marker.strip() - operations = _CHAIN(execution_context) - tokenize(StringIO(marker).readline, operations.eat) - return operations.result() diff --git a/distutils2/tests/test_markers.py b/distutils2/tests/test_markers.py new file mode 100644 --- /dev/null +++ b/distutils2/tests/test_markers.py @@ -0,0 +1,69 @@ +"""Tests for distutils.metadata.""" +import os +import sys +import platform +from StringIO import StringIO + +from distutils2.markers import interpret +from distutils2.tests import run_unittest, unittest +from distutils2.tests.support import LoggingCatcher, WarningsCatcher + + +class MarkersTestCase(LoggingCatcher, WarningsCatcher, + unittest.TestCase): + + def test_interpret(self): + sys_platform = sys.platform + version = sys.version.split()[0] + os_name = os.name + platform_version = platform.version() + platform_machine = platform.machine() + + self.assertTrue(interpret("sys.platform == '%s'" % sys_platform)) + self.assertTrue(interpret( + "sys.platform == '%s' or python_version == '2.4'" % sys_platform)) + self.assertTrue(interpret( + "sys.platform == '%s' and python_full_version == '%s'" % + (sys_platform, version))) + self.assertTrue(interpret("'%s' == sys.platform" % sys_platform)) + self.assertTrue(interpret('os.name == "%s"' % os_name)) + self.assertTrue(interpret( + 'platform.version == "%s" and platform.machine == "%s"' % + (platform_version, platform_machine))) + + # stuff that need to raise a syntax error + ops = ('os.name == os.name', 'os.name == 2', "'2' == '2'", + 'okpjonon', '', 'os.name ==', 'python_version == 2.4') + for op in ops: + self.assertRaises(SyntaxError, interpret, op) + + # combined operations + OP = 'os.name == "%s"' % os_name + AND = ' and ' + OR = ' or ' + self.assertTrue(interpret(OP + AND + OP)) + self.assertTrue(interpret(OP + AND + OP + AND + OP)) + self.assertTrue(interpret(OP + OR + OP)) + self.assertTrue(interpret(OP + OR + OP + OR + OP)) + + # other operators + self.assertTrue(interpret("os.name != 'buuuu'")) + self.assertTrue(interpret("python_version > '1.0'")) + self.assertTrue(interpret("python_version < '5.0'")) + self.assertTrue(interpret("python_version <= '5.0'")) + self.assertTrue(interpret("python_version >= '1.0'")) + self.assertTrue(interpret("'%s' in os.name" % os_name)) + self.assertTrue(interpret("'buuuu' not in os.name")) + self.assertTrue(interpret( + "'buuuu' not in os.name and '%s' in os.name" % os_name)) + + # execution context + self.assertTrue(interpret('python_version == "0.1"', + {'python_version': '0.1'})) + + +def test_suite(): + return unittest.makeSuite(MarkersTestCase) + +if __name__ == '__main__': + run_unittest(test_suite()) diff --git a/distutils2/tests/test_metadata.py b/distutils2/tests/test_metadata.py --- a/distutils2/tests/test_metadata.py +++ b/distutils2/tests/test_metadata.py @@ -1,10 +1,10 @@ -"""Tests for distutils.command.bdist.""" +"""Tests for distutils.metadata.""" import os import sys import platform from StringIO import StringIO -from distutils2.metadata import (DistributionMetadata, _interpret, +from distutils2.metadata import (DistributionMetadata, PKG_INFO_PREFERRED_VERSION) from distutils2.tests import run_unittest, unittest from distutils2.tests.support import LoggingCatcher, WarningsCatcher @@ -46,55 +46,6 @@ self.assertRaises(TypeError, DistributionMetadata, PKG_INFO, mapping=m, fileobj=fp) - def test_interpret(self): - sys_platform = sys.platform - version = sys.version.split()[0] - os_name = os.name - platform_version = platform.version() - platform_machine = platform.machine() - - self.assertTrue(_interpret("sys.platform == '%s'" % sys_platform)) - self.assertTrue(_interpret( - "sys.platform == '%s' or python_version == '2.4'" % sys_platform)) - self.assertTrue(_interpret( - "sys.platform == '%s' and python_full_version == '%s'" % - (sys_platform, version))) - self.assertTrue(_interpret("'%s' == sys.platform" % sys_platform)) - self.assertTrue(_interpret('os.name == "%s"' % os_name)) - self.assertTrue(_interpret( - 'platform.version == "%s" and platform.machine == "%s"' % - (platform_version, platform_machine))) - - # stuff that need to raise a syntax error - ops = ('os.name == os.name', 'os.name == 2', "'2' == '2'", - 'okpjonon', '', 'os.name ==', 'python_version == 2.4') - for op in ops: - self.assertRaises(SyntaxError, _interpret, op) - - # combined operations - OP = 'os.name == "%s"' % os_name - AND = ' and ' - OR = ' or ' - self.assertTrue(_interpret(OP + AND + OP)) - self.assertTrue(_interpret(OP + AND + OP + AND + OP)) - self.assertTrue(_interpret(OP + OR + OP)) - self.assertTrue(_interpret(OP + OR + OP + OR + OP)) - - # other operators - self.assertTrue(_interpret("os.name != 'buuuu'")) - self.assertTrue(_interpret("python_version > '1.0'")) - self.assertTrue(_interpret("python_version < '5.0'")) - self.assertTrue(_interpret("python_version <= '5.0'")) - self.assertTrue(_interpret("python_version >= '1.0'")) - self.assertTrue(_interpret("'%s' in os.name" % os_name)) - self.assertTrue(_interpret("'buuuu' not in os.name")) - self.assertTrue(_interpret( - "'buuuu' not in os.name and '%s' in os.name" % os_name)) - - # execution context - self.assertTrue(_interpret('python_version == "0.1"', - {'python_version': '0.1'})) - def test_metadata_read_write(self): PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO') metadata = DistributionMetadata(PKG_INFO) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 15:19:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 15:19:57 +0100 Subject: [Python-checkins] distutils2: remove unwanted diff Message-ID: tarek.ziade pushed f1cdc803cdd5 to distutils2: http://hg.python.org/distutils2/rev/f1cdc803cdd5 changeset: 918:f1cdc803cdd5 parent: 916:88b453387537 user: Alexis Metaireau date: Sat Jan 29 15:15:27 2011 +0100 summary: remove unwanted diff files: patch diff --git a/patch b/patch deleted file mode 100644 --- a/patch +++ /dev/null @@ -1,23 +0,0 @@ -diff -r 5603e1bc5442 distutils2/util.py ---- a/distutils2/util.py Fri Jan 28 18:42:44 2011 +0100 -+++ b/distutils2/util.py Sat Jan 29 02:39:55 2011 +0100 -@@ -1203,12 +1203,13 @@ - in_cfg_value = has_get_option(config, section, option) - if not in_cfg_value: - # There is no such option in the setup.cfg -- continue -- -- if arg == "long_description": -- filename = has_get_option("description_file") -- if filename: -- in_cfg_value = open(filename).read() -+ if arg == "long_description": -+ filename = has_get_option(config, section, "description_file") -+ print "We have a filename", filename -+ if filename: -+ in_cfg_value = open(filename).read() -+ else: -+ continue - - if arg in MULTI_FIELDS: - # Special behaviour when we have a multi line option -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 15:19:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 15:19:57 +0100 Subject: [Python-checkins] distutils2: merged Message-ID: tarek.ziade pushed 34210b95cffd to distutils2: http://hg.python.org/distutils2/rev/34210b95cffd changeset: 919:34210b95cffd tag: tip parent: 917:608317e1a8b4 parent: 918:f1cdc803cdd5 user: Tarek Ziade date: Sat Jan 29 15:19:39 2011 +0100 summary: merged files: patch diff --git a/patch b/patch deleted file mode 100644 --- a/patch +++ /dev/null @@ -1,23 +0,0 @@ -diff -r 5603e1bc5442 distutils2/util.py ---- a/distutils2/util.py Fri Jan 28 18:42:44 2011 +0100 -+++ b/distutils2/util.py Sat Jan 29 02:39:55 2011 +0100 -@@ -1203,12 +1203,13 @@ - in_cfg_value = has_get_option(config, section, option) - if not in_cfg_value: - # There is no such option in the setup.cfg -- continue -- -- if arg == "long_description": -- filename = has_get_option("description_file") -- if filename: -- in_cfg_value = open(filename).read() -+ if arg == "long_description": -+ filename = has_get_option(config, section, "description_file") -+ print "We have a filename", filename -+ if filename: -+ in_cfg_value = open(filename).read() -+ else: -+ continue - - if arg in MULTI_FIELDS: - # Special behaviour when we have a multi line option -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 16:10:07 2011 From: python-checkins at python.org (tarek.ziade) Date: Sat, 29 Jan 2011 16:10:07 +0100 Subject: [Python-checkins] distutils2: allowing customization of paths Message-ID: tarek.ziade pushed 860a4bcab873 to distutils2: http://hg.python.org/distutils2/rev/860a4bcab873 changeset: 920:860a4bcab873 tag: tip user: Tarek Ziade date: Sat Jan 29 16:10:03 2011 +0100 summary: allowing customization of paths files: distutils2/_backport/pkgutil.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -660,14 +660,14 @@ _cache_generated_egg = False -def _yield_distributions(include_dist, include_egg): +def _yield_distributions(include_dist, include_egg, paths=sys.path): """ Yield .dist-info and .egg(-info) distributions, based on the arguments :parameter include_dist: yield .dist-info distributions :parameter include_egg: yield .egg(-info) distributions """ - for path in sys.path: + for path in paths: realpath = os.path.realpath(path) if not os.path.isdir(realpath): continue @@ -679,7 +679,7 @@ dir.endswith('.egg')): yield EggInfoDistribution(dist_path) -def _generate_cache(use_egg_info=False): +def _generate_cache(use_egg_info=False, paths=sys.path): global _cache_generated, _cache_generated_egg if _cache_generated_egg or (_cache_generated and not use_egg_info): @@ -688,7 +688,7 @@ gen_dist = not _cache_generated gen_egg = use_egg_info - for dist in _yield_distributions(gen_dist, gen_egg): + for dist in _yield_distributions(gen_dist, gen_egg, paths): if isinstance(dist, Distribution): _cache_path[dist.path] = dist if not dist.name in _cache_name: @@ -1017,7 +1017,7 @@ return '-'.join([name, normalized_version]) + file_extension -def get_distributions(use_egg_info=False): +def get_distributions(use_egg_info=False, paths=sys.path): """ Provides an iterator that looks for ``.dist-info`` directories in ``sys.path`` and returns :class:`Distribution` instances for each one of @@ -1028,7 +1028,7 @@ instances """ if not _cache_enabled: - for dist in _yield_distributions(True, use_egg_info): + for dist in _yield_distributions(True, use_egg_info, paths): yield dist else: _generate_cache(use_egg_info) @@ -1041,7 +1041,7 @@ yield dist -def get_distribution(name, use_egg_info=False): +def get_distribution(name, use_egg_info=False, paths=sys.path): """ Scans all elements in ``sys.path`` and looks for all directories ending with ``.dist-info``. Returns a :class:`Distribution` @@ -1059,7 +1059,7 @@ :rtype: :class:`Distribution` or :class:`EggInfoDistribution` or None """ if not _cache_enabled: - for dist in _yield_distributions(True, use_egg_info): + for dist in _yield_distributions(True, use_egg_info, paths): if dist.name == name: return dist else: -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sat Jan 29 18:19:08 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Sat, 29 Jan 2011 18:19:08 +0100 (CET) Subject: [Python-checkins] r88231 - in python/branches/py3k: Lib/imaplib.py Lib/test/test_imaplib.py Misc/ACKS Message-ID: <20110129171908.F1071EE982@mail.python.org> Author: alexander.belopolsky Date: Sat Jan 29 18:19:08 2011 New Revision: 88231 Log: Issue #10939: Fixed imaplib.Internaldate2tuple(). Thanks Joe Peterson for the report and the patch. Reviewed by Georg Brandl. Modified: python/branches/py3k/Lib/imaplib.py python/branches/py3k/Lib/test/test_imaplib.py python/branches/py3k/Misc/ACKS Modified: python/branches/py3k/Lib/imaplib.py ============================================================================== --- python/branches/py3k/Lib/imaplib.py (original) +++ python/branches/py3k/Lib/imaplib.py Sat Jan 29 18:19:08 2011 @@ -1308,8 +1308,8 @@ -Mon2num = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6, - 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12} +Mon2num = {b'Jan': 1, b'Feb': 2, b'Mar': 3, b'Apr': 4, b'May': 5, b'Jun': 6, + b'Jul': 7, b'Aug': 8, b'Sep': 9, b'Oct': 10, b'Nov': 11, b'Dec': 12} def Internaldate2tuple(resp): """Parse an IMAP4 INTERNALDATE string. @@ -1336,7 +1336,7 @@ # INTERNALDATE timezone must be subtracted to get UT zone = (zoneh*60 + zonem)*60 - if zonen == '-': + if zonen == b'-': zone = -zone tt = (year, mon, day, hour, min, sec, -1, -1, -1) Modified: python/branches/py3k/Lib/test/test_imaplib.py ============================================================================== --- python/branches/py3k/Lib/test/test_imaplib.py (original) +++ python/branches/py3k/Lib/test/test_imaplib.py Sat Jan 29 18:19:08 2011 @@ -23,6 +23,17 @@ class TestImaplib(unittest.TestCase): + def test_Internaldate2tuple(self): + tt = imaplib.Internaldate2tuple( + b'25 (INTERNALDATE "01-Jan-1970 00:00:00 +0000")') + self.assertEqual(time.mktime(tt), 0) + tt = imaplib.Internaldate2tuple( + b'25 (INTERNALDATE "01-Jan-1970 11:30:00 +1130")') + self.assertEqual(time.mktime(tt), 0) + tt = imaplib.Internaldate2tuple( + b'25 (INTERNALDATE "31-Dec-1969 12:30:00 -1130")') + self.assertEqual(time.mktime(tt), 0) + def test_that_Time2Internaldate_returns_a_result(self): # We can check only that it successfully produces a result, # not the correctness of the result itself, since the result Modified: python/branches/py3k/Misc/ACKS ============================================================================== --- python/branches/py3k/Misc/ACKS (original) +++ python/branches/py3k/Misc/ACKS Sat Jan 29 18:19:08 2011 @@ -653,6 +653,7 @@ Gabriel de Perthuis Tim Peters Benjamin Peterson +Joe Peterson Chris Petrilli Bjorn Pettersen Geoff Philbrick From python-checkins at python.org Sat Jan 29 19:29:01 2011 From: python-checkins at python.org (ned.deily) Date: Sat, 29 Jan 2011 19:29:01 +0100 (CET) Subject: [Python-checkins] r88232 - in python/branches/py3k: Lib/idlelib/EditorWindow.py Misc/NEWS Message-ID: <20110129182901.B2002EE989@mail.python.org> Author: ned.deily Date: Sat Jan 29 19:29:01 2011 New Revision: 88232 Log: Issue #10940: Workaround an IDLE hang on Mac OS X 10.6 when using the menu accelerators for Open Module, Go to Line, and New Indent Width. The accelerators still work but no longer appear in the menu items. Modified: python/branches/py3k/Lib/idlelib/EditorWindow.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/idlelib/EditorWindow.py ============================================================================== --- python/branches/py3k/Lib/idlelib/EditorWindow.py (original) +++ python/branches/py3k/Lib/idlelib/EditorWindow.py Sat Jan 29 19:29:01 2011 @@ -1546,7 +1546,12 @@ def get_accelerator(keydefs, eventname): keylist = keydefs.get(eventname) - if not keylist: + # issue10940: temporary workaround to prevent hang with OS X Cocoa Tk 8.5 + # if not keylist: + if (not keylist) or (macosxSupport.runningAsOSXApp() and eventname in { + "<>", + "<>", + "<>"}): return "" s = keylist[0] s = re.sub(r"-[a-z]\b", lambda m: m.group().upper(), s) Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 29 19:29:01 2011 @@ -16,6 +16,10 @@ Library ------- +- Issue #10940: Workaround an IDLE hang on Mac OS X 10.6 when using the + menu accelerators for Open Module, Go to Line, and New Indent Width. + The accelerators still work but no longer appear in the menu items. + - Issue #10989: Fix a crash on SSLContext.load_verify_locations(None, True). - Issue #11020: Command-line pyclbr was broken because of missing 2-to-3 From python-checkins at python.org Sat Jan 29 19:43:43 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Sat, 29 Jan 2011 19:43:43 +0100 (CET) Subject: [Python-checkins] r88233 - in python/branches/release31-maint: Lib/imaplib.py Lib/test/test_imaplib.py Misc/ACKS Message-ID: <20110129184343.39283EE981@mail.python.org> Author: alexander.belopolsky Date: Sat Jan 29 19:43:43 2011 New Revision: 88233 Log: Merged revisions 88231 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88231 | alexander.belopolsky | 2011-01-29 12:19:08 -0500 (Sat, 29 Jan 2011) | 4 lines Issue #10939: Fixed imaplib.Internaldate2tuple(). Thanks Joe Peterson for the report and the patch. Reviewed by Georg Brandl. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/imaplib.py python/branches/release31-maint/Lib/test/test_imaplib.py python/branches/release31-maint/Misc/ACKS Modified: python/branches/release31-maint/Lib/imaplib.py ============================================================================== --- python/branches/release31-maint/Lib/imaplib.py (original) +++ python/branches/release31-maint/Lib/imaplib.py Sat Jan 29 19:43:43 2011 @@ -1266,8 +1266,8 @@ -Mon2num = {'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6, - 'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12} +Mon2num = {b'Jan': 1, b'Feb': 2, b'Mar': 3, b'Apr': 4, b'May': 5, b'Jun': 6, + b'Jul': 7, b'Aug': 8, b'Sep': 9, b'Oct': 10, b'Nov': 11, b'Dec': 12} def Internaldate2tuple(resp): """Convert IMAP4 INTERNALDATE to UT. @@ -1293,7 +1293,7 @@ # INTERNALDATE timezone must be subtracted to get UT zone = (zoneh*60 + zonem)*60 - if zonen == '-': + if zonen == b'-': zone = -zone tt = (year, mon, day, hour, min, sec, -1, -1, -1) Modified: python/branches/release31-maint/Lib/test/test_imaplib.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_imaplib.py (original) +++ python/branches/release31-maint/Lib/test/test_imaplib.py Sat Jan 29 19:43:43 2011 @@ -26,6 +26,17 @@ class TestImaplib(unittest.TestCase): + def test_Internaldate2tuple(self): + tt = imaplib.Internaldate2tuple( + b'25 (INTERNALDATE "01-Jan-1970 00:00:00 +0000")') + self.assertEqual(time.mktime(tt), 0) + tt = imaplib.Internaldate2tuple( + b'25 (INTERNALDATE "01-Jan-1970 11:30:00 +1130")') + self.assertEqual(time.mktime(tt), 0) + tt = imaplib.Internaldate2tuple( + b'25 (INTERNALDATE "31-Dec-1969 12:30:00 -1130")') + self.assertEqual(time.mktime(tt), 0) + def test_that_Time2Internaldate_returns_a_result(self): # We can check only that it successfully produces a result, # not the correctness of the result itself, since the result Modified: python/branches/release31-maint/Misc/ACKS ============================================================================== --- python/branches/release31-maint/Misc/ACKS (original) +++ python/branches/release31-maint/Misc/ACKS Sat Jan 29 19:43:43 2011 @@ -611,6 +611,7 @@ Gabriel de Perthuis Tim Peters Benjamin Peterson +Joe Peterson Chris Petrilli Bjorn Pettersen Geoff Philbrick From python-checkins at python.org Sat Jan 29 19:43:56 2011 From: python-checkins at python.org (ned.deily) Date: Sat, 29 Jan 2011 19:43:56 +0100 (CET) Subject: [Python-checkins] r88234 - in python/branches/py3k: Lib/idlelib/ScriptBinding.py Misc/NEWS Message-ID: <20110129184356.EF64DEE984@mail.python.org> Author: ned.deily Date: Sat Jan 29 19:43:56 2011 New Revision: 88234 Log: Issue #11053: Fix IDLE "Syntax Error" windows to behave as in 2.x, preventing a confusing hung appearance on OS X with the windows obscured. (with release manager approval for 3.2rc2) Modified: python/branches/py3k/Lib/idlelib/ScriptBinding.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/idlelib/ScriptBinding.py ============================================================================== --- python/branches/py3k/Lib/idlelib/ScriptBinding.py (original) +++ python/branches/py3k/Lib/idlelib/ScriptBinding.py Sat Jan 29 19:43:56 2011 @@ -190,10 +190,10 @@ icon=tkMessageBox.QUESTION, type=tkMessageBox.OKCANCEL, default=tkMessageBox.OK, - parent=self.editwin.text) + master=self.editwin.text) return mb.show() def errorbox(self, title, message): # XXX This should really be a function of EditorWindow... - tkMessageBox.showerror(title, message, parent=self.editwin.text) + tkMessageBox.showerror(title, message, master=self.editwin.text) self.editwin.text.focus_set() Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 29 19:43:56 2011 @@ -16,6 +16,10 @@ Library ------- +- Issue #11053: Fix IDLE "Syntax Error" windows to behave as in 2.x, + preventing a confusing hung appearance on OS X with the windows + obscured. + - Issue #10940: Workaround an IDLE hang on Mac OS X 10.6 when using the menu accelerators for Open Module, Go to Line, and New Indent Width. The accelerators still work but no longer appear in the menu items. From python-checkins at python.org Sat Jan 29 19:56:28 2011 From: python-checkins at python.org (ned.deily) Date: Sat, 29 Jan 2011 19:56:28 +0100 (CET) Subject: [Python-checkins] r88235 - in python/branches/py3k: Mac/BuildScript/README.txt Mac/BuildScript/build-installer.py Misc/NEWS Message-ID: <20110129185628.6F234EE9AF@mail.python.org> Author: ned.deily Date: Sat Jan 29 19:56:28 2011 New Revision: 88235 Log: Issue #11054: Allow Mac OS X installer builds to again work on 10.5 with the system-provided Python. Also, properly guard a new Python 3 only installer build step so that build-installer.py can stay compatible with the 2.7 version. (with release manager approval for 3.2rc2) Modified: python/branches/py3k/Mac/BuildScript/README.txt python/branches/py3k/Mac/BuildScript/build-installer.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Mac/BuildScript/README.txt ============================================================================== --- python/branches/py3k/Mac/BuildScript/README.txt (original) +++ python/branches/py3k/Mac/BuildScript/README.txt Sat Jan 29 19:56:28 2011 @@ -14,7 +14,7 @@ 1. 32-bit-only, i386 and PPC universal, capable on running on all machines supported by Mac OS X 10.3.9 through (at least) 10.6:: - python2.6 build-installer.py \ + python build-installer.py \ --sdk-path=/Developer/SDKs/MacOSX10.4u.sdk \ --universal-archs=32-bit \ --dep-target=10.3 @@ -38,7 +38,7 @@ * ``MacOSX10.4u`` SDK (later SDKs do not support PPC G3 processors) * ``MACOSX_DEPLOYMENT_TARGET=10.3`` * Apple ``gcc-4.0`` - * Python 2.6 for documentation build with Sphinx + * Python 2.n (n >= 4) for documentation build with Sphinx - alternate build environments: @@ -48,7 +48,7 @@ 2. 64-bit / 32-bit, x86_64 and i386 universal, for OS X 10.6 (and later):: - python2.6 build-installer.py \ + python build-installer.py \ --sdk-path=/Developer/SDKs/MacOSX10.6.sdk \ --universal-archs=intel \ --dep-target=10.6 @@ -67,7 +67,7 @@ * ``MacOSX10.6`` SDK * ``MACOSX_DEPLOYMENT_TARGET=10.6`` * Apple ``gcc-4.2`` - * Python 2.6 for documentation build with Sphinx + * Python 2.n (n >= 4) for documentation build with Sphinx - alternate build environments: Modified: python/branches/py3k/Mac/BuildScript/build-installer.py ============================================================================== --- python/branches/py3k/Mac/BuildScript/build-installer.py (original) +++ python/branches/py3k/Mac/BuildScript/build-installer.py Sat Jan 29 19:56:28 2011 @@ -1,12 +1,14 @@ #!/usr/bin/python """ -This script is used to build the "official unofficial" universal build on -Mac OS X. It requires Mac OS X 10.4, Xcode 2.2 and the 10.4u SDK to do its -work. 64-bit or four-way universal builds require at least OS X 10.5 and -the 10.5 SDK. - -Please ensure that this script keeps working with Python 2.3, to avoid -bootstrap issues (/usr/bin/python is Python 2.3 on OSX 10.4) +This script is used to build "official" universal installers on Mac OS X. +It requires at least Mac OS X 10.4, Xcode 2.2 and the 10.4u SDK for +32-bit builds. 64-bit or four-way universal builds require at least +OS X 10.5 and the 10.5 SDK. + +Please ensure that this script keeps working with Python 2.5, to avoid +bootstrap issues (/usr/bin/python is Python 2.5 on OSX 10.5). Sphinx, +which is used to build the documentation, currently requires at least +Python 2.4. Usage: see USAGE variable in the script. """ @@ -405,6 +407,9 @@ Check that we're running on a supported system. """ + if sys.version_info[0:2] < (2, 4): + fatal("This script must be run with Python 2.4 or later") + if platform.system() != 'Darwin': fatal("This script should be run on a Mac OS X 10.4 (or later) system") @@ -835,29 +840,33 @@ os.chmod(p, stat.S_IMODE(st.st_mode) | stat.S_IWGRP) os.chown(p, -1, gid) - LDVERSION=None - VERSION=None - ABIFLAGS=None + if PYTHON_3: + LDVERSION=None + VERSION=None + ABIFLAGS=None - with open(os.path.join(buildDir, 'Makefile')) as fp: + fp = open(os.path.join(buildDir, 'Makefile'), 'r') for ln in fp: if ln.startswith('VERSION='): VERSION=ln.split()[1] if ln.startswith('ABIFLAGS='): ABIFLAGS=ln.split()[1] - if ln.startswith('LDVERSION='): LDVERSION=ln.split()[1] + fp.close() - LDVERSION = LDVERSION.replace('$(VERSION)', VERSION) - LDVERSION = LDVERSION.replace('$(ABIFLAGS)', ABIFLAGS) + LDVERSION = LDVERSION.replace('$(VERSION)', VERSION) + LDVERSION = LDVERSION.replace('$(ABIFLAGS)', ABIFLAGS) + config_suffix = '-' + LDVERSION + else: + config_suffix = '' # Python 2.x # We added some directories to the search path during the configure # phase. Remove those because those directories won't be there on # the end-users system. path =os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework', 'Versions', version, 'lib', 'python%s'%(version,), - 'config-' + LDVERSION, 'Makefile') + 'config' + config_suffix, 'Makefile') fp = open(path, 'r') data = fp.read() fp.close() Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 29 19:56:28 2011 @@ -73,6 +73,13 @@ - Issue #9509: argparse now properly handles IOErrors raised by argparse.FileType. +Build +----- + +- Issue #11054: Allow Mac OS X installer builds to again work on 10.5 with + the system-provided Python. + + What's New in Python 3.2 Release Candidate 1 ============================================ From python-checkins at python.org Sat Jan 29 20:10:26 2011 From: python-checkins at python.org (ned.deily) Date: Sat, 29 Jan 2011 20:10:26 +0100 (CET) Subject: [Python-checkins] r88236 - in python/branches/py3k: Lib/idlelib/config-keys.def Misc/NEWS Message-ID: <20110129191026.A495BEE988@mail.python.org> Author: ned.deily Date: Sat Jan 29 20:10:26 2011 New Revision: 88236 Log: Issue 11052: Correct IDLE menu accelerators on Mac OS X for Save commands. (with release manager approval for 3.2rc2) Modified: python/branches/py3k/Lib/idlelib/config-keys.def python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/idlelib/config-keys.def ============================================================================== --- python/branches/py3k/Lib/idlelib/config-keys.def (original) +++ python/branches/py3k/Lib/idlelib/config-keys.def Sat Jan 29 20:10:26 2011 @@ -176,7 +176,7 @@ redo = close-window = restart-shell = -save-window-as-file = +save-window-as-file = close-all-windows = view-restart = tabify-region = @@ -208,7 +208,7 @@ open-module = find-selection = python-context-help = -save-copy-of-window-as-file = +save-copy-of-window-as-file = open-window-from-file = python-docs = Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 29 20:10:26 2011 @@ -16,6 +16,9 @@ Library ------- +- Issue #11052: Correct IDLE menu accelerators on Mac OS X for Save + commands. + - Issue #11053: Fix IDLE "Syntax Error" windows to behave as in 2.x, preventing a confusing hung appearance on OS X with the windows obscured. From python-checkins at python.org Sat Jan 29 20:22:26 2011 From: python-checkins at python.org (ned.deily) Date: Sat, 29 Jan 2011 20:22:26 +0100 (CET) Subject: [Python-checkins] r88237 - in python/branches/release31-maint: Lib/idlelib/config-keys.def Misc/NEWS Message-ID: <20110129192226.AE1AFEE985@mail.python.org> Author: ned.deily Date: Sat Jan 29 20:22:26 2011 New Revision: 88237 Log: Merged revisions 88236 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88236 | ned.deily | 2011-01-29 11:10:26 -0800 (Sat, 29 Jan 2011) | 3 lines Issue 11052: Correct IDLE menu accelerators on Mac OS X for Save commands. (with release manager approval for 3.2rc2) ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/idlelib/config-keys.def python/branches/release31-maint/Misc/NEWS Modified: python/branches/release31-maint/Lib/idlelib/config-keys.def ============================================================================== --- python/branches/release31-maint/Lib/idlelib/config-keys.def (original) +++ python/branches/release31-maint/Lib/idlelib/config-keys.def Sat Jan 29 20:22:26 2011 @@ -176,7 +176,7 @@ redo = close-window = restart-shell = -save-window-as-file = +save-window-as-file = close-all-windows = view-restart = tabify-region = @@ -208,7 +208,7 @@ open-module = find-selection = python-context-help = -save-copy-of-window-as-file = +save-copy-of-window-as-file = open-window-from-file = python-docs = Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Sat Jan 29 20:22:26 2011 @@ -37,6 +37,9 @@ Library ------- +- Issue #11052: Correct IDLE menu accelerators on Mac OS X for Save + commands. + - Issue #11020: Command-line pyclbr was broken because of missing 2-to-3 conversion. From python-checkins at python.org Sat Jan 29 20:30:40 2011 From: python-checkins at python.org (ned.deily) Date: Sat, 29 Jan 2011 20:30:40 +0100 (CET) Subject: [Python-checkins] r88238 - in python/branches/release27-maint: Lib/idlelib/config-keys.def Misc/NEWS Message-ID: <20110129193040.2457FEE985@mail.python.org> Author: ned.deily Date: Sat Jan 29 20:30:39 2011 New Revision: 88238 Log: Merged revisions 88236 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88236 | ned.deily | 2011-01-29 11:10:26 -0800 (Sat, 29 Jan 2011) | 3 lines Issue 11052: Correct IDLE menu accelerators on Mac OS X for Save commands. (with release manager approval for 3.2rc2) ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/idlelib/config-keys.def python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Lib/idlelib/config-keys.def ============================================================================== --- python/branches/release27-maint/Lib/idlelib/config-keys.def (original) +++ python/branches/release27-maint/Lib/idlelib/config-keys.def Sat Jan 29 20:30:39 2011 @@ -176,7 +176,7 @@ redo = close-window = restart-shell = -save-window-as-file = +save-window-as-file = close-all-windows = view-restart = tabify-region = @@ -208,7 +208,7 @@ open-module = find-selection = python-context-help = -save-copy-of-window-as-file = +save-copy-of-window-as-file = open-window-from-file = python-docs = Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Sat Jan 29 20:30:39 2011 @@ -37,6 +37,9 @@ Library ------- +- Issue #11052: Correct IDLE menu accelerators on Mac OS X for Save + commands. + - Issue #10949: Improved robustness of rotating file handlers. - Issue #10955: Fix a potential crash when trying to mmap() a file past its From python-checkins at python.org Sat Jan 29 20:49:40 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Sat, 29 Jan 2011 20:49:40 +0100 (CET) Subject: [Python-checkins] r88239 - python/branches/py3k/Lib/test/test_imaplib.py Message-ID: <20110129194940.D40ACEE981@mail.python.org> Author: alexander.belopolsky Date: Sat Jan 29 20:49:40 2011 New Revision: 88239 Log: Issue #10939: Make Internaldate2tuple test more robust. Modified: python/branches/py3k/Lib/test/test_imaplib.py Modified: python/branches/py3k/Lib/test/test_imaplib.py ============================================================================== --- python/branches/py3k/Lib/test/test_imaplib.py (original) +++ python/branches/py3k/Lib/test/test_imaplib.py Sat Jan 29 20:49:40 2011 @@ -9,6 +9,7 @@ import os.path import socketserver import time +import calendar from test.support import reap_threads, verbose, transient_internet import unittest @@ -24,15 +25,16 @@ class TestImaplib(unittest.TestCase): def test_Internaldate2tuple(self): + t0 = calendar.timegm((2000, 1, 1, 0, 0, 0, -1, -1, -1)) tt = imaplib.Internaldate2tuple( - b'25 (INTERNALDATE "01-Jan-1970 00:00:00 +0000")') - self.assertEqual(time.mktime(tt), 0) + b'25 (INTERNALDATE "01-Jan-2000 00:00:00 +0000")') + self.assertEqual(time.mktime(tt), t0) tt = imaplib.Internaldate2tuple( - b'25 (INTERNALDATE "01-Jan-1970 11:30:00 +1130")') - self.assertEqual(time.mktime(tt), 0) + b'25 (INTERNALDATE "01-Jan-2000 11:30:00 +1130")') + self.assertEqual(time.mktime(tt), t0) tt = imaplib.Internaldate2tuple( - b'25 (INTERNALDATE "31-Dec-1969 12:30:00 -1130")') - self.assertEqual(time.mktime(tt), 0) + b'25 (INTERNALDATE "31-Dec-1999 12:30:00 -1130")') + self.assertEqual(time.mktime(tt), t0) def test_that_Time2Internaldate_returns_a_result(self): # We can check only that it successfully produces a result, From python-checkins at python.org Sat Jan 29 21:32:11 2011 From: python-checkins at python.org (eric.araujo) Date: Sat, 29 Jan 2011 21:32:11 +0100 (CET) Subject: [Python-checkins] r88240 - in python/branches/py3k: Lib/shutil.py Misc/NEWS Message-ID: <20110129203211.9ABB9C49F@mail.python.org> Author: eric.araujo Date: Sat Jan 29 21:32:11 2011 New Revision: 88240 Log: Protect logging call against None argument (fixes #11045). Initial patch by Kelsey Hightower. Approved by Raymond. A test was non-trivial to write without calling the private function directly, so we moved that for later. Modified: python/branches/py3k/Lib/shutil.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/shutil.py ============================================================================== --- python/branches/py3k/Lib/shutil.py (original) +++ python/branches/py3k/Lib/shutil.py Sat Jan 29 21:32:11 2011 @@ -391,7 +391,8 @@ archive_dir = os.path.dirname(archive_name) if not os.path.exists(archive_dir): - logger.info("creating %s" % archive_dir) + if logger is not None: + logger.info("creating %s" % archive_dir) if not dry_run: os.makedirs(archive_dir) Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sat Jan 29 21:32:11 2011 @@ -16,6 +16,8 @@ Library ------- +- Issue #11045: Protect logging call against None argument. + - Issue #11052: Correct IDLE menu accelerators on Mac OS X for Save commands. From python-checkins at python.org Sat Jan 29 21:42:47 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Sat, 29 Jan 2011 21:42:47 +0100 (CET) Subject: [Python-checkins] r88241 - in python/branches/release31-maint: Lib/test/test_imaplib.py Message-ID: <20110129204247.1F8A1EE988@mail.python.org> Author: alexander.belopolsky Date: Sat Jan 29 21:42:46 2011 New Revision: 88241 Log: Merged revisions 88239 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88239 | alexander.belopolsky | 2011-01-29 14:49:40 -0500 (Sat, 29 Jan 2011) | 1 line Issue #10939: Make Internaldate2tuple test more robust. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/test/test_imaplib.py Modified: python/branches/release31-maint/Lib/test/test_imaplib.py ============================================================================== --- python/branches/release31-maint/Lib/test/test_imaplib.py (original) +++ python/branches/release31-maint/Lib/test/test_imaplib.py Sat Jan 29 21:42:46 2011 @@ -12,6 +12,7 @@ import socketserver import sys import time +import calendar from test.support import reap_threads, verbose, transient_internet import unittest @@ -27,15 +28,16 @@ class TestImaplib(unittest.TestCase): def test_Internaldate2tuple(self): + t0 = calendar.timegm((2000, 1, 1, 0, 0, 0, -1, -1, -1)) tt = imaplib.Internaldate2tuple( - b'25 (INTERNALDATE "01-Jan-1970 00:00:00 +0000")') - self.assertEqual(time.mktime(tt), 0) + b'25 (INTERNALDATE "01-Jan-2000 00:00:00 +0000")') + self.assertEqual(time.mktime(tt), t0) tt = imaplib.Internaldate2tuple( - b'25 (INTERNALDATE "01-Jan-1970 11:30:00 +1130")') - self.assertEqual(time.mktime(tt), 0) + b'25 (INTERNALDATE "01-Jan-2000 11:30:00 +1130")') + self.assertEqual(time.mktime(tt), t0) tt = imaplib.Internaldate2tuple( - b'25 (INTERNALDATE "31-Dec-1969 12:30:00 -1130")') - self.assertEqual(time.mktime(tt), 0) + b'25 (INTERNALDATE "31-Dec-1999 12:30:00 -1130")') + self.assertEqual(time.mktime(tt), t0) def test_that_Time2Internaldate_returns_a_result(self): # We can check only that it successfully produces a result, From python-checkins at python.org Sun Jan 30 00:34:20 2011 From: python-checkins at python.org (ned.deily) Date: Sun, 30 Jan 2011 00:34:20 +0100 (CET) Subject: [Python-checkins] r88242 - in python/branches/release31-maint: Lib/idlelib/ScriptBinding.py Misc/NEWS Message-ID: <20110129233420.0B80FEE989@mail.python.org> Author: ned.deily Date: Sun Jan 30 00:34:19 2011 New Revision: 88242 Log: Merged revisions 88234 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88234 | ned.deily | 2011-01-29 10:43:56 -0800 (Sat, 29 Jan 2011) | 5 lines Issue #11053: Fix IDLE "Syntax Error" windows to behave as in 2.x, preventing a confusing hung appearance on OS X with the windows obscured. (with release manager approval for 3.2rc2) ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/idlelib/ScriptBinding.py python/branches/release31-maint/Misc/NEWS Modified: python/branches/release31-maint/Lib/idlelib/ScriptBinding.py ============================================================================== --- python/branches/release31-maint/Lib/idlelib/ScriptBinding.py (original) +++ python/branches/release31-maint/Lib/idlelib/ScriptBinding.py Sun Jan 30 00:34:19 2011 @@ -190,10 +190,10 @@ icon=tkMessageBox.QUESTION, type=tkMessageBox.OKCANCEL, default=tkMessageBox.OK, - parent=self.editwin.text) + master=self.editwin.text) return mb.show() def errorbox(self, title, message): # XXX This should really be a function of EditorWindow... - tkMessageBox.showerror(title, message, parent=self.editwin.text) + tkMessageBox.showerror(title, message, master=self.editwin.text) self.editwin.text.focus_set() Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Sun Jan 30 00:34:19 2011 @@ -37,6 +37,10 @@ Library ------- +- Issue #11053: Fix IDLE "Syntax Error" windows to behave as in 2.x, + preventing a confusing hung appearance on OS X with the windows + obscured. + - Issue #11052: Correct IDLE menu accelerators on Mac OS X for Save commands. From python-checkins at python.org Sun Jan 30 01:18:47 2011 From: python-checkins at python.org (ned.deily) Date: Sun, 30 Jan 2011 01:18:47 +0100 (CET) Subject: [Python-checkins] r88243 - in python/branches/release27-maint: Lib/idlelib/PyShell.py Lib/idlelib/macosxSupport.py Mac/BuildScript/resources/ReadMe.txt Mac/BuildScript/resources/Welcome.rtf Misc/NEWS Message-ID: <20110130001847.DA74DEE98B@mail.python.org> Author: ned.deily Date: Sun Jan 30 01:18:47 2011 New Revision: 88243 Log: Merged revisions 88003 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88003 | ned.deily | 2011-01-14 20:37:12 -0800 (Fri, 14 Jan 2011) | 5 lines #10907: Warn OS X 10.6 IDLE users to use ActiveState Tcl/Tk 8.5, rather than the currently problematic Apple-supplied one, when running with the 64-/32-bit installer variant. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/idlelib/PyShell.py python/branches/release27-maint/Lib/idlelib/macosxSupport.py python/branches/release27-maint/Mac/BuildScript/resources/ReadMe.txt python/branches/release27-maint/Mac/BuildScript/resources/Welcome.rtf python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Lib/idlelib/PyShell.py ============================================================================== --- python/branches/release27-maint/Lib/idlelib/PyShell.py (original) +++ python/branches/release27-maint/Lib/idlelib/PyShell.py Sun Jan 30 01:18:47 2011 @@ -1432,6 +1432,13 @@ shell.interp.prepend_syspath(script) shell.interp.execfile(script) + # Check for problematic OS X Tk versions and print a warning message + # in the IDLE shell window; this is less intrusive than always opening + # a separate window. + tkversionwarning = macosxSupport.tkVersionWarning(root) + if tkversionwarning: + shell.interp.runcommand(''.join(("print('", tkversionwarning, "')"))) + root.mainloop() root.destroy() Modified: python/branches/release27-maint/Lib/idlelib/macosxSupport.py ============================================================================== --- python/branches/release27-maint/Lib/idlelib/macosxSupport.py (original) +++ python/branches/release27-maint/Lib/idlelib/macosxSupport.py Sun Jan 30 01:18:47 2011 @@ -34,6 +34,23 @@ 'AppKit' not in root.tk.call('winfo', 'server', '.')) return _carbonaquatk +def tkVersionWarning(root): + """ + Returns a string warning message if the Tk version in use appears to + be one known to cause problems with IDLE. The Apple Cocoa-based Tk 8.5 + that was shipped with Mac OS X 10.6. + """ + + if (runningAsOSXApp() and + ('AppKit' in root.tk.call('winfo', 'server', '.')) and + (root.tk.call('info', 'patchlevel') == '8.5.7') ): + return (r"WARNING: The version of Tcl/Tk (8.5.7) in use may" + r" be unstable.\n" + r"Visit http://www.python.org/download/mac/tcltk/" + r" for current information.") + else: + return False + def addOpenEventSupport(root, flist): """ This ensures that the application will respont to open AppleEvents, which Modified: python/branches/release27-maint/Mac/BuildScript/resources/ReadMe.txt ============================================================================== --- python/branches/release27-maint/Mac/BuildScript/resources/ReadMe.txt (original) +++ python/branches/release27-maint/Mac/BuildScript/resources/ReadMe.txt Sun Jan 30 01:18:47 2011 @@ -1,27 +1,36 @@ This package will install Python $FULL_VERSION for Mac OS X -$MACOSX_DEPLOYMENT_TARGET for the following -architecture(s): $ARCHITECTURES. +$MACOSX_DEPLOYMENT_TARGET for the following architecture(s): +$ARCHITECTURES. -Separate installers are available for older versions -of Mac OS X, see the homepage, below. +Installation requires approximately $INSTALL_SIZE MB of disk space, +ignore the message that it will take zero bytes. -Installation requires approximately $INSTALL_SIZE MB of disk -space, ignore the message that it will take zero bytes. +You must install onto your current boot disk, even though the +installer does not enforce this, otherwise things will not work. -You must install onto your current boot disk, even -though the installer does not enforce this, otherwise -things will not work. - -Python consists of the Python programming language -interpreter, plus a set of programs to allow easy -access to it for Mac users including an integrated development -environment, IDLE, plus a set of pre-built extension modules -that open up specific Macintosh technologies to Python programs. - -The installer puts the applications in "Python $VERSION" -in your Applications folder, command-line tools in -/usr/local/bin and the underlying machinery in -$PYTHONFRAMEWORKINSTALLDIR. +Python consists of the Python programming language interpreter, plus +a set of programs to allow easy access to it for Mac users including +an integrated development environment, IDLE, plus a set of pre-built +extension modules that open up specific Macintosh technologies to +Python programs. + + **** IMPORTANT **** + +Before using IDLE or other programs using the tkinter graphical user +interface toolkit, visit http://www.python.org/download/mac/tcltk/ +for current information about supported and recommended versions +of Tcl/Tk for this version of Python and Mac OS X. + + ******************* + +The installer puts applications, an "Update Shell Profile" command, +and an Extras folder containing demo programs and tools into the +"Python $VERSION" subfolder of the system Applications folder, +and puts the underlying machinery into the folder +$PYTHONFRAMEWORKINSTALLDIR. It can +optionally place links to the command-line tools in /usr/local/bin as +well. Double-click on the "Update Shell Profile" command to add the +"bin" directory inside the framework to your shell's search path. More information on Python in general can be found at http://www.python.org. Modified: python/branches/release27-maint/Mac/BuildScript/resources/Welcome.rtf ============================================================================== --- python/branches/release27-maint/Mac/BuildScript/resources/Welcome.rtf (original) +++ python/branches/release27-maint/Mac/BuildScript/resources/Welcome.rtf Sun Jan 30 01:18:47 2011 @@ -1,18 +1,29 @@ -{\rtf1\mac\ansicpg10000\cocoartf824\cocoasubrtf410 -{\fonttbl\f0\fswiss\fcharset77 Helvetica;\f1\fswiss\fcharset77 Helvetica-Bold;} +{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} {\colortbl;\red255\green255\blue255;} -\paperw11900\paperh16840\margl1440\margr1440\vieww9920\viewh10660\viewkind0 +\paperw11904\paperh16836\margl1440\margr1440\vieww9640\viewh10620\viewkind0 \pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural \f0\fs24 \cf0 This package will install -\f1\b Python $FULL_VERSION -\f0\b0 for -\f1\b Mac OS X $MACOSX_DEPLOYMENT_TARGET -\f0\b0 .\ +\b Python $FULL_VERSION +\b0 for +\b Mac OS X $MACOSX_DEPLOYMENT_TARGET +\b0 .\ \ -Python consists of the Python programming language interpreter, plus a set of programs to allow easy access to it for Mac users including an integrated development environment \b IDLE\b0 plus a set of pre-built extension modules that open up specific Macintosh technologies to Python programs.\ -\ -See the ReadMe file for more information.\ + +\b Python for Mac OS X +\b0 consists of the Python programming language interpreter, plus a set of programs to allow easy access to it for Mac OS X users including an integrated development environment +\b IDLE +\b0 and a set of pre-built extension modules that open up specific Macintosh technologies to Python programs.\ \ +See the ReadMe file and the Python documentation for more information.\ \ -This package will by default update your shell profile to ensure that this version of Python is on the search path of your shell. Please deselect the "Shell profile updater" package on the package customization screen if you want to avoid this modification. Double-click \b Update Shell Profile\b0 at any time to make $FULL_VERSION the default Python.} + +\b IMPORTANT: +\b0 +\b IDLE +\b0 and other programs using the +\b tkinter +\b0 graphical user interface toolkit require specific versions of the +\b Tcl/Tk +\b0 platform independent windowing toolkit. Visit {\field{\*\fldinst{HYPERLINK "http://www.python.org/download/mac/tcltk/"}}{\fldrslt http://www.python.org/download/mac/tcltk/}} for current information on supported and recommended versions of Tcl/Tk for this version of Python and Mac OS X.} \ No newline at end of file Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Sun Jan 30 01:18:47 2011 @@ -37,6 +37,10 @@ Library ------- +- Issue #10907: Warn OS X 10.6 IDLE users to use ActiveState Tcl/Tk 8.5, rather + than the currently problematic Apple-supplied one, when running with the + 64-/32-bit installer variant. + - Issue #11052: Correct IDLE menu accelerators on Mac OS X for Save commands. From nnorwitz at gmail.com Sun Jan 30 00:48:18 2011 From: nnorwitz at gmail.com (Neal Norwitz) Date: Sat, 29 Jan 2011 18:48:18 -0500 Subject: [Python-checkins] Python Regression Test Failures refleak (1) Message-ID: <20110129234818.GA760@kbk-i386-bb.dyndns.org> More important issues: ---------------------- test_bz2 leaked [-84, 0, 0] references, sum=-84 Less important issues: ---------------------- From python-checkins at python.org Sun Jan 30 01:39:00 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 30 Jan 2011 01:39:00 +0100 (CET) Subject: [Python-checkins] r88244 - python/branches/py3k/Doc/library/http.client.rst Message-ID: <20110130003900.702CFEE98B@mail.python.org> Author: raymond.hettinger Date: Sun Jan 30 01:39:00 2011 New Revision: 88244 Log: Typos. Modified: python/branches/py3k/Doc/library/http.client.rst Modified: python/branches/py3k/Doc/library/http.client.rst ============================================================================== --- python/branches/py3k/Doc/library/http.client.rst (original) +++ python/branches/py3k/Doc/library/http.client.rst Sun Jan 30 01:39:00 2011 @@ -36,7 +36,7 @@ used. If the optional *timeout* parameter is given, blocking operations (like connection attempts) will timeout after that many seconds (if it is not given, the global default timeout setting is used). - The optional *source_address* parameter may be a typle of a (host, port) + The optional *source_address* parameter may be a tuple of a (host, port) to use as the source address the HTTP connection is made from. For example, the following calls all create instances that connect to the server @@ -400,7 +400,7 @@ contents of the file is sent; this file object should support ``fileno()`` and ``read()`` methods. The header Content-Length is automatically set to the length of the file as reported by stat. The *body* argument may also be - an iterable and Contet-Length header should be explicitly provided when the + an iterable and Content-Length header should be explicitly provided when the body is an iterable. The *headers* argument should be a mapping of extra HTTP From python-checkins at python.org Sun Jan 30 01:47:56 2011 From: python-checkins at python.org (brett.cannon) Date: Sun, 30 Jan 2011 01:47:56 +0100 Subject: [Python-checkins] devguide: Various corrections from Eli Bendersky. Message-ID: brett.cannon pushed 3df3d7a25956 to devguide: http://hg.python.org/devguide/rev/3df3d7a25956 changeset: 221:3df3d7a25956 tag: tip user: Brett Cannon date: Sat Jan 29 16:47:50 2011 -0800 summary: Various corrections from Eli Bendersky. files: coverage.rst docquality.rst fixingissues.rst silencewarnings.rst diff --git a/coverage.rst b/coverage.rst --- a/coverage.rst +++ b/coverage.rst @@ -3,7 +3,7 @@ Increase Test Coverage ====================== -Python development follows a practice that all semantics changes and additions +Python development follows a practice that all semantic changes and additions to the language and :abbr:`stdlib (standard library)` are accompanied by appropriate unit tests. Unfortunately Python was in existence for a long time before the practice came into effect. This has left chunks of the stdlib @@ -18,8 +18,9 @@ conservative and assuming something should be covered is generally a good rule to follow. -Choosing what module you want to increase test coverage can be done in a couple -of ways. A third-party website at http://coverage.livinglogic.de/ provides an +Choosing what module you want to increase test coverage for can be done in a +couple of ways. +A third-party website at http://coverage.livinglogic.de/ provides an overall view of how good coverage is for various modules (you will want to focus on those in the ``Lib`` directory as those are the pure Python modules from Python's stdlib, and thus easier to work with than the C extension @@ -36,7 +37,7 @@ takes some time to complete, but you will have an accurate, up-to-date notion of what modules need the most work. -Do make sure, though, that for any module you do decide to work that you run +Do make sure, though, that for any module you do decide to work on that you run coverage for just that module. This wll make sure you know how good the explicit coverage of the module is from its own set of tests instead of from implicit testing by other code that happens to use the module. diff --git a/docquality.rst b/docquality.rst --- a/docquality.rst +++ b/docquality.rst @@ -12,7 +12,7 @@ It includes an explanation of the markup used (although you can figure a lot out simply by looking at pre-existing documentation) and how to build the documentation (which allows you to see how your changes will look along with -validating your new markup is correct). +validating that your new markup is correct). .. _Documenting Python: http://docs.python.org/py3k/documenting/index.html @@ -42,7 +42,7 @@ While an issue filed on the `issue tracker`_ means there is a known issue somewhere, that does not mean there are not other issues lurking about in the -documentation. Simply proofreading parts of the documentation are enough to +documentation. Simply proofreading parts of the documentation is enough to uncover problems (e.g., documentation that needs to be updated for Python 3 from Python 2). diff --git a/fixingissues.rst b/fixingissues.rst --- a/fixingissues.rst +++ b/fixingissues.rst @@ -15,7 +15,7 @@ it is quite possible that a bug that has been left open has been left into that state because of the difficulty compared to the benefit of the fix. It could also still be open because no consensus has been reached on how to fix the -issue (although having a patch the proposes a fix can turn the tides of the +issue (although having a patch that proposes a fix can turn the tides of the discussion to help bring it to a close). Regardless of why the issue is open, you can also always provide useful comments if you do attempt a fix, successful or not. diff --git a/silencewarnings.rst b/silencewarnings.rst --- a/silencewarnings.rst +++ b/silencewarnings.rst @@ -5,7 +5,7 @@ When running Python's test suite, no warnings should result when you run it under :ref:`strenuous testing conditions ` (you can ignore -the extra flags past to ``test`` that cause randomness and parallel execution +the extra flags passed to ``test`` that cause randomness and parallel execution if you want). Unfortunately new warnings are added to Python on occasion which take some time to eliminate (e.g., ``ResourceWarning``). Typically the easy warnings are dealt with quickly, but the more difficult ones that require some -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Sun Jan 30 01:55:48 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 30 Jan 2011 01:55:48 +0100 (CET) Subject: [Python-checkins] r88245 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110130005548.11C1FEE981@mail.python.org> Author: raymond.hettinger Date: Sun Jan 30 01:55:47 2011 New Revision: 88245 Log: Add section for http.client. Link to OS X build instructions. Add back issue references for datetime. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Sun Jan 30 01:55:47 2011 @@ -1006,7 +1006,11 @@ :func:`time.strftime` functions will accept the full range supported by the corresponding operating system functions. -(Contributed by Alexander Belopolsky and Victor Stinner.) +(Contributed by Alexander Belopolsky and Victor Stinner in :issue:`1289118`, +:issue:`5094`, :issue:`6641`, :issue:`2706`, :issue:`1777412`, :issue:`8013`, +and :issue:`10827`.) + +.. XXX http://bugs.python.org/issue?%40search_text=datetime&%40sort=-activity math ---- @@ -1620,11 +1624,36 @@ (Contributed by Lorenzo M. Catucci and Antoine Pitrou, :issue:`4471`.) -.. XXX sys._xoptions http://bugs.python.org/issue10089 -.. XXX perhaps add issue numbers back to datetime -.. XXX Mac OS fixes and remaining issues -.. XXX Mailbox fixes and remaining issues -.. XXX HTTP client now using latin-1 +http.client +----------- + +There were a number of small API improvements in the :mod:`http.client` module. +The old-style HTTP 0.9 simple responses are no longer supported and the *strict* +parameter is deprecated in all classes. + +The :class:`~http.client.HTTPConnection` and +:class:`~http.client.HTTPSConnection` classes now have a *source_address* +parameter for a (host, port) tuple indicating where the HTTP connection is made +from. + +Support for certificate checking and HTTPS virtual hosts were added to +:class:`~http.client.HTTPSConnection`. + +The :meth:`~http.client.HTTPConnection.request` method on connection objects +allowed an optional *body* argument so that a :term:`file object` could be used +to supply the content of the request. Conveniently, the *body* argument now +also accepts an :term:`iterable` object so long as it includes an explicit +``Content-Length`` header. This extended interface is much more flexible than +before. + +To establish an HTTPS connection through a proxy server, there is a new +:meth:`~http.client.HTTPConnection.set_tunnel` method that sets the host and +port for HTTP Connect tunneling. + +To match the behaviour of :mod:`http.server`, the HTTP client library now also +encodes headers with ISO-8859-1 (Latin-1) encoding. It was already doing that +for incoming headers, so now the behaviour is consistent for both incoming and +outgoing traffic. (See work by Armin Ronacher in :issue:`10980`.) unittest -------- @@ -2413,6 +2442,8 @@ There were a number of other small changes to the C-API. See the :file:`Misc/NEWS` file for a complete list. +Also, the were a number of updates to the OS X build, see +:file:/`Mac/BuildScript/README.txt`. Porting to Python 3.2 ===================== From python-checkins at python.org Sun Jan 30 02:10:07 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 30 Jan 2011 02:10:07 +0100 (CET) Subject: [Python-checkins] r88246 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110130011007.A67B6EE985@mail.python.org> Author: raymond.hettinger Date: Sun Jan 30 02:10:07 2011 New Revision: 88246 Log: Markup nits. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Sun Jan 30 02:10:07 2011 @@ -2440,10 +2440,10 @@ longer used and it had never been documented (:issue:`8837`). There were a number of other small changes to the C-API. See the -:file:`Misc/NEWS` file for a complete list. +:source:`Misc/NEWS` file for a complete list. -Also, the were a number of updates to the OS X build, see -:file:/`Mac/BuildScript/README.txt`. +Also, there were a number of updates to the OS X build, see +:source:`Mac/BuildScript/README.txt`. Porting to Python 3.2 ===================== From python-checkins at python.org Sun Jan 30 02:24:09 2011 From: python-checkins at python.org (nick.coghlan) Date: Sun, 30 Jan 2011 02:24:09 +0100 (CET) Subject: [Python-checkins] r88247 - in python/branches/py3k: Lib/multiprocessing/forking.py Misc/NEWS Message-ID: <20110130012409.05C05EE985@mail.python.org> Author: nick.coghlan Date: Sun Jan 30 02:24:08 2011 New Revision: 88247 Log: Issue #10845: Improve compatibility between multiprocessing on Windows and package, zipfile and directory execution (Reviewed by Antoine Pitrou and approved by Georg Brandl) Modified: python/branches/py3k/Lib/multiprocessing/forking.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/multiprocessing/forking.py ============================================================================== --- python/branches/py3k/Lib/multiprocessing/forking.py (original) +++ python/branches/py3k/Lib/multiprocessing/forking.py Sun Jan 30 02:24:08 2011 @@ -459,12 +459,20 @@ process.ORIGINAL_DIR = data['orig_dir'] if 'main_path' in data: + # XXX (ncoghlan): The following code makes several bogus + # assumptions regarding the relationship between __file__ + # and a module's real name. See PEP 302 and issue #10845 main_path = data['main_path'] main_name = os.path.splitext(os.path.basename(main_path))[0] if main_name == '__init__': main_name = os.path.basename(os.path.dirname(main_path)) - if main_name != 'ipython': + if main_name == '__main__': + main_module = sys.modules['__main__'] + main_module.__file__ = main_path + elif main_name != 'ipython': + # Main modules not actually called __main__.py may + # contain additional code that should still be executed import imp if main_path is None: Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sun Jan 30 02:24:08 2011 @@ -16,6 +16,10 @@ Library ------- +- Issue #10845: Mitigate the incompatibility between the multiprocessing + module on Windows and the use of package, zipfile or directory execution + by special casing main modules that actually *are* called __main__.py. + - Issue #11045: Protect logging call against None argument. - Issue #11052: Correct IDLE menu accelerators on Mac OS X for Save From python-checkins at python.org Sun Jan 30 02:43:41 2011 From: python-checkins at python.org (ned.deily) Date: Sun, 30 Jan 2011 02:43:41 +0100 (CET) Subject: [Python-checkins] r88248 - in python/branches/release27-maint: Mac/BuildScript/README.txt Mac/BuildScript/build-installer.py Misc/NEWS Message-ID: <20110130014341.006C1EE985@mail.python.org> Author: ned.deily Date: Sun Jan 30 02:43:40 2011 New Revision: 88248 Log: Merged revisions 88004,88006,88235 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88004 | ned.deily | 2011-01-14 20:44:12 -0800 (Fri, 14 Jan 2011) | 4 lines #10907: Update OS X installer build README to better reflect current build practices. ........ r88006 | ned.deily | 2011-01-14 21:29:12 -0800 (Fri, 14 Jan 2011) | 6 lines #10843: Update third-party library versions used in OS X 32-bit installer builds: bzip2 1.0.6, readline 6.1.2, SQLite 3.7.4 (with FTS3/FTS4 and RTREE enabled), and ncursesw 5.5 (wide-char support enabled). ........ r88235 | ned.deily | 2011-01-29 10:56:28 -0800 (Sat, 29 Jan 2011) | 5 lines Issue #11054: Allow Mac OS X installer builds to again work on 10.5 with the system-provided Python. Also, properly guard a new Python 3 only installer build step so that build-installer.py can stay compatible with the 2.7 version. (with release manager approval for 3.2rc2) ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Mac/BuildScript/README.txt python/branches/release27-maint/Mac/BuildScript/build-installer.py python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Mac/BuildScript/README.txt ============================================================================== --- python/branches/release27-maint/Mac/BuildScript/README.txt (original) +++ python/branches/release27-maint/Mac/BuildScript/README.txt Sun Jan 30 02:43:40 2011 @@ -1,78 +1,147 @@ -Building a MacPython distribution -================================= +Building a Python Mac OS X distribution +======================================= -The ``build-install.py`` script creates MacPython distributions, including -sleepycat db4, sqlite3 and readline support. It builds a complete +The ``build-install.py`` script creates Python distributions, including +certain third-party libraries as necessary. It builds a complete framework-based Python out-of-tree, installs it in a funny place with $DESTROOT, massages that installation to remove .pyc files and such, creates an Installer package from the installation plus other files in ``resources`` and ``scripts`` and placed that on a ``.dmg`` disk image. -Prerequisites -------------- +As of Python 2.7.x and 3.2, PSF practice is to build two installer variants +for each release: -* A MacOS X 10.4 (or later) +1. 32-bit-only, i386 and PPC universal, capable on running on all machines + supported by Mac OS X 10.3.9 through (at least) 10.6:: -* XCode 2.2 (or later), with the universal SDK + python build-installer.py \ + --sdk-path=/Developer/SDKs/MacOSX10.4u.sdk \ + --universal-archs=32-bit \ + --dep-target=10.3 + # These are the current default options -* No Fink (in ``/sw``) or DarwinPorts (in ``/opt/local``), those could + - builds the following third-party libraries + + * Bzip2 + * Zlib 1.2.3 + * GNU Readline (GPL) + * SQLite 3 + * NCurses + * Oracle Sleepycat DB 4.8 (Python 2.x only) + + - requires ActiveState ``Tcl/Tk 8.4`` (currently 8.4.19) to be installed for building + + - current target build environment: + + * Mac OS X 10.5.8 PPC or Intel + * Xcode 3.1.4 (or later) + * ``MacOSX10.4u`` SDK (later SDKs do not support PPC G3 processors) + * ``MACOSX_DEPLOYMENT_TARGET=10.3`` + * Apple ``gcc-4.0`` + * Python 2.n (n >= 4) for documentation build with Sphinx + + - alternate build environments: + + * Mac OS X 10.4.11 with Xcode 2.5 + * Mac OS X 10.6.6 with Xcode 3.2.5 + - need to change ``/System/Library/Frameworks/{Tcl,Tk}.framework/Version/Current`` to ``8.4`` + +2. 64-bit / 32-bit, x86_64 and i386 universal, for OS X 10.6 (and later):: + + python build-installer.py \ + --sdk-path=/Developer/SDKs/MacOSX10.6.sdk \ + --universal-archs=intel \ + --dep-target=10.6 + + - uses system-supplied versions of third-party libraries + + * readline module links with Apple BSD editline (libedit) + * builds Oracle Sleepycat DB 4.8 (Python 2.x only) + + - requires ActiveState Tcl/Tk 8.5.9 (or later) to be installed for building + + - current target build environment: + + * Mac OS X 10.6.6 (or later) + * Xcode 3.2.5 (or later) + * ``MacOSX10.6`` SDK + * ``MACOSX_DEPLOYMENT_TARGET=10.6`` + * Apple ``gcc-4.2`` + * Python 2.n (n >= 4) for documentation build with Sphinx + + - alternate build environments: + + * none + + +General Prerequisites +--------------------- + +* No Fink (in ``/sw``) or MacPorts (in ``/opt/local``) or other local + libraries or utilities (in ``/usr/local``) as they could interfere with the build. -* The documentation for the release must be available on python.org +* The documentation for the release is built using Sphinx because it is included in the installer. +* It is safest to start each variant build with an empty source directory + populated with a fresh copy of the untarred source. + The Recipe ---------- -Here are the steps you need to follow to build a MacPython installer: +Here are the steps you need to follow to build a Python installer: -* Run ``./build-installer.py``. Optionally you can pass a number of arguments - to specify locations of various files. Please see the top of +* Run ``build-installer.py``. Optionally you can pass a number of arguments + to specify locations of various files. Please see the top of ``build-installer.py`` for its usage. - Running this script takes some time, I will not only build Python itself + Running this script takes some time, it will not only build Python itself but also some 3th-party libraries that are needed for extensions. * When done the script will tell you where the DMG image is (by default somewhere in ``/tmp/_py``). -Building a 4-way universal installer -.................................... +Building other universal installers +................................... It is also possible to build a 4-way universal installer that runs on -OSX Leopard or later:: +OS X Leopard or later:: - $ ./build-installer.py --dep-target=10.5 --universal-archs=all --sdk=/ + python 2.6 /build-installer.py \ + --dep-target=10.5 + --universal-archs=all + --sdk-path=/Developer/SDKs/MacOSX10.5.sdk + +This requires that the deployment target is 10.5, and hence +also that you are building on at least OS X 10.5. 4-way includes +``i386``, ``x86_64``, ``ppc``, and ``ppc64`` (G5). ``ppc64`` executable +variants can only be run on G5 machines running 10.5. Note that, +while OS X 10.6 is only supported on Intel-based machines, it is possible +to run ``ppc`` (32-bit) executables unmodified thanks to the Rosetta ppc +emulation in OS X 10.5 and 10.6. + +Other ``--universal-archs`` options are ``64-bit`` (``x86_64``, ``ppc64``), +and ``3-way`` (``ppc``, ``i386``, ``x86_64``). None of these options +are regularly exercised; use at your own risk. -This requires that the deployment target is 10.5 (or later), and hence -also that your building on at least OSX 10.5. Testing ------- -The resulting binaries should work on MacOSX 10.3.9 or later. I usually run -the installer on a 10.3.9, a 10.4.x PPC and a 10.4.x Intel system and then -run the testsuite to make sure. - - -Announcements -------------- - -(This is mostly of historic interest) - -When all is done, announcements can be posted to at least the following -places: -- pythonmac-sig at python.org -- python-dev at python.org -- python-announce at python.org -- archivist at info-mac.org -- adcnews at apple.com -- news at macnn.com -- http://www.macupdate.com -- http://guide.apple.com/usindex.lasso -- http://www.apple.com/downloads/macosx/submit -- http://www.versiontracker.com/ (userid Jack.Jansen at oratrix.com) -- http://www.macshareware.net (userid jackjansen) +Ideally, the resulting binaries should be installed and the test suite run +on all supported OS X releases and architectures. As a practical matter, +that is generally not possible. At a minimum, variant 1 should be run on +at least one Intel, one PPC G4, and one PPC G3 system and one each of +OS X 10.6, 10.5, 10.4, and 10.3.9. Not all tests run on 10.3.9. +Variant 2 should be run on 10.6 in both 32-bit and 64-bit modes.:: + + arch -i386 /usr/local/bin/pythonn.n -m test.regrtest -w -u all + arch -X86_64 /usr/local/bin/pythonn.n -m test.regrtest -w -u all + +Certain tests will be skipped and some cause the interpreter to fail +which will likely generate ``Python quit unexpectedly`` alert messages +to be generated at several points during a test run. These can +be ignored. -Also, check out Stephan Deibels http://pythonology.org/market contact list Modified: python/branches/release27-maint/Mac/BuildScript/build-installer.py ============================================================================== --- python/branches/release27-maint/Mac/BuildScript/build-installer.py (original) +++ python/branches/release27-maint/Mac/BuildScript/build-installer.py Sun Jan 30 02:43:40 2011 @@ -1,12 +1,14 @@ -#!/usr/bin/env python +#!/usr/bin/python """ -This script is used to build the "official unofficial" universal build on -Mac OS X. It requires Mac OS X 10.4, Xcode 2.2 and the 10.4u SDK to do its -work. 64-bit or four-way universal builds require at least OS X 10.5 and -the 10.5 SDK. - -Please ensure that this script keeps working with Python 2.3, to avoid -bootstrap issues (/usr/bin/python is Python 2.3 on OSX 10.4) +This script is used to build "official" universal installers on Mac OS X. +It requires at least Mac OS X 10.4, Xcode 2.2 and the 10.4u SDK for +32-bit builds. 64-bit or four-way universal builds require at least +OS X 10.5 and the 10.5 SDK. + +Please ensure that this script keeps working with Python 2.5, to avoid +bootstrap issues (/usr/bin/python is Python 2.5 on OSX 10.5). Sphinx, +which is used to build the documentation, currently requires at least +Python 2.4. Usage: see USAGE variable in the script. """ @@ -40,16 +42,19 @@ if ln.startswith(variable): value = ln[len(variable):].strip() return value[1:-1] + raise RuntimeError, "Cannot find variable %s" % variable[:-1] def getVersion(): return grepValue(os.path.join(SRCDIR, 'configure'), 'PACKAGE_VERSION') +def getVersionTuple(): + return tuple([int(n) for n in getVersion().split('.')]) + def getFullVersion(): fn = os.path.join(SRCDIR, 'Include', 'patchlevel.h') for ln in open(fn): if 'PY_VERSION' in ln: return ln.split()[-1][1:-1] - raise RuntimeError, "Cannot find full version??" # The directory we'll use to create the build (will be erased and recreated) @@ -114,6 +119,8 @@ CC = target_cc_map[DEPTARGET] +PYTHON_3 = getVersionTuple() >= (3, 0) + USAGE = textwrap.dedent("""\ Usage: build_python [options] @@ -139,9 +146,9 @@ if DEPTARGET < '10.5': result.extend([ dict( - name="Bzip2 1.0.5", - url="http://www.bzip.org/1.0.5/bzip2-1.0.5.tar.gz", - checksum='3c15a0c8d1d3ee1c46a1634d00617b1a', + name="Bzip2 1.0.6", + url="http://bzip.org/1.0.6/bzip2-1.0.6.tar.gz", + checksum='00b516f4704d4a7cb50a1d97e6e8e15b', configure=None, install='make install CC=%s PREFIX=%s/usr/local/ CFLAGS="-arch %s -isysroot %s"'%( CC, @@ -164,29 +171,33 @@ ), dict( # Note that GNU readline is GPL'd software - name="GNU Readline 5.1.4", - url="http://ftp.gnu.org/pub/gnu/readline/readline-5.1.tar.gz" , - checksum='7ee5a692db88b30ca48927a13fd60e46', + name="GNU Readline 6.1.2", + url="http://ftp.gnu.org/pub/gnu/readline/readline-6.1.tar.gz" , + checksum='fc2f7e714fe792db1ce6ddc4c9fb4ef3', patchlevel='0', patches=[ # The readline maintainers don't do actual micro releases, but # just ship a set of patches. - 'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-001', - 'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-002', - 'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-003', - 'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-004', + 'http://ftp.gnu.org/pub/gnu/readline/readline-6.1-patches/readline61-001', + 'http://ftp.gnu.org/pub/gnu/readline/readline-6.1-patches/readline61-002', ] ), dict( - name="SQLite 3.6.11", - url="http://www.sqlite.org/sqlite-3.6.11.tar.gz", - checksum='7ebb099696ab76cc6ff65dd496d17858', + name="SQLite 3.7.4", + url="http://www.sqlite.org/sqlite-autoconf-3070400.tar.gz", + checksum='8f0c690bfb33c3cbbc2471c3d9ba0158', + configure_env=('CFLAGS="-Os' + ' -DSQLITE_ENABLE_FTS3' + ' -DSQLITE_ENABLE_FTS3_PARENTHESIS' + ' -DSQLITE_ENABLE_RTREE' + ' -DSQLITE_TCL=0' + '"'), configure_pre=[ '--enable-threadsafe', - '--enable-tempstore', '--enable-shared=no', '--enable-static=yes', - '--disable-tcl', + '--disable-readline', + '--disable-dependency-tracking', ] ), dict( @@ -194,6 +205,7 @@ url="http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.5.tar.gz", checksum='e73c1ac10b4bfc46db43b2ddfd6244ef', configure_pre=[ + "--enable-widec", "--without-cxx", "--without-ada", "--without-progs", @@ -220,24 +232,26 @@ ), ]) - result.extend([ - dict( - name="Sleepycat DB 4.7.25", - url="http://download.oracle.com/berkeley-db/db-4.7.25.tar.gz", - checksum='ec2b87e833779681a0c3a814aa71359e', - buildDir="build_unix", - configure="../dist/configure", - configure_pre=[ - '--includedir=/usr/local/include/db4', - ] - ), - ]) + if not PYTHON_3: + result.extend([ + dict( + name="Sleepycat DB 4.7.25", + url="http://download.oracle.com/berkeley-db/db-4.7.25.tar.gz", + checksum='ec2b87e833779681a0c3a814aa71359e', + buildDir="build_unix", + configure="../dist/configure", + configure_pre=[ + '--includedir=/usr/local/include/db4', + ] + ), + ]) return result # Instructions for building packages inside the .mpkg. def pkg_recipes(): + unselected_for_python3 = ('selected', 'unselected')[PYTHON_3] result = [ dict( name="PythonFramework", @@ -308,7 +322,7 @@ topdir="/Library/Frameworks/Python.framework", source="/empty-dir", required=False, - selected='selected', + selected=unselected_for_python3, ), ] @@ -326,7 +340,7 @@ topdir="/Library/Frameworks/Python.framework", source="/empty-dir", required=False, - selected='selected', + selected=unselected_for_python3, ) ) return result @@ -393,6 +407,9 @@ Check that we're running on a supported system. """ + if sys.version_info[0:2] < (2, 4): + fatal("This script must be run with Python 2.4 or later") + if platform.system() != 'Darwin': fatal("This script should be run on a Mac OS X 10.4 (or later) system") @@ -412,15 +429,16 @@ # to install a newer patch level. for framework in ['Tcl', 'Tk']: - fw = dict(lower=framework.lower(), - upper=framework.upper(), - cap=framework.capitalize()) - fwpth = "Library/Frameworks/%(cap)s.framework/%(lower)sConfig.sh" % fw - sysfw = os.path.join('/System', fwpth) + #fw = dict(lower=framework.lower(), + # upper=framework.upper(), + # cap=framework.capitalize()) + #fwpth = "Library/Frameworks/%(cap)s.framework/%(lower)sConfig.sh" % fw + fwpth = 'Library/Frameworks/Tcl.framework/Versions/Current' + sysfw = os.path.join(SDKPATH, 'System', fwpth) libfw = os.path.join('/', fwpth) usrfw = os.path.join(os.getenv('HOME'), fwpth) - version = "%(upper)s_VERSION" % fw - if getTclTkVersion(libfw, version) != getTclTkVersion(sysfw, version): + #version = "%(upper)s_VERSION" % fw + if os.readlink(libfw) != os.readlink(sysfw): fatal("Version of %s must match %s" % (libfw, sysfw) ) if os.path.exists(usrfw): fatal("Please rename %s to avoid possible dynamic load issues." @@ -690,6 +708,9 @@ configure_args.insert(0, configure) configure_args = [ shellQuote(a) for a in configure_args ] + if 'configure_env' in recipe: + configure_args.insert(0, recipe['configure_env']) + print "Running configure for %s"%(name,) runCommand(' '.join(configure_args) + ' 2>&1') @@ -745,9 +766,9 @@ shutil.rmtree(buildDir) if os.path.exists(rootDir): shutil.rmtree(rootDir) - os.mkdir(buildDir) - os.mkdir(rootDir) - os.mkdir(os.path.join(rootDir, 'empty-dir')) + os.makedirs(buildDir) + os.makedirs(rootDir) + os.makedirs(os.path.join(rootDir, 'empty-dir')) curdir = os.getcwd() os.chdir(buildDir) @@ -767,18 +788,20 @@ print "Running configure..." runCommand("%s -C --enable-framework --enable-universalsdk=%s " "--with-universal-archs=%s " + "%s " "LDFLAGS='-g -L%s/libraries/usr/local/lib' " "OPT='-g -O3 -I%s/libraries/usr/local/include' 2>&1"%( shellQuote(os.path.join(SRCDIR, 'configure')), shellQuote(SDKPATH), UNIVERSALARCHS, + (' ', '--with-computed-gotos ')[PYTHON_3], shellQuote(WORKDIR)[1:-1], shellQuote(WORKDIR)[1:-1])) print "Running make" runCommand("make") - print "Running make frameworkinstall" - runCommand("make frameworkinstall DESTDIR=%s"%( + print "Running make install" + runCommand("make install DESTDIR=%s"%( shellQuote(rootDir))) print "Running make frameworkinstallextras" @@ -817,12 +840,33 @@ os.chmod(p, stat.S_IMODE(st.st_mode) | stat.S_IWGRP) os.chown(p, -1, gid) + if PYTHON_3: + LDVERSION=None + VERSION=None + ABIFLAGS=None + + fp = open(os.path.join(buildDir, 'Makefile'), 'r') + for ln in fp: + if ln.startswith('VERSION='): + VERSION=ln.split()[1] + if ln.startswith('ABIFLAGS='): + ABIFLAGS=ln.split()[1] + if ln.startswith('LDVERSION='): + LDVERSION=ln.split()[1] + fp.close() + + LDVERSION = LDVERSION.replace('$(VERSION)', VERSION) + LDVERSION = LDVERSION.replace('$(ABIFLAGS)', ABIFLAGS) + config_suffix = '-' + LDVERSION + else: + config_suffix = '' # Python 2.x + # We added some directories to the search path during the configure # phase. Remove those because those directories won't be there on # the end-users system. path =os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework', 'Versions', version, 'lib', 'python%s'%(version,), - 'config', 'Makefile') + 'config' + config_suffix, 'Makefile') fp = open(path, 'r') data = fp.read() fp.close() @@ -847,7 +891,11 @@ os.chdir(curdir) - + if PYTHON_3: + # Remove the 'Current' link, that way we don't accidently mess + # with an already installed version of python 2 + os.unlink(os.path.join(rootDir, 'Library', 'Frameworks', + 'Python.framework', 'Versions', 'Current')) def patchFile(inPath, outPath): data = fileContents(inPath) Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Sun Jan 30 02:43:40 2011 @@ -160,6 +160,14 @@ Build ----- +- Issue #11054: Allow Mac OS X installer builds to again work on 10.5 with + the system-provided Python. + +- Issue #10843: Update third-party library versions used in OS X + 32-bit installer builds: bzip2 1.0.6, readline 6.1.2, SQLite 3.7.4 + (with FTS3/FTS4 and RTREE enabled), and ncursesw 5.5 (wide-char + support enabled). + - Don't run pgen twice when using make -j. - Issue #7716: Under Solaris, don't assume existence of /usr/xpg4/bin/grep in From solipsis at pitrou.net Sun Jan 30 05:06:41 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Sun, 30 Jan 2011 05:06:41 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r88247): sum=0 Message-ID: py3k results for svn r88247 (hg cset 1d293974c133) -------------------------------------------------- Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflog_avSm5', '-x'] From python-checkins at python.org Sun Jan 30 06:37:16 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 30 Jan 2011 06:37:16 +0100 (CET) Subject: [Python-checkins] r88251 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110130053716.81D99EE9C3@mail.python.org> Author: raymond.hettinger Date: Sun Jan 30 06:37:16 2011 New Revision: 88251 Log: List known build/install problems for OS X. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Sun Jan 30 06:37:16 2011 @@ -2443,7 +2443,10 @@ :source:`Misc/NEWS` file for a complete list. Also, there were a number of updates to the OS X build, see -:source:`Mac/BuildScript/README.txt`. +:source:`Mac/BuildScript/README.txt` for details. For users running a 32/64-bit +build, there is a known problem with the default Tcl/Tk on OS X 10.6. +Accordingly, we recommend installing an updated alternative such as +`ActiveState Tcl/Tk 8.5 `_ . Porting to Python 3.2 ===================== From python-checkins at python.org Sun Jan 30 07:21:29 2011 From: python-checkins at python.org (r.david.murray) Date: Sun, 30 Jan 2011 07:21:29 +0100 (CET) Subject: [Python-checkins] r88252 - in python/branches/py3k: Doc/library/mailbox.rst Lib/mailbox.py Lib/test/test_mailbox.py Misc/NEWS Message-ID: <20110130062129.02D68EE983@mail.python.org> Author: r.david.murray Date: Sun Jan 30 07:21:28 2011 New Revision: 88252 Log: #9124: mailbox now accepts binary input and uses binary internally Although this patch contains API changes and is rather weighty for an RC phase, the mailbox module was essentially unusable without the patch since it would produce UnicodeErrors when handling non-ascii input at arbitrary and somewhat mysterious places, and any non-trivial amount of email processing will encounter messages with non-ascii bytes. The release manager approved the patch application. The changes allow binary input, and reject non-ASCII string input early with a useful message instead of failing mysteriously later. Binary is used internally for reading and writing the mailbox files. StringIO and Text file input are deprecated. Initial patch by Victor Stinner, validated and expanded by R. David Murray. Modified: python/branches/py3k/Doc/library/mailbox.rst python/branches/py3k/Lib/mailbox.py python/branches/py3k/Lib/test/test_mailbox.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Doc/library/mailbox.rst ============================================================================== --- python/branches/py3k/Doc/library/mailbox.rst (original) +++ python/branches/py3k/Doc/library/mailbox.rst Sun Jan 30 07:21:28 2011 @@ -81,13 +81,16 @@ it. Parameter *message* may be a :class:`Message` instance, an - :class:`email.Message.Message` instance, a string, or a file-like object - (which should be open in text mode). If *message* is an instance of the + :class:`email.Message.Message` instance, a string, a byte string, or a + file-like object (which should be open in binary mode). If *message* is + an instance of the appropriate format-specific :class:`Message` subclass (e.g., if it's an :class:`mboxMessage` instance and this is an :class:`mbox` instance), its format-specific information is used. Otherwise, reasonable defaults for format-specific information are used. + .. versionchanged:: 3.2 support for binary input + .. method:: remove(key) __delitem__(key) @@ -108,8 +111,9 @@ :exc:`KeyError` exception if no message already corresponds to *key*. As with :meth:`add`, parameter *message* may be a :class:`Message` - instance, an :class:`email.Message.Message` instance, a string, or a - file-like object (which should be open in text mode). If *message* is an + instance, an :class:`email.Message.Message` instance, a string, a byte + string, or a file-like object (which should be open in binary mode). If + *message* is an instance of the appropriate format-specific :class:`Message` subclass (e.g., if it's an :class:`mboxMessage` instance and this is an :class:`mbox` instance), its format-specific information is @@ -171,10 +175,20 @@ raise a :exc:`KeyError` exception if no such message exists. + .. method:: get_bytes(key) + + Return a byte representation of the message corresponding to *key*, or + raise a :exc:`KeyError` exception if no such message exists. + + .. versionadded:: 3.2 + + .. method:: get_string(key) Return a string representation of the message corresponding to *key*, or - raise a :exc:`KeyError` exception if no such message exists. + raise a :exc:`KeyError` exception if no such message exists. The + message is processed through :class:`email.message.Message` to + convert it to a 7bit clean representation. .. method:: get_file(key) @@ -184,9 +198,11 @@ file-like object behaves as if open in binary mode. This file should be closed once it is no longer needed. - .. versionadded:: 3.2 - The file-like object supports the context manager protocol, so that - you can use a :keyword:`with` statement to automatically close it. + .. versionchanged:: 3.2 + The file object really is a binary file; previously it was incorrectly + returned in text mode. Also, the file-like object now supports the + context manager protocol: you can use a :keyword:`with` statement to + automatically close it. .. note:: @@ -746,9 +762,11 @@ If *message* is omitted, the new instance is created in a default, empty state. If *message* is an :class:`email.Message.Message` instance, its contents are copied; furthermore, any format-specific information is converted insofar as - possible if *message* is a :class:`Message` instance. If *message* is a string + possible if *message* is a :class:`Message` instance. If *message* is a string, + a byte string, or a file, it should contain an :rfc:`2822`\ -compliant message, which is read - and parsed. + and parsed. Files should be open in binary mode, but text mode files + are accepted for backward compatibility. The format-specific state and behaviors offered by subclasses vary, but in general it is only the properties that are not specific to a particular Modified: python/branches/py3k/Lib/mailbox.py ============================================================================== --- python/branches/py3k/Lib/mailbox.py (original) +++ python/branches/py3k/Lib/mailbox.py Sun Jan 30 07:21:28 2011 @@ -15,6 +15,7 @@ import socket import errno import copy +import warnings import email import email.message import email.generator @@ -31,6 +32,8 @@ 'Message', 'MaildirMessage', 'mboxMessage', 'MHMessage', 'BabylMessage', 'MMDFMessage'] +linesep = os.linesep.encode('ascii') + class Mailbox: """A group of messages in a particular place.""" @@ -80,7 +83,14 @@ raise NotImplementedError('Method must be implemented by subclass') def get_string(self, key): - """Return a string representation or raise a KeyError.""" + """Return a string representation or raise a KeyError. + + Uses email.message.Message to create a 7bit clean string + representation of the message.""" + return email.message_from_bytes(self.get_bytes(key)).as_string() + + def get_bytes(self, key): + """Return a byte string representation or raise a KeyError.""" raise NotImplementedError('Method must be implemented by subclass') def get_file(self, key): @@ -186,31 +196,55 @@ """Flush and close the mailbox.""" raise NotImplementedError('Method must be implemented by subclass') + def _string_to_bytes(self, message): + # If a message is not 7bit clean, we refuse to handle it since it + # likely came from reading invalid messages in text mode, and that way + # lies mojibake. + try: + return message.encode('ascii') + except UnicodeError: + raise ValueError("String input must be ASCII-only; " + "use bytes or a Message instead") + def _dump_message(self, message, target, mangle_from_=False): - # This assumes the target file is open in *text* mode with the - # desired encoding and newline setting. + # This assumes the target file is open in binary mode. """Dump message contents to target file.""" if isinstance(message, email.message.Message): - buffer = io.StringIO() - gen = email.generator.Generator(buffer, mangle_from_, 0) + buffer = io.BytesIO() + gen = email.generator.BytesGenerator(buffer, mangle_from_, 0) gen.flatten(message) buffer.seek(0) data = buffer.read() - ##data = data.replace('\n', os.linesep) + data = data.replace(b'\n', linesep) target.write(data) - elif isinstance(message, str): + elif isinstance(message, (str, bytes, io.StringIO)): + if isinstance(message, io.StringIO): + warnings.warn("Use of StringIO input is deprecated, " + "use BytesIO instead", DeprecationWarning, 3) + message = message.getvalue() + if isinstance(message, str): + message = self._string_to_bytes(message) if mangle_from_: - message = message.replace('\nFrom ', '\n>From ') - ##message = message.replace('\n', os.linesep) + message = message.replace(b'\nFrom ', b'\n>From ') + message = message.replace(b'\n', linesep) target.write(message) elif hasattr(message, 'read'): + if hasattr(message, 'buffer'): + warnings.warn("Use of text mode files is deprecated, " + "use a binary mode file instead", DeprecationWarning, 3) + message = message.buffer while True: line = message.readline() + # Universal newline support. + if line.endswith(b'\r\n'): + line = line[:-2] + b'\n' + elif line.endswith(b'\r'): + line = line[:-1] + b'\n' if not line: break - if mangle_from_ and line.startswith('From '): - line = '>From ' + line[5:] - ##line = line.replace('\n', os.linesep) + if mangle_from_ and line.startswith(b'From '): + line = b'>From ' + line[5:] + line = line.replace(b'\n', linesep) target.write(line) else: raise TypeError('Invalid message type: %s' % type(message)) @@ -319,7 +353,7 @@ def get_message(self, key): """Return a Message representation or raise a KeyError.""" subpath = self._lookup(key) - f = open(os.path.join(self._path, subpath), 'r', newline='') + f = open(os.path.join(self._path, subpath), 'rb') try: if self._factory: msg = self._factory(f) @@ -334,17 +368,17 @@ msg.set_date(os.path.getmtime(os.path.join(self._path, subpath))) return msg - def get_string(self, key): - """Return a string representation or raise a KeyError.""" - f = open(os.path.join(self._path, self._lookup(key)), 'r', newline='') + def get_bytes(self, key): + """Return a bytes representation or raise a KeyError.""" + f = open(os.path.join(self._path, self._lookup(key)), 'rb') try: - return f.read() + return f.read().replace(linesep, b'\n') finally: f.close() def get_file(self, key): """Return a file-like representation or raise a KeyError.""" - f = open(os.path.join(self._path, self._lookup(key)), 'r', newline='') + f = open(os.path.join(self._path, self._lookup(key)), 'rb') return _ProxyFile(f) def iterkeys(self): @@ -534,15 +568,15 @@ """Initialize a single-file mailbox.""" Mailbox.__init__(self, path, factory, create) try: - f = open(self._path, 'r+', newline='') + f = open(self._path, 'rb+') except IOError as e: if e.errno == errno.ENOENT: if create: - f = open(self._path, 'w+', newline='') + f = open(self._path, 'wb+') else: raise NoSuchMailboxError(self._path) elif e.errno == errno.EACCES: - f = open(self._path, 'r', newline='') + f = open(self._path, 'rb') else: raise self._file = f @@ -708,20 +742,25 @@ """Return a Message representation or raise a KeyError.""" start, stop = self._lookup(key) self._file.seek(start) - from_line = self._file.readline().replace(os.linesep, '') + from_line = self._file.readline().replace(linesep, b'') string = self._file.read(stop - self._file.tell()) - msg = self._message_factory(string.replace(os.linesep, '\n')) - msg.set_from(from_line[5:]) + msg = self._message_factory(string.replace(linesep, b'\n')) + msg.set_from(from_line[5:].decode('ascii')) return msg def get_string(self, key, from_=False): """Return a string representation or raise a KeyError.""" + return email.message_from_bytes( + self.get_bytes(key)).as_string(unixfrom=from_) + + def get_bytes(self, key, from_=False): + """Return a string representation or raise a KeyError.""" start, stop = self._lookup(key) self._file.seek(start) if not from_: self._file.readline() string = self._file.read(stop - self._file.tell()) - return string.replace(os.linesep, '\n') + return string.replace(linesep, b'\n') def get_file(self, key, from_=False): """Return a file-like representation or raise a KeyError.""" @@ -734,22 +773,27 @@ def _install_message(self, message): """Format a message and blindly write to self._file.""" from_line = None - if isinstance(message, str) and message.startswith('From '): - newline = message.find('\n') + if isinstance(message, str): + message = self._string_to_bytes(message) + if isinstance(message, bytes) and message.startswith(b'From '): + newline = message.find(b'\n') if newline != -1: from_line = message[:newline] message = message[newline + 1:] else: from_line = message - message = '' + message = b'' elif isinstance(message, _mboxMMDFMessage): - from_line = 'From ' + message.get_from() + author = message.get_from().encode('ascii') + from_line = b'From ' + author elif isinstance(message, email.message.Message): from_line = message.get_unixfrom() # May be None. + if from_line is not None: + from_line = from_line.encode('ascii') if from_line is None: - from_line = 'From MAILER-DAEMON %s' % time.asctime(time.gmtime()) + from_line = b'From MAILER-DAEMON ' + time.asctime(time.gmtime()).encode() start = self._file.tell() - self._file.write(from_line + os.linesep) + self._file.write(from_line + linesep) self._dump_message(message, self._file, self._mangle_from_) stop = self._file.tell() return (start, stop) @@ -768,7 +812,7 @@ def _pre_message_hook(self, f): """Called before writing each message to file f.""" if f.tell() != 0: - f.write(os.linesep) + f.write(linesep) def _generate_toc(self): """Generate key-to-(start, stop) table of contents.""" @@ -777,9 +821,9 @@ while True: line_pos = self._file.tell() line = self._file.readline() - if line.startswith('From '): + if line.startswith(b'From '): if len(stops) < len(starts): - stops.append(line_pos - len(os.linesep)) + stops.append(line_pos - len(linesep)) starts.append(line_pos) elif not line: stops.append(line_pos) @@ -799,11 +843,11 @@ def _pre_message_hook(self, f): """Called before writing each message to file f.""" - f.write('\001\001\001\001' + os.linesep) + f.write(b'\001\001\001\001' + linesep) def _post_message_hook(self, f): """Called after writing each message to file f.""" - f.write(os.linesep + '\001\001\001\001' + os.linesep) + f.write(linesep + b'\001\001\001\001' + linesep) def _generate_toc(self): """Generate key-to-(start, stop) table of contents.""" @@ -814,14 +858,14 @@ line_pos = next_pos line = self._file.readline() next_pos = self._file.tell() - if line.startswith('\001\001\001\001' + os.linesep): + if line.startswith(b'\001\001\001\001' + linesep): starts.append(next_pos) while True: line_pos = next_pos line = self._file.readline() next_pos = self._file.tell() - if line == '\001\001\001\001' + os.linesep: - stops.append(line_pos - len(os.linesep)) + if line == b'\001\001\001\001' + linesep: + stops.append(line_pos - len(linesep)) break elif not line: stops.append(line_pos) @@ -890,7 +934,7 @@ """Replace the keyed message; raise KeyError if it doesn't exist.""" path = os.path.join(self._path, str(key)) try: - f = open(path, 'r+', newline='') + f = open(path, 'rb+') except IOError as e: if e.errno == errno.ENOENT: raise KeyError('No message with key: %s' % key) @@ -914,9 +958,9 @@ """Return a Message representation or raise a KeyError.""" try: if self._locked: - f = open(os.path.join(self._path, str(key)), 'r+', newline='') + f = open(os.path.join(self._path, str(key)), 'rb+') else: - f = open(os.path.join(self._path, str(key)), 'r', newline='') + f = open(os.path.join(self._path, str(key)), 'rb') except IOError as e: if e.errno == errno.ENOENT: raise KeyError('No message with key: %s' % key) @@ -937,13 +981,13 @@ msg.add_sequence(name) return msg - def get_string(self, key): - """Return a string representation or raise a KeyError.""" + def get_bytes(self, key): + """Return a bytes representation or raise a KeyError.""" try: if self._locked: - f = open(os.path.join(self._path, str(key)), 'r+', newline='') + f = open(os.path.join(self._path, str(key)), 'rb+') else: - f = open(os.path.join(self._path, str(key)), 'r', newline='') + f = open(os.path.join(self._path, str(key)), 'rb') except IOError as e: if e.errno == errno.ENOENT: raise KeyError('No message with key: %s' % key) @@ -953,7 +997,7 @@ if self._locked: _lock_file(f) try: - return f.read() + return f.read().replace(linesep, b'\n') finally: if self._locked: _unlock_file(f) @@ -963,7 +1007,7 @@ def get_file(self, key): """Return a file-like representation or raise a KeyError.""" try: - f = open(os.path.join(self._path, str(key)), 'r', newline='') + f = open(os.path.join(self._path, str(key)), 'rb') except IOError as e: if e.errno == errno.ENOENT: raise KeyError('No message with key: %s' % key) @@ -1041,7 +1085,7 @@ def get_sequences(self): """Return a name-to-key-list dictionary to define each sequence.""" results = {} - f = open(os.path.join(self._path, '.mh_sequences'), 'r', newline='') + f = open(os.path.join(self._path, '.mh_sequences'), 'r') try: all_keys = set(self.keys()) for line in f: @@ -1067,13 +1111,13 @@ def set_sequences(self, sequences): """Set sequences using the given name-to-key-list dictionary.""" - f = open(os.path.join(self._path, '.mh_sequences'), 'r+', newline='') + f = open(os.path.join(self._path, '.mh_sequences'), 'r+') try: os.close(os.open(f.name, os.O_WRONLY | os.O_TRUNC)) for name, keys in sequences.items(): if len(keys) == 0: continue - f.write('%s:' % name) + f.write(name + ':') prev = None completing = False for key in sorted(set(keys)): @@ -1168,50 +1212,55 @@ """Return a Message representation or raise a KeyError.""" start, stop = self._lookup(key) self._file.seek(start) - self._file.readline() # Skip '1,' line specifying labels. - original_headers = io.StringIO() + self._file.readline() # Skip b'1,' line specifying labels. + original_headers = io.BytesIO() while True: line = self._file.readline() - if line == '*** EOOH ***' + os.linesep or not line: + if line == b'*** EOOH ***' + linesep or not line: break - original_headers.write(line.replace(os.linesep, '\n')) - visible_headers = io.StringIO() + original_headers.write(line.replace(linesep, b'\n')) + visible_headers = io.BytesIO() while True: line = self._file.readline() - if line == os.linesep or not line: + if line == linesep or not line: break - visible_headers.write(line.replace(os.linesep, '\n')) - body = self._file.read(stop - self._file.tell()).replace(os.linesep, - '\n') + visible_headers.write(line.replace(linesep, b'\n')) + # Read up to the stop, or to the end + n = stop - self._file.tell() + assert n >= 0 + body = self._file.read(n) + body = body.replace(linesep, b'\n') msg = BabylMessage(original_headers.getvalue() + body) msg.set_visible(visible_headers.getvalue()) if key in self._labels: msg.set_labels(self._labels[key]) return msg - def get_string(self, key): + def get_bytes(self, key): """Return a string representation or raise a KeyError.""" start, stop = self._lookup(key) self._file.seek(start) - self._file.readline() # Skip '1,' line specifying labels. - original_headers = io.StringIO() + self._file.readline() # Skip b'1,' line specifying labels. + original_headers = io.BytesIO() while True: line = self._file.readline() - if line == '*** EOOH ***' + os.linesep or not line: + if line == b'*** EOOH ***' + linesep or not line: break - original_headers.write(line.replace(os.linesep, '\n')) + original_headers.write(line.replace(linesep, b'\n')) while True: line = self._file.readline() - if line == os.linesep or not line: + if line == linesep or not line: break - return original_headers.getvalue() + \ - self._file.read(stop - self._file.tell()).replace(os.linesep, - '\n') + headers = original_headers.getvalue() + n = stop - self._file.tell() + assert n >= 0 + data = self._file.read(n) + data = data.replace(linesep, b'\n') + return headers + data def get_file(self, key): """Return a file-like representation or raise a KeyError.""" - return io.StringIO(self.get_string(key).replace('\n', - os.linesep)) + return io.BytesIO(self.get_bytes(key).replace(b'\n', linesep)) def get_labels(self): """Return a list of user-defined labels in the mailbox.""" @@ -1232,19 +1281,19 @@ line_pos = next_pos line = self._file.readline() next_pos = self._file.tell() - if line == '\037\014' + os.linesep: + if line == b'\037\014' + linesep: if len(stops) < len(starts): - stops.append(line_pos - len(os.linesep)) + stops.append(line_pos - len(linesep)) starts.append(next_pos) labels = [label.strip() for label - in self._file.readline()[1:].split(',') + in self._file.readline()[1:].split(b',') if label.strip()] label_lists.append(labels) - elif line == '\037' or line == '\037' + os.linesep: + elif line == b'\037' or line == b'\037' + linesep: if len(stops) < len(starts): - stops.append(line_pos - len(os.linesep)) + stops.append(line_pos - len(linesep)) elif not line: - stops.append(line_pos - len(os.linesep)) + stops.append(line_pos - len(linesep)) break self._toc = dict(enumerate(zip(starts, stops))) self._labels = dict(enumerate(label_lists)) @@ -1254,17 +1303,21 @@ def _pre_mailbox_hook(self, f): """Called before writing the mailbox to file f.""" - f.write('BABYL OPTIONS:%sVersion: 5%sLabels:%s%s\037' % - (os.linesep, os.linesep, ','.join(self.get_labels()), - os.linesep)) + babyl = b'BABYL OPTIONS:' + linesep + babyl += b'Version: 5' + linesep + labels = self.get_labels() + labels = (label.encode() for label in labels) + babyl += b'Labels:' + b','.join(labels) + linesep + babyl += b'\037' + f.write(babyl) def _pre_message_hook(self, f): """Called before writing each message to file f.""" - f.write('\014' + os.linesep) + f.write(b'\014' + linesep) def _post_message_hook(self, f): """Called after writing each message to file f.""" - f.write(os.linesep + '\037') + f.write(linesep + b'\037') def _install_message(self, message): """Write message contents and return (start, stop).""" @@ -1277,68 +1330,80 @@ special_labels.append(label) else: labels.append(label) - self._file.write('1') + self._file.write(b'1') for label in special_labels: - self._file.write(', ' + label) - self._file.write(',,') + self._file.write(b', ' + label.encode()) + self._file.write(b',,') for label in labels: - self._file.write(' ' + label + ',') - self._file.write(os.linesep) + self._file.write(b' ' + label.encode() + b',') + self._file.write(linesep) else: - self._file.write('1,,' + os.linesep) + self._file.write(b'1,,' + linesep) if isinstance(message, email.message.Message): - orig_buffer = io.StringIO() - orig_generator = email.generator.Generator(orig_buffer, False, 0) + orig_buffer = io.BytesIO() + orig_generator = email.generator.BytesGenerator(orig_buffer, False, 0) orig_generator.flatten(message) orig_buffer.seek(0) while True: line = orig_buffer.readline() - self._file.write(line.replace('\n', os.linesep)) - if line == '\n' or not line: + self._file.write(line.replace(b'\n', linesep)) + if line == b'\n' or not line: break - self._file.write('*** EOOH ***' + os.linesep) + self._file.write(b'*** EOOH ***' + linesep) if isinstance(message, BabylMessage): - vis_buffer = io.StringIO() - vis_generator = email.generator.Generator(vis_buffer, False, 0) + vis_buffer = io.BytesIO() + vis_generator = email.generator.BytesGenerator(vis_buffer, False, 0) vis_generator.flatten(message.get_visible()) while True: line = vis_buffer.readline() - self._file.write(line.replace('\n', os.linesep)) - if line == '\n' or not line: + self._file.write(line.replace(b'\n', linesep)) + if line == b'\n' or not line: break else: orig_buffer.seek(0) while True: line = orig_buffer.readline() - self._file.write(line.replace('\n', os.linesep)) - if line == '\n' or not line: + self._file.write(line.replace(b'\n', linesep)) + if line == b'\n' or not line: break while True: buffer = orig_buffer.read(4096) # Buffer size is arbitrary. if not buffer: break - self._file.write(buffer.replace('\n', os.linesep)) - elif isinstance(message, str): - body_start = message.find('\n\n') + 2 + self._file.write(buffer.replace(b'\n', linesep)) + elif isinstance(message, (bytes, str, io.StringIO)): + if isinstance(message, io.StringIO): + warnings.warn("Use of StringIO input is deprecated, " + "use BytesIO instead", DeprecationWarning, 3) + message = message.getvalue() + if isinstance(message, str): + message = self._string_to_bytes(message) + body_start = message.find(b'\n\n') + 2 if body_start - 2 != -1: - self._file.write(message[:body_start].replace('\n', - os.linesep)) - self._file.write('*** EOOH ***' + os.linesep) - self._file.write(message[:body_start].replace('\n', - os.linesep)) - self._file.write(message[body_start:].replace('\n', - os.linesep)) + self._file.write(message[:body_start].replace(b'\n', linesep)) + self._file.write(b'*** EOOH ***' + linesep) + self._file.write(message[:body_start].replace(b'\n', linesep)) + self._file.write(message[body_start:].replace(b'\n', linesep)) else: - self._file.write('*** EOOH ***' + os.linesep + os.linesep) - self._file.write(message.replace('\n', os.linesep)) + self._file.write(b'*** EOOH ***' + linesep + linesep) + self._file.write(message.replace(b'\n', linesep)) elif hasattr(message, 'readline'): + if hasattr(message, 'buffer'): + warnings.warn("Use of text mode files is deprecated, " + "use a binary mode file instead", DeprecationWarning, 3) + message = message.buffer original_pos = message.tell() first_pass = True while True: line = message.readline() - self._file.write(line.replace('\n', os.linesep)) - if line == '\n' or not line: - self._file.write('*** EOOH ***' + os.linesep) + # Universal newline support. + if line.endswith(b'\r\n'): + line = line[:-2] + b'\n' + elif line.endswith(b'\r'): + line = line[:-1] + b'\n' + self._file.write(line.replace(b'\n', linesep)) + if line == b'\n' or not line: + self._file.write(b'*** EOOH ***' + linesep) if first_pass: first_pass = False message.seek(original_pos) @@ -1348,7 +1413,7 @@ buffer = message.read(4096) # Buffer size is arbitrary. if not buffer: break - self._file.write(buffer.replace('\n', os.linesep)) + self._file.write(buffer.replace(b'\n', linesep)) else: raise TypeError('Invalid message type: %s' % type(message)) stop = self._file.tell() @@ -1364,10 +1429,14 @@ self._become_message(copy.deepcopy(message)) if isinstance(message, Message): message._explain_to(self) + elif isinstance(message, bytes): + self._become_message(email.message_from_bytes(message)) elif isinstance(message, str): self._become_message(email.message_from_string(message)) - elif hasattr(message, "read"): + elif isinstance(message, io.TextIOWrapper): self._become_message(email.message_from_file(message)) + elif hasattr(message, "read"): + self._become_message(email.message_from_binary_file(message)) elif message is None: email.message.Message.__init__(self) else: @@ -1631,7 +1700,7 @@ if not sequence in self._sequences: self._sequences.append(sequence) else: - raise TypeError('sequence must be a string: %s' % type(sequence)) + raise TypeError('sequence type must be str: %s' % type(sequence)) def remove_sequence(self, sequence): """Remove sequence from the list of sequences including the message.""" @@ -1791,6 +1860,10 @@ """Read bytes.""" return self._read(size, self._file.read) + def read1(self, size=None): + """Read bytes.""" + return self._read(size, self._file.read1) + def readline(self, size=None): """Read a line.""" return self._read(size, self._file.readline) @@ -1847,6 +1920,22 @@ def __exit__(self, *exc): self.close() + def readable(self): + return self._file.readable() + + def writable(self): + return self._file.writable() + + def seekable(self): + return self._file.seekable() + + def flush(self): + return self._file.flush() + + @property + def closed(self): + return self._file.closed + class _PartialFile(_ProxyFile): """A read-only wrapper of part of a file.""" @@ -1875,7 +1964,7 @@ """Read size bytes using read_method, honoring start and stop.""" remaining = self._stop - self._pos if remaining <= 0: - return '' + return b'' if size is None or size < 0 or size > remaining: size = remaining return _ProxyFile._read(self, size, read_method) @@ -1942,7 +2031,7 @@ """Create a file if it doesn't exist and open for reading and writing.""" fd = os.open(path, os.O_CREAT | os.O_EXCL | os.O_RDWR, 0o666) try: - return open(path, 'r+', newline='') + return open(path, 'rb+') finally: os.close(fd) Modified: python/branches/py3k/Lib/test/test_mailbox.py ============================================================================== --- python/branches/py3k/Lib/test/test_mailbox.py (original) +++ python/branches/py3k/Lib/test/test_mailbox.py Sun Jan 30 07:21:28 2011 @@ -7,8 +7,10 @@ import email.message import re import io +import tempfile from test import support import unittest +import textwrap import mailbox import glob try: @@ -48,6 +50,8 @@ class TestMailbox(TestBase): + maxDiff = None + _factory = None # Overridden by subclasses to reuse tests _template = 'From: foo\n\n%s' @@ -69,14 +73,108 @@ self.assertEqual(len(self._box), 2) keys.append(self._box.add(email.message_from_string(_sample_message))) self.assertEqual(len(self._box), 3) - keys.append(self._box.add(io.StringIO(_sample_message))) + keys.append(self._box.add(io.BytesIO(_bytes_sample_message))) self.assertEqual(len(self._box), 4) keys.append(self._box.add(_sample_message)) self.assertEqual(len(self._box), 5) + keys.append(self._box.add(_bytes_sample_message)) + self.assertEqual(len(self._box), 6) + with self.assertWarns(DeprecationWarning): + keys.append(self._box.add( + io.TextIOWrapper(io.BytesIO(_bytes_sample_message)))) + self.assertEqual(len(self._box), 7) self.assertEqual(self._box.get_string(keys[0]), self._template % 0) - for i in (1, 2, 3, 4): + for i in (1, 2, 3, 4, 5, 6): self._check_sample(self._box[keys[i]]) + _nonascii_msg = textwrap.dedent("""\ + From: foo + Subject: Falinapt?r h?zhozsz?ll?t?ssal. M?r rendelt?l? + + 0 + """) + + def test_add_invalid_8bit_bytes_header(self): + key = self._box.add(self._nonascii_msg.encode('latin1')) + self.assertEqual(len(self._box), 1) + self.assertEqual(self._box.get_bytes(key), + self._nonascii_msg.encode('latin1')) + + def test_invalid_nonascii_header_as_string(self): + subj = self._nonascii_msg.splitlines()[1] + key = self._box.add(subj.encode('latin1')) + self.assertEqual(self._box.get_string(key), + 'Subject: =?unknown-8bit?b?RmFsaW5hcHThciBo4Xpob3pzeuFsbO104XNz' + 'YWwuIE3hciByZW5kZWx06Ww/?=\n\n') + + def test_add_nonascii_header_raises(self): + with self.assertRaisesRegex(ValueError, "ASCII-only"): + self._box.add(self._nonascii_msg) + + _non_latin_bin_msg = textwrap.dedent("""\ + From: foo at bar.com + To: b?z + Subject: Maintenant je vous pr?sente mon coll?gue, le pouf c?l?bre + \tJean de Baddie + Mime-Version: 1.0 + Content-Type: text/plain; charset="utf-8" + Content-Transfer-Encoding: 8bit + + ??, ??? ?????. + """).encode('utf-8') + + def test_add_8bit_body(self): + key = self._box.add(self._non_latin_bin_msg) + self.assertEqual(self._box.get_bytes(key), + self._non_latin_bin_msg) + with self._box.get_file(key) as f: + self.assertEqual(f.read(), + self._non_latin_bin_msg.replace(b'\n', + os.linesep.encode())) + self.assertEqual(self._box[key].get_payload(), + "??, ??? ?????.\n") + + def test_add_binary_file(self): + with tempfile.TemporaryFile('wb+') as f: + f.write(_bytes_sample_message) + f.seek(0) + key = self._box.add(f) + # See issue 11062 + if not isinstance(self._box, mailbox.Babyl): + self.assertEqual(self._box.get_bytes(key).split(b'\n'), + _bytes_sample_message.split(b'\n')) + + def test_add_binary_nonascii_file(self): + with tempfile.TemporaryFile('wb+') as f: + f.write(self._non_latin_bin_msg) + f.seek(0) + key = self._box.add(f) + # See issue 11062 + if not isinstance(self._box, mailbox.Babyl): + self.assertEqual(self._box.get_bytes(key).split(b'\n'), + self._non_latin_bin_msg.split(b'\n')) + + def test_add_text_file_warns(self): + with tempfile.TemporaryFile('w+') as f: + f.write(_sample_message) + f.seek(0) + with self.assertWarns(DeprecationWarning): + key = self._box.add(f) + # See issue 11062 + if not isinstance(self._box, mailbox.Babyl): + self.assertEqual(self._box.get_bytes(key).split(b'\n'), + _bytes_sample_message.split(b'\n')) + + def test_add_StringIO_warns(self): + with self.assertWarns(DeprecationWarning): + key = self._box.add(io.StringIO(self._template % "0")) + self.assertEqual(self._box.get_string(key), self._template % "0") + + def test_add_nonascii_StringIO_raises(self): + with self.assertWarns(DeprecationWarning): + with self.assertRaisesRegex(ValueError, "ASCII-only"): + self._box.add(io.StringIO(self._nonascii_msg)) + def test_remove(self): # Remove messages using remove() self._test_remove_or_delitem(self._box.remove) @@ -154,12 +252,21 @@ self.assertEqual(msg0.get_payload(), '0') self._check_sample(self._box.get_message(key1)) + def test_get_bytes(self): + # Get bytes representations of messages + key0 = self._box.add(self._template % 0) + key1 = self._box.add(_sample_message) + self.assertEqual(self._box.get_bytes(key0), + (self._template % 0).encode('ascii')) + self.assertEqual(self._box.get_bytes(key1), _bytes_sample_message) + def test_get_string(self): # Get string representations of messages key0 = self._box.add(self._template % 0) key1 = self._box.add(_sample_message) self.assertEqual(self._box.get_string(key0), self._template % 0) - self.assertEqual(self._box.get_string(key1), _sample_message) + self.assertEqual(self._box.get_string(key1).split('\n'), + _sample_message.split('\n')) def test_get_file(self): # Get file representations of messages @@ -169,9 +276,9 @@ data0 = file.read() with self._box.get_file(key1) as file: data1 = file.read() - self.assertEqual(data0.replace(os.linesep, '\n'), + self.assertEqual(data0.decode('ascii').replace(os.linesep, '\n'), self._template % 0) - self.assertEqual(data1.replace(os.linesep, '\n'), + self.assertEqual(data1.decode('ascii').replace(os.linesep, '\n'), _sample_message) def test_iterkeys(self): @@ -405,11 +512,12 @@ def test_dump_message(self): # Write message representations to disk for input in (email.message_from_string(_sample_message), - _sample_message, io.StringIO(_sample_message)): - output = io.StringIO() + _sample_message, io.BytesIO(_bytes_sample_message)): + output = io.BytesIO() self._box._dump_message(input, output) - self.assertEqual(output.getvalue(), _sample_message) - output = io.StringIO() + self.assertEqual(output.getvalue(), + _bytes_sample_message.replace(b'\n', os.linesep.encode())) + output = io.BytesIO() self.assertRaises(TypeError, lambda: self._box._dump_message(None, output)) @@ -439,6 +547,7 @@ self.assertRaises(NotImplementedError, lambda: box.__getitem__('')) self.assertRaises(NotImplementedError, lambda: box.get_message('')) self.assertRaises(NotImplementedError, lambda: box.get_string('')) + self.assertRaises(NotImplementedError, lambda: box.get_bytes('')) self.assertRaises(NotImplementedError, lambda: box.get_file('')) self.assertRaises(NotImplementedError, lambda: '' in box) self.assertRaises(NotImplementedError, lambda: box.__contains__('')) @@ -640,9 +749,9 @@ "Host name mismatch: '%s' should be '%s'" % (groups[4], hostname)) previous_groups = groups - tmp_file.write(_sample_message) + tmp_file.write(_bytes_sample_message) tmp_file.seek(0) - self.assertEqual(tmp_file.read(), _sample_message) + self.assertEqual(tmp_file.read(), _bytes_sample_message) tmp_file.close() file_count = len(os.listdir(os.path.join(self._path, "tmp"))) self.assertEqual(file_count, repetitions, @@ -787,6 +896,12 @@ self.assertEqual(self._box[key].get_from(), 'foo at bar blah') self.assertEqual(self._box[key].get_payload(), '0') + def test_add_from_bytes(self): + # Add a byte string starting with 'From ' to the mailbox + key = self._box.add(b'From foo at bar blah\nFrom: foo\n\n0') + self.assertEqual(self._box[key].get_from(), 'foo at bar blah') + self.assertEqual(self._box[key].get_payload(), '0') + def test_add_mbox_or_mmdf_message(self): # Add an mboxMessage or MMDFMessage for class_ in (mailbox.mboxMessage, mailbox.MMDFMessage): @@ -817,7 +932,7 @@ self._box._file.seek(0) contents = self._box._file.read() self._box.close() - with open(self._path, 'r', newline='') as f: + with open(self._path, 'rb') as f: self.assertEqual(contents, f.read()) self._box = self._factory(self._path) @@ -1087,6 +1202,15 @@ self._post_initialize_hook(msg) self._check_sample(msg) + def test_initialize_with_binary_file(self): + # Initialize based on contents of binary file + with open(self._path, 'wb+') as f: + f.write(_bytes_sample_message) + f.seek(0) + msg = self._factory(f) + self._post_initialize_hook(msg) + self._check_sample(msg) + def test_initialize_with_nothing(self): # Initialize without arguments msg = self._factory() @@ -1363,6 +1487,14 @@ msg_plain = mailbox.Message(msg) self._check_sample(msg_plain) + def test_x_from_bytes(self): + # Convert all formats to Message + for class_ in (mailbox.Message, mailbox.MaildirMessage, + mailbox.mboxMessage, mailbox.MHMessage, + mailbox.BabylMessage, mailbox.MMDFMessage): + msg = class_(_bytes_sample_message) + self._check_sample(msg) + def test_x_to_invalid(self): # Convert all formats to an invalid format for class_ in (mailbox.Message, mailbox.MaildirMessage, @@ -1908,6 +2040,8 @@ --NMuMz9nt05w80d4+-- """ +_bytes_sample_message = _sample_message.encode('ascii') + _sample_headers = { "Return-Path":"", "X-Original-To":"gkj+person at localhost", Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sun Jan 30 07:21:28 2011 @@ -16,6 +16,12 @@ Library ------- +- Issue #9124: mailbox now accepts binary input and reads and writes mailbox + files in binary mode, using the email package's binary support to parse + arbitrary email messages. StringIO and text file input is deprecated, + and string input fails early if non-ASCII characters are used, where + previously it would fail when the email was processed in a later step. + - Issue #10845: Mitigate the incompatibility between the multiprocessing module on Windows and the use of package, zipfile or directory execution by special casing main modules that actually *are* called __main__.py. From python-checkins at python.org Sun Jan 30 08:56:03 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 30 Jan 2011 08:56:03 +0100 (CET) Subject: [Python-checkins] r88256 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110130075603.90B55EE982@mail.python.org> Author: raymond.hettinger Date: Sun Jan 30 08:56:03 2011 New Revision: 88256 Log: Add entry for the mailbox fixups. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Sun Jan 30 08:56:03 2011 @@ -2144,6 +2144,34 @@ (Work by Nick Coghlan, Dan Mahn, and Senthil Kumaran in :issue:`2987`, :issue:`5468`, and :issue:`9873`.) +mailbox +------- + +Thanks to a concerted effort by R. David Murray, the :mod:`mailbox` module has +been fixed for Python 3.2. The challenge was that mailbox had been originally +designed with a text interface, but email messages are best represented with +:class:`bytes` because various parts of a message may have different encodings. + +The solution harnessed the :mod:`email` package's binary support for parsing +arbitrary email messages. In addition, the solution required a number of API +changes. + +As expected, the :meth:`~mailbox.Mailbox.add` method for +:class:`mailbox.Mailbox` objects now accepts binary input. + +:class:`~io.StringIO` and text file input are deprecated. Also, string input +will fail early if non-ASCII characters are used. Previously it would fail when +the email was processed in a later step. + +There is also support for binary output. The :meth:`~mailbox.Mailbox.get_file` +method now returns a file in the binary mode (where it used to incorrectly set +the file to text-mode). There is also a new :meth:`~mailbox.Mailbox.get_bytes` +method that returns a :class:`bytes` representation of a message corresponding +to a given *key*. + +(Contributed by R. David Murray with efforts from Steffen Daode Nurpmeso and +Victor Stinner in :issue:`9124`.) + turtledemo ---------- From python-checkins at python.org Sun Jan 30 09:16:07 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 30 Jan 2011 09:16:07 +0100 (CET) Subject: [Python-checkins] r88258 - python/branches/py3k/Lib/idlelib/RemoteObjectBrowser.py Message-ID: <20110130081607.463B0EE982@mail.python.org> Author: georg.brandl Date: Sun Jan 30 09:16:07 2011 New Revision: 88258 Log: #11069: fix the IDLE Stack Viewer, by not using "list" as a variable name. Modified: python/branches/py3k/Lib/idlelib/RemoteObjectBrowser.py Modified: python/branches/py3k/Lib/idlelib/RemoteObjectBrowser.py ============================================================================== --- python/branches/py3k/Lib/idlelib/RemoteObjectBrowser.py (original) +++ python/branches/py3k/Lib/idlelib/RemoteObjectBrowser.py Sun Jan 30 09:16:07 2011 @@ -17,8 +17,8 @@ return value def _GetSubList(self): - list = self.__item._GetSubList() - return list(map(remote_object_tree_item, list)) + sub_list = self.__item._GetSubList() + return list(map(remote_object_tree_item, sub_list)) class StubObjectTreeItem: # Lives in IDLE process @@ -32,5 +32,5 @@ return value def _GetSubList(self): - list = self.sockio.remotecall(self.oid, "_GetSubList", (), {}) - return [StubObjectTreeItem(self.sockio, oid) for oid in list] + sub_list = self.sockio.remotecall(self.oid, "_GetSubList", (), {}) + return [StubObjectTreeItem(self.sockio, oid) for oid in sub_list] From python-checkins at python.org Sun Jan 30 09:16:39 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 30 Jan 2011 09:16:39 +0100 (CET) Subject: [Python-checkins] r88258 - svn:log Message-ID: <20110130081639.B8373EE982@mail.python.org> Author: georg.brandl Revision: 88258 Property Name: svn:log Action: modified Property diff: --- old property value +++ new property value @@ -1 +1,2 @@ -#11069: fix the IDLE Stack Viewer, by not using "list" as a variable name. \ No newline at end of file +#11069: fix the IDLE Stack Viewer, by not using "list" as a variable name. +Original patch by Brian Curtin, reviewed by me. From python-checkins at python.org Sun Jan 30 09:20:37 2011 From: python-checkins at python.org (raymond.hettinger) Date: Sun, 30 Jan 2011 09:20:37 +0100 (CET) Subject: [Python-checkins] r88259 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110130082037.3EFEFEE982@mail.python.org> Author: raymond.hettinger Date: Sun Jan 30 09:20:37 2011 New Revision: 88259 Log: Clarify the status of get_string() and recommend using the binary API. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Sun Jan 30 09:20:37 2011 @@ -2169,8 +2169,13 @@ method that returns a :class:`bytes` representation of a message corresponding to a given *key*. -(Contributed by R. David Murray with efforts from Steffen Daode Nurpmeso and -Victor Stinner in :issue:`9124`.) +It is still possible to get non-binary output using the old API's +:meth:`~mailbox.Mailbox.get_string` method, but that approach +is not very useful. Instead, it is best to extract messages from +a :class:`~mailbox.Message` object or to load them from binary input. + +(Contributed by R. David Murray, with efforts from Steffen Daode Nurpmeso and an +initial patch by Victor Stinner in :issue:`9124`.) turtledemo ---------- From python-checkins at python.org Sun Jan 30 09:37:19 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 30 Jan 2011 09:37:19 +0100 (CET) Subject: [Python-checkins] r88261 - in python/branches/py3k: Lib/pydoc.py Lib/test/test_pydoc.py Misc/NEWS Message-ID: <20110130083719.9956DEE983@mail.python.org> Author: georg.brandl Date: Sun Jan 30 09:37:19 2011 New Revision: 88261 Log: #10961: fix exception handling in new pydoc server code. Patch by Ron Adam, reviewed by Eric Araujo. Modified: python/branches/py3k/Lib/pydoc.py python/branches/py3k/Lib/test/test_pydoc.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/pydoc.py ============================================================================== --- python/branches/py3k/Lib/pydoc.py (original) +++ python/branches/py3k/Lib/pydoc.py Sun Jan 30 09:37:19 2011 @@ -70,7 +70,7 @@ import warnings from collections import deque from reprlib import Repr -from traceback import extract_tb +from traceback import extract_tb, format_exception_only # --------------------------------------------------------- common routines @@ -1882,7 +1882,9 @@ def _gettopic(self, topic, more_xrefs=''): """Return unbuffered tuple of (topic, xrefs). - If an error occurs, topic is the error message, and xrefs is ''. + If an error occurs here, the exception is caught and displayed by + the url handler. + This function duplicates the showtopic method but returns its result directly so it can be formatted for display in an html page. """ @@ -1895,14 +1897,11 @@ ''' , '') target = self.topics.get(topic, self.keywords.get(topic)) if not target: - return 'no documentation found for %r' % topic, '' + raise ValueError('could not find topic') if isinstance(target, str): return self._gettopic(target, more_xrefs) label, xrefs = target - try: - doc = pydoc_data.topics.topics[label] - except KeyError: - return 'no documentation found for %r' % topic, '' + doc = pydoc_data.topics.topics[label] if more_xrefs: xrefs = (xrefs or '') + ' ' + more_xrefs return doc, xrefs @@ -2387,7 +2386,7 @@ else: content_type = 'text/html' self.send_response(200) - self.send_header('Content-Type', '%s;charset=UTF-8' % content_type) + self.send_header('Content-Type', '%s; charset=UTF-8' % content_type) self.end_headers() self.wfile.write(self.urlhandler( self.path, content_type).encode('utf-8')) @@ -2479,10 +2478,10 @@ css_path) return '''\ -Python: %s +Pydoc: %s -%s%s -''' % (title, css_link, contents) +%s%s
%s
+''' % (title, css_link, html_navbar(), contents) def filelink(self, url, path): return '%s' % (url, path) @@ -2491,12 +2490,12 @@ html = _HTMLDoc() def html_navbar(): - version = "%s [%s, %s]" % (platform.python_version(), - platform.python_build()[0], - platform.python_compiler()) + version = html.escape("%s [%s, %s]" % (platform.python_version(), + platform.python_build()[0], + platform.python_compiler())) return """
- Python %s
%s

+ Python %s
%s
@@ -2505,19 +2504,17 @@ : Keywords
- + -     - -
+
  +
-
 
- """ % (version, platform.platform(terse=True)) + """ % (version, html.escape(platform.platform(terse=True))) def html_index(): """Module Index page.""" @@ -2589,7 +2586,7 @@ """Index of topic texts available.""" def bltinlink(name): - return '%s' % (name, name) + return '%s' % (name, name) heading = html.heading( 'INDEX', @@ -2609,7 +2606,7 @@ names = sorted(Helper.keywords.keys()) def bltinlink(name): - return '%s' % (name, name) + return '%s' % (name, name) contents = html.multicolumn(names, bltinlink) contents = heading + html.bigsection( @@ -2628,79 +2625,91 @@ heading = html.heading( '%s' % title, '#ffffff', '#7799ee') - contents = '
%s
' % contents + contents = '
%s
' % html.markup(contents) contents = html.bigsection(topic , '#ffffff','#ee77aa', contents) - xrefs = sorted(xrefs.split()) + if xrefs: + xrefs = sorted(xrefs.split()) - def bltinlink(name): - return '%s' % (name, name) + def bltinlink(name): + return '%s' % (name, name) - xrefs = html.multicolumn(xrefs, bltinlink) - xrefs = html.section('Related help topics: ', - '#ffffff', '#ee77aa', xrefs) + xrefs = html.multicolumn(xrefs, bltinlink) + xrefs = html.section('Related help topics: ', + '#ffffff', '#ee77aa', xrefs) return ('%s %s' % (title, topic), ''.join((heading, contents, xrefs))) - def html_error(url): + def html_getobj(url): + obj = locate(url, forceload=1) + if obj is None and url != 'None': + raise ValueError('could not find object') + title = describe(obj) + content = html.document(obj, url) + return title, content + + def html_error(url, exc): heading = html.heading( 'Error', - '#ffffff', '#ee0000') - return heading + url + '#ffffff', '#7799ee') + contents = '
'.join(html.escape(line) for line in + format_exception_only(type(exc), exc)) + contents = heading + html.bigsection(url, '#ffffff', '#bb0000', + contents) + return "Error - %s" % url, contents def get_html_page(url): """Generate an HTML page for url.""" + complete_url = url if url.endswith('.html'): url = url[:-5] - if url.startswith('/'): - url = url[1:] - if url.startswith("get?key="): - url = url[8:] - title = url - contents = '' - if url in ("", ".", "index"): - title, contents = html_index() - elif url == "topics": - title, contents = html_topics() - elif url == "keywords": - title, contents = html_keywords() - elif url.startswith("search?key="): - title, contents = html_search(url[11:]) - elif url.startswith("getfile?key="): - url = url[12:] - try: - title, contents = html_getfile(url) - except IOError: - contents = html_error('could not read file %r' % url) - title = 'Read Error' - else: - obj = None - try: - obj = locate(url, forceload=1) - except ErrorDuringImport as value: - contents = html.escape(str(value)) - if obj: - title = describe(obj) - contents = html.document(obj, url) - elif url in Helper.keywords or url in Helper.topics: - title, contents = html_topicpage(url) + try: + if url in ("", "index"): + title, content = html_index() + elif url == "topics": + title, content = html_topics() + elif url == "keywords": + title, content = html_keywords() + elif '=' in url: + op, _, url = url.partition('=') + if op == "search?key": + title, content = html_search(url) + elif op == "getfile?key": + title, content = html_getfile(url) + elif op == "topic?key": + # try topics first, then objects. + try: + title, content = html_topicpage(url) + except ValueError: + title, content = html_getobj(url) + elif op == "get?key": + # try objects first, then topics. + if url in ("", "index"): + title, content = html_index() + else: + try: + title, content = html_getobj(url) + except ValueError: + title, content = html_topicpage(url) + else: + raise ValueError('bad pydoc url') else: - contents = html_error( - 'no Python documentation found for %r' % url) - title = 'Error' - return html.page(title, html_navbar() + contents) + title, content = html_getobj(url) + except Exception as exc: + # Catch any errors and display them in an error page. + title, content = html_error(complete_url, exc) + return html.page(title, content) if url.startswith('/'): url = url[1:] if content_type == 'text/css': path_here = os.path.dirname(os.path.realpath(__file__)) - try: - with open(os.path.join(path_here, url)) as fp: - return ''.join(fp.readlines()) - except IOError: - return 'Error: can not open css file %r' % url + css_path = os.path.join(path_here, url) + with open(css_path) as fp: + return ''.join(fp.readlines()) elif content_type == 'text/html': return get_html_page(url) - return 'Error: unknown content type %r' % content_type + # Errors outside the url handler are caught by the server. + raise TypeError('unknown content type %r for url %s' % (content_type, url)) def browse(port=0, *, open_browser=True): Modified: python/branches/py3k/Lib/test/test_pydoc.py ============================================================================== --- python/branches/py3k/Lib/test/test_pydoc.py (original) +++ python/branches/py3k/Lib/test/test_pydoc.py Sun Jan 30 09:37:19 2011 @@ -244,7 +244,7 @@ return title -class PyDocDocTest(unittest.TestCase): +class PydocDocTest(unittest.TestCase): @unittest.skipIf(sys.flags.optimize >= 2, "Docstrings are omitted with -O2 and above") @@ -392,7 +392,7 @@ self.assertIn(expected, pydoc.render_doc(c)) -class PyDocServerTest(unittest.TestCase): +class PydocServerTest(unittest.TestCase): """Tests for pydoc._start_server""" def test_server(self): @@ -415,34 +415,31 @@ self.assertEqual(serverthread.error, None) -class PyDocUrlHandlerTest(unittest.TestCase): +class PydocUrlHandlerTest(unittest.TestCase): """Tests for pydoc._url_handler""" def test_content_type_err(self): - err = 'Error: unknown content type ' f = pydoc._url_handler - result = f("", "") - self.assertEqual(result, err + "''") - result = f("", "foobar") - self.assertEqual(result, err + "'foobar'") + self.assertRaises(TypeError, f, 'A', '') + self.assertRaises(TypeError, f, 'B', 'foobar') def test_url_requests(self): # Test for the correct title in the html pages returned. # This tests the different parts of the URL handler without # getting too picky about the exact html. requests = [ - ("", "Python: Index of Modules"), - ("get?key=", "Python: Index of Modules"), - ("index", "Python: Index of Modules"), - ("topics", "Python: Topics"), - ("keywords", "Python: Keywords"), - ("pydoc", "Python: module pydoc"), - ("get?key=pydoc", "Python: module pydoc"), - ("search?key=pydoc", "Python: Search Results"), - ("def", "Python: KEYWORD def"), - ("STRINGS", "Python: TOPIC STRINGS"), - ("foobar", "Python: Error"), - ("getfile?key=foobar", "Python: Read Error"), + ("", "Pydoc: Index of Modules"), + ("get?key=", "Pydoc: Index of Modules"), + ("index", "Pydoc: Index of Modules"), + ("topics", "Pydoc: Topics"), + ("keywords", "Pydoc: Keywords"), + ("pydoc", "Pydoc: module pydoc"), + ("get?key=pydoc", "Pydoc: module pydoc"), + ("search?key=pydoc", "Pydoc: Search Results"), + ("topic?key=def", "Pydoc: KEYWORD def"), + ("topic?key=STRINGS", "Pydoc: TOPIC STRINGS"), + ("foobar", "Pydoc: Error - foobar"), + ("getfile?key=foobar", "Pydoc: Error - getfile?key=foobar"), ] for url, title in requests: @@ -451,7 +448,7 @@ self.assertEqual(result, title) path = string.__file__ - title = "Python: getfile " + path + title = "Pydoc: getfile " + path url = "getfile?key=" + path text = pydoc._url_handler(url, "text/html") result = get_html_title(text) @@ -459,10 +456,10 @@ def test_main(): - test.support.run_unittest(PyDocDocTest, + test.support.run_unittest(PydocDocTest, TestDescriptions, - PyDocServerTest, - PyDocUrlHandlerTest, + PydocServerTest, + PydocUrlHandlerTest, ) if __name__ == "__main__": Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sun Jan 30 09:37:19 2011 @@ -88,6 +88,9 @@ - Issue #9509: argparse now properly handles IOErrors raised by argparse.FileType. +- Issue #10961: The new pydoc server now better handles exceptions raised + during request handling. + Build ----- From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: savepoint Message-ID: tarek.ziade pushed 59285ae1fc70 to distutils2: http://hg.python.org/distutils2/rev/59285ae1fc70 changeset: 921:59285ae1fc70 parent: 852:e283946b09de user: Tarek Ziade date: Sun Dec 26 17:11:20 2010 +0100 summary: savepoint files: distutils2/index/dist.py distutils2/index/simple.py distutils2/install.py distutils2/run.py distutils2/version.py diff --git a/distutils2/index/dist.py b/distutils2/index/dist.py --- a/distutils2/index/dist.py +++ b/distutils2/index/dist.py @@ -376,6 +376,8 @@ """ predicate = get_version_predicate(requirements) releases = self.filter(predicate) + if len(releases) == 0: + return None releases.sort_releases(prefer_final, reverse=True) return releases[0] diff --git a/distutils2/index/simple.py b/distutils2/index/simple.py --- a/distutils2/index/simple.py +++ b/distutils2/index/simple.py @@ -14,6 +14,7 @@ import logging import os +from distutils2 import logger from distutils2.index.base import BaseClient from distutils2.index.dist import (ReleasesList, EXTENSIONS, get_infos_from_url, MD5_HASH) @@ -167,6 +168,7 @@ if predicate.name.lower() in self._projects and not force_update: return self._projects.get(predicate.name.lower()) prefer_final = self._get_prefer_final(prefer_final) + logger.info('Reading info on PyPI about %s' % predicate.name) self._process_index_page(predicate.name) if predicate.name.lower() not in self._projects: diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -1,14 +1,15 @@ from tempfile import mkdtemp -import logging import shutil import os import errno import itertools +from distutils2 import logger from distutils2._backport.pkgutil import get_distributions from distutils2.depgraph import generate_graph from distutils2.index import wrapper from distutils2.index.errors import ProjectNotFound, ReleaseNotFound +from distutils2.version import get_version_predicate """Provides installations scripts. @@ -72,10 +73,13 @@ installed_dists, installed_files = [], [] for d in dists: + logger.info('Installing %s %s' % (d.name, d.version)) try: installed_files.extend(d.install(path)) installed_dists.append(d) except Exception, e : + logger.info('Failed. %s' % str(e)) + for d in installed_dists: d.uninstall() raise e @@ -155,12 +159,36 @@ conflict. """ + + if not installed: + logger.info('Reading installed distributions') + installed = get_distributions(use_egg_info=True) + + infos = {'install': [], 'remove': [], 'conflict': []} + # Is a compatible version of the project is already installed ? + predicate = get_version_predicate(requirements) + found = False + installed = list(installed) + for installed_project in installed: + # is it a compatible project ? + if predicate.name.lower() != installed_project.name.lower(): + continue + found = True + logger.info('Found %s %s' % (installed_project.name, + installed_project.metadata.version)) + if predicate.match(installed_project.metadata.version): + return infos + + + + break + + if not found: + logger.info('Project not installed.') + if not index: index = wrapper.ClientWrapper() - if not installed: - installed = get_distributions(use_egg_info=True) - # Get all the releases that match the requirements try: releases = index.get_releases(requirements) @@ -170,28 +198,31 @@ # Pick up a release, and try to get the dependency tree release = releases.get_last(requirements, prefer_final=prefer_final) + if release is None: + logger.info('Could not find a matching project') + return infos + # Iter since we found something without conflicts metadata = release.fetch_metadata() - # Get the distributions already_installed on the system - # and add the one we want to install distributions = itertools.chain(installed, [release]) depgraph = generate_graph(distributions) # Store all the already_installed packages in a list, in case of rollback. - infos = {'install': [], 'remove': [], 'conflict': []} + # Get what the missing deps are - for dists in depgraph.missing.values(): + for dists in depgraph.missing[release]: if dists: - logging.info("missing dependencies found, installing them") + logger.info("missing dependencies found, installing them") # we have missing deps for dist in dists: _update_infos(infos, get_infos(dist, index, installed)) # Fill in the infos existing = [d for d in installed if d.name == release.name] + if existing: infos['remove'].append(existing[0]) infos['conflict'].extend(depgraph.reverse_list[existing[0]]) @@ -214,5 +245,28 @@ attrs['requirements'] = sys.argv[1] get_infos(**attrs) + +def install(project): + logger.info('Getting information about "%s".' % project) + try: + info = get_infos(project) + except InstallationException: + logger.info('Cound not find "%s".' % project) + return + + if info['install'] == []: + logger.info('Nothing to install.') + return + + #logger.info('Installing "%s" and its dependencies' % project) + try: + install_from_infos(info['install'], info['remove'], info['conflict']) + + except InstallationConflict, e: + + projects = ['%s %s' % (p.name, p.metadata.version) for p in e.args[0]] + logger.info('"%s" conflicts with "%s"' % (project, ','.join(projects))) + + if __name__ == '__main__': main() diff --git a/distutils2/run.py b/distutils2/run.py --- a/distutils2/run.py +++ b/distutils2/run.py @@ -1,7 +1,9 @@ import os import sys from optparse import OptionParser +import logging +from distutils2 import logger from distutils2.util import grok_environment_error from distutils2.errors import (DistutilsSetupError, DistutilsArgError, DistutilsError, CCompilerError) @@ -9,6 +11,7 @@ from distutils2 import __version__ from distutils2._backport.pkgutil import get_distributions, get_distribution from distutils2.depgraph import generate_graph +from distutils2.install import install # This is a barebones help message generated displayed when the user # runs the setup script with no arguments at all. More useful help @@ -114,8 +117,17 @@ return dist +def _set_logger(): + logger.setLevel(logging.INFO) + sth = logging.StreamHandler(sys.stderr) + sth.setLevel(logging.INFO) + logger.addHandler(sth) + logger.propagate = 0 + + def main(): """Main entry point for Distutils2""" + _set_logger() parser = OptionParser() parser.disable_interspersed_args() parser.usage = '%prog [options] cmd1 cmd2 ..' @@ -136,6 +148,14 @@ action="store_true", dest="fgraph", default=False, help="Display the full graph for installed distributions.") + parser.add_option("-i", "--install", + action="store", dest="install", + help="Install a project.") + + parser.add_option("-r", "--remove", + action="store", dest="remove", + help="Remove a project.") + options, args = parser.parse_args() if options.version: print('Distutils2 %s' % __version__) @@ -169,6 +189,10 @@ print(graph) sys.exit(0) + if options.install is not None: + install(options.install) + sys.exit(0) + if len(args) == 0: parser.print_help() sys.exit(0) @@ -178,4 +202,5 @@ if __name__ == '__main__': + main() diff --git a/distutils2/version.py b/distutils2/version.py --- a/distutils2/version.py +++ b/distutils2/version.py @@ -323,7 +323,7 @@ _PREDICATE = re.compile(r"(?i)^\s*([a-z_][\sa-zA-Z_-]*(?:\.[a-z_]\w*)*)(.*)") -_VERSIONS = re.compile(r"^\s*\((.*)\)\s*$") +_VERSIONS = re.compile(r"^\s*\((?P.*)\)\s*$|^\s*(?P.*)\s*$") _PLAIN_VERSIONS = re.compile(r"^\s*(.*)\s*$") _SPLIT_CMP = re.compile(r"^\s*(<=|>=|<|>|!=|==)\s*([^\s,]+)\s*$") @@ -358,14 +358,22 @@ name, predicates = match.groups() self.name = name.strip() - predicates = predicates.strip() - predicates = _VERSIONS.match(predicates) + self.predicates = [] + predicates = _VERSIONS.match(predicates.strip()) if predicates is not None: - predicates = predicates.groups()[0] - self.predicates = [_split_predicate(pred.strip()) - for pred in predicates.split(',')] - else: - self.predicates = [] + predicates = predicates.groupdict() + if predicates['versions'] is not None: + versions = predicates['versions'] + else: + versions = predicates.get('versions2') + + if versions is not None: + for version in versions.split(','): + try: + self.predicates.append(_split_predicate(version)) + except: + pass + #import pdb; pdb.set_trace() def match(self, version): """Check if the provided version matches the predicates.""" -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: savepoint Message-ID: tarek.ziade pushed 0a2b6ac0fed2 to distutils2: http://hg.python.org/distutils2/rev/0a2b6ac0fed2 changeset: 922:0a2b6ac0fed2 parent: 856:0de7d5f4dae5 user: Tarek Ziade date: Mon Jan 03 18:09:24 2011 +0100 summary: savepoint files: distutils2/index/dist.py distutils2/index/simple.py distutils2/index/xmlrpc.py distutils2/install.py distutils2/run.py diff --git a/distutils2/index/dist.py b/distutils2/index/dist.py --- a/distutils2/index/dist.py +++ b/distutils2/index/dist.py @@ -17,7 +17,6 @@ import urllib import urlparse import zipfile - try: import hashlib except ImportError: @@ -206,6 +205,7 @@ __hash__ = object.__hash__ + class DistInfo(IndexReference): """Represents a distribution retrieved from an index (sdist, bdist, ...) """ diff --git a/distutils2/index/simple.py b/distutils2/index/simple.py --- a/distutils2/index/simple.py +++ b/distutils2/index/simple.py @@ -199,6 +199,7 @@ Currently, download one archive, extract it and use the PKG-INFO file. """ + import pdb; pdb.set_trace() release = self.get_distributions(project_name, version) if not release._metadata: location = release.get_distribution().unpack() diff --git a/distutils2/index/xmlrpc.py b/distutils2/index/xmlrpc.py --- a/distutils2/index/xmlrpc.py +++ b/distutils2/index/xmlrpc.py @@ -127,10 +127,17 @@ return release def get_metadata(self, project_name, version): - """Retreive project metadatas. + """Retrieve project metadata. Return a ReleaseInfo object, with metadata informations filled in. """ + # to be case-insensitive + projects = [d['name'] for d in + self.proxy.search({'name': project_name}) + if d['name'].lower() == project_name] + if len(projects) > 0: + project_name = projects[0] + metadata = self.proxy.release_data(project_name, version) project = self._get_project(project_name) if version not in project.get_versions(): diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -1,14 +1,18 @@ from tempfile import mkdtemp -import logging import shutil import os import errno import itertools +import sys +import tarfile +from distutils2 import logger from distutils2._backport.pkgutil import get_distributions +from distutils2._backport.sysconfig import get_config_var from distutils2.depgraph import generate_graph from distutils2.index import wrapper from distutils2.index.errors import ProjectNotFound, ReleaseNotFound +from distutils2.version import get_version_predicate """Provides installations scripts. @@ -53,7 +57,129 @@ else: raise e os.rename(old, new) - yield(old, new) + yield old, new + + + +# ripped from shutil +def _ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + +def _unpack_zipfile(filename, extract_dir): + try: + import zipfile + except ImportError: + raise ReadError('zlib not supported, cannot unpack this archive.') + + if not zipfile.is_zipfile(filename): + raise ReadError("%s is not a zip file" % filename) + + zip = zipfile.ZipFile(filename) + try: + for info in zip.infolist(): + name = info.filename + if name.startswith('/') or '..' in name: + continue + + target = os.path.join(extract_dir, *name.split('/')) + if not target: + continue + + _ensure_directory(target) + if not name.endswith('/'): + # file + data = zip.read(info.filename) + f = open(target,'wb') + try: + f.write(data) + finally: + f.close() + del data + finally: + zip.close() + +def _unpack_tarfile(filename, extract_dir): + try: + tarobj = tarfile.open(filename) + except tarfile.TarError: + raise ReadError( + "%s is not a compressed or uncompressed tar file" % filename) + try: + tarobj.extractall(extract_dir) + finally: + tarobj.close() + + +_UNPACKERS = ( + (['.tar.gz', '.tgz', '.tar'], _unpack_tarfile), + (['.zip', '.egg'], _unpack_zipfile)) + + +def _unpack(filename, extract_dir=None): + if extract_dir is None: + extract_dir = os.path.dirname(filename) + + for formats, func in _UNPACKERS: + for format in formats: + if filename.endswith(format): + func(filename, extract_dir) + return extract_dir + + raise ValueError('Unknown archive format: %s' % filename) + + +def _install_dist(dist, path): + """Install a distribution into a path""" + def _run_d1_install(archive_dir, path): + # backward compat: using setuptools or plain-distutils + cmd = '%s setup.py install --root=%s --record=%s' + setup_py = os.path.join(archive_dir, 'setup.py') + if 'setuptools' in open(setup_py).read(): + cmd += ' --single-version-externally-managed' + + # how to place this file in the egg-info dir + # for non-distutils2 projects ? + record_file = os.path.join(archive_dir, 'RECORD') + os.system(cmd % (sys.executable, path, record_file)) + if not os.path.exists(record_file): + raise ValueError('Failed to install.') + return open(record_file).read().split('\n') + + def _run_d2_install(archive_dir, path): + # using our own install command + raise NotImplementedError() + + # download + archive = dist.download() + + # unarchive + where = _unpack(archive) + + # get into the dir + archive_dir = None + for item in os.listdir(where): + fullpath = os.path.join(where, item) + if os.path.isdir(fullpath): + archive_dir = fullpath + break + + if archive_dir is None: + raise ValueError('Cannot locate the unpacked archive') + + # install + old_dir = os.getcwd() + os.chdir(archive_dir) + try: + # distutils2 or distutils1 ? + if 'setup.py' in os.listdir(archive_dir): + return _run_d1_install(archive_dir, path) + else: + return _run_d2_install(archive_dir, path) + finally: + os.chdir(old_dir) def install_dists(dists, path=None): @@ -65,19 +191,23 @@ Return a list of installed files. :param dists: distributions to install - :param path: base path to install distribution on + :param path: base path to install distribution in """ if not path: path = mkdtemp() installed_dists, installed_files = [], [] for d in dists: + logger.info('Installing %s %s' % (d.name, d.version)) try: - installed_files.extend(d.install(path)) + installed_files.extend(_install_dist(d, path)) installed_dists.append(d) except Exception, e : + logger.info('Failed. %s' % str(e)) + + # reverting for d in installed_dists: - d.uninstall() + _uninstall(d) raise e return installed_files @@ -123,16 +253,26 @@ try: if install: installed_files = install_dists(install, install_path) # install to tmp first - for files in temp_files.values(): - for old, new in files: - os.remove(new) - except Exception,e: + except Exception: # if an error occurs, put back the files in the good place. for files in temp_files.values(): for old, new in files: shutil.move(new, old) + # now re-raising + raise + + # we can emove them for good + for files in temp_files.values(): + for old, new in files: + os.remove(new) + + +def _get_setuptools_deps(release): + # NotImplementedError + pass + def get_infos(requirements, index=None, installed=None, prefer_final=True): """Return the informations on what's going to be installed and upgraded. @@ -155,12 +295,34 @@ conflict. """ + + if not installed: + logger.info('Reading installed distributions') + installed = get_distributions(use_egg_info=True) + + infos = {'install': [], 'remove': [], 'conflict': []} + # Is a compatible version of the project is already installed ? + predicate = get_version_predicate(requirements) + found = False + installed = list(installed) + for installed_project in installed: + # is it a compatible project ? + if predicate.name.lower() != installed_project.name.lower(): + continue + found = True + logger.info('Found %s %s' % (installed_project.name, + installed_project.metadata.version)) + if predicate.match(installed_project.metadata.version): + return infos + + break + + if not found: + logger.info('Project not installed.') + if not index: index = wrapper.ClientWrapper() - if not installed: - installed = get_distributions(use_egg_info=True) - # Get all the releases that match the requirements try: releases = index.get_releases(requirements) @@ -170,28 +332,36 @@ # Pick up a release, and try to get the dependency tree release = releases.get_last(requirements, prefer_final=prefer_final) - # Iter since we found something without conflicts + if release is None: + logger.info('Could not find a matching project') + return infos + + import pdb; pdb.set_trace() + + # this works for Metadata 1.2 metadata = release.fetch_metadata() - # Get the distributions already_installed on the system - # and add the one we want to install + # for earlier, we need to build setuptools deps if any + if 'requires_dist' not in metadata: + deps = _get_setuptools_deps(release) + else: + deps = metadata['requires_dist'] distributions = itertools.chain(installed, [release]) depgraph = generate_graph(distributions) # Store all the already_installed packages in a list, in case of rollback. - infos = {'install': [], 'remove': [], 'conflict': []} - # Get what the missing deps are - for dists in depgraph.missing.values(): + for dists in depgraph.missing[release]: if dists: - logging.info("missing dependencies found, installing them") + logger.info("missing dependencies found, installing them") # we have missing deps for dist in dists: _update_infos(infos, get_infos(dist, index, installed)) # Fill in the infos existing = [d for d in installed if d.name == release.name] + if existing: infos['remove'].append(existing[0]) infos['conflict'].extend(depgraph.reverse_list[existing[0]]) @@ -214,5 +384,28 @@ attrs['requirements'] = sys.argv[1] get_infos(**attrs) + +def install(project): + logger.info('Getting information about "%s".' % project) + try: + info = get_infos(project) + except InstallationException: + logger.info('Cound not find "%s".' % project) + return + + if info['install'] == []: + logger.info('Nothing to install.') + return + + install_path = get_config_var('base') + try: + install_from_infos(info['install'], info['remove'], info['conflict'], + install_path=install_path) + + except InstallationConflict, e: + projects = ['%s %s' % (p.name, p.metadata.version) for p in e.args[0]] + logger.info('"%s" conflicts with "%s"' % (project, ','.join(projects))) + + if __name__ == '__main__': main() diff --git a/distutils2/run.py b/distutils2/run.py --- a/distutils2/run.py +++ b/distutils2/run.py @@ -1,7 +1,9 @@ import os import sys from optparse import OptionParser +import logging +from distutils2 import logger from distutils2.util import grok_environment_error from distutils2.errors import (DistutilsSetupError, DistutilsArgError, DistutilsError, CCompilerError) @@ -9,6 +11,7 @@ from distutils2 import __version__ from distutils2._backport.pkgutil import get_distributions, get_distribution from distutils2.depgraph import generate_graph +from distutils2.install import install # This is a barebones help message generated displayed when the user # runs the setup script with no arguments at all. More useful help @@ -114,8 +117,17 @@ return dist +def _set_logger(): + logger.setLevel(logging.INFO) + sth = logging.StreamHandler(sys.stderr) + sth.setLevel(logging.INFO) + logger.addHandler(sth) + logger.propagate = 0 + + def main(): """Main entry point for Distutils2""" + _set_logger() parser = OptionParser() parser.disable_interspersed_args() parser.usage = '%prog [options] cmd1 cmd2 ..' @@ -136,6 +148,10 @@ action="store_true", dest="fgraph", default=False, help="Display the full graph for installed distributions.") + parser.add_option("-i", "--install", + action="store", dest="install", + help="Install a project.") + options, args = parser.parse_args() if options.version: print('Distutils2 %s' % __version__) @@ -169,6 +185,10 @@ print(graph) sys.exit(0) + if options.install is not None: + install(options.install) + sys.exit(0) + if len(args) == 0: parser.print_help() sys.exit(0) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: merge tarek changes. Message-ID: tarek.ziade pushed 4a41a15d1f9f to distutils2: http://hg.python.org/distutils2/rev/4a41a15d1f9f changeset: 924:4a41a15d1f9f parent: 923:e26de21a7b4e parent: 921:59285ae1fc70 user: Alexis Metaireau date: Fri Jan 28 12:45:38 2011 +0100 summary: merge tarek changes. files: distutils2/install.py distutils2/run.py distutils2/tests/pypi_server.py distutils2/version.py diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -3,8 +3,6 @@ import os import errno import itertools -import sys -import tarfile from distutils2 import logger from distutils2._backport.pkgutil import get_distributions @@ -57,7 +55,7 @@ else: raise e os.rename(old, new) - yield old, new + yield (old, new) def _install_dist(dist, path): @@ -261,8 +259,6 @@ logger.info('Could not find a matching project') return infos - import pdb; pdb.set_trace() - # this works for Metadata 1.2 metadata = release.fetch_metadata() diff --git a/distutils2/run.py b/distutils2/run.py --- a/distutils2/run.py +++ b/distutils2/run.py @@ -152,6 +152,10 @@ action="store", dest="install", help="Install a project.") + parser.add_option("-r", "--remove", + action="store", dest="remove", + help="Remove a project.") + options, args = parser.parse_args() if options.version: print('Distutils2 %s' % __version__) diff --git a/distutils2/tests/pypi_server.py b/distutils2/tests/pypi_server.py --- a/distutils2/tests/pypi_server.py +++ b/distutils2/tests/pypi_server.py @@ -375,6 +375,7 @@ def __init__(self, dists=[]): self._dists = dists + self._search_result = [] def add_distributions(self, dists): for dist in dists: -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: move the unpack utilities to _backport Message-ID: tarek.ziade pushed e26de21a7b4e to distutils2: http://hg.python.org/distutils2/rev/e26de21a7b4e changeset: 923:e26de21a7b4e user: Alexis Metaireau date: Mon Jan 03 22:04:17 2011 +0100 summary: move the unpack utilities to _backport files: distutils2/_backport/shutil.py distutils2/index/dist.py distutils2/install.py distutils2/util.py diff --git a/distutils2/_backport/shutil.py b/distutils2/_backport/shutil.py --- a/distutils2/_backport/shutil.py +++ b/distutils2/_backport/shutil.py @@ -568,3 +568,72 @@ os.chdir(save_cwd) return filename + + +def _ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + +def _unpack_zipfile(filename, extract_dir): + try: + import zipfile + except ImportError: + raise ReadError('zlib not supported, cannot unpack this archive.') + + if not zipfile.is_zipfile(filename): + raise ReadError("%s is not a zip file" % filename) + + zip = zipfile.ZipFile(filename) + try: + for info in zip.infolist(): + name = info.filename + if name.startswith('/') or '..' in name: + continue + + target = os.path.join(extract_dir, *name.split('/')) + if not target: + continue + + _ensure_directory(target) + if not name.endswith('/'): + # file + data = zip.read(info.filename) + f = open(target,'wb') + try: + f.write(data) + finally: + f.close() + del data + finally: + zip.close() + +def _unpack_tarfile(filename, extract_dir): + try: + tarobj = tarfile.open(filename) + except tarfile.TarError: + raise ReadError( + "%s is not a compressed or uncompressed tar file" % filename) + try: + tarobj.extractall(extract_dir) + finally: + tarobj.close() + + +_UNPACKERS = ( + (['.tar.gz', '.tgz', '.tar'], _unpack_tarfile), + (['.zip', '.egg'], _unpack_zipfile)) + + +def unpack_archive(filename, extract_dir=None): + if extract_dir is None: + extract_dir = os.path.dirname(filename) + + for formats, func in _UNPACKERS: + for format in formats: + if filename.endswith(format): + func(filename, extract_dir) + return extract_dir + + raise ValueError('Unknown archive format: %s' % filename) diff --git a/distutils2/index/dist.py b/distutils2/index/dist.py --- a/distutils2/index/dist.py +++ b/distutils2/index/dist.py @@ -22,13 +22,14 @@ except ImportError: from distutils2._backport import hashlib +from distutils2._backport.shutil import unpack_archive from distutils2.errors import IrrationalVersionError from distutils2.index.errors import (HashDoesNotMatch, UnsupportedHashName, CantParseArchiveName) from distutils2.version import (suggest_normalized_version, NormalizedVersion, get_version_predicate) from distutils2.metadata import DistributionMetadata -from distutils2.util import untar_file, unzip_file, splitext +from distutils2.util import splitext __all__ = ['ReleaseInfo', 'DistInfo', 'ReleasesList', 'get_infos_from_url'] @@ -313,17 +314,8 @@ filename = self.download() content_type = mimetypes.guess_type(filename)[0] + self._unpacked_dir = unpack_archive(filename) - if (content_type == 'application/zip' - or filename.endswith('.zip') - or filename.endswith('.pybundle') - or zipfile.is_zipfile(filename)): - unzip_file(filename, path, flatten=not filename.endswith('.pybundle')) - elif (content_type == 'application/x-gzip' - or tarfile.is_tarfile(filename) - or splitext(filename)[1].lower() in ('.tar', '.tar.gz', '.tar.bz2', '.tgz', '.tbz')): - untar_file(filename, path) - self._unpacked_dir = path return self._unpacked_dir def _check_md5(self, filename): diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -60,77 +60,6 @@ yield old, new - -# ripped from shutil -def _ensure_directory(path): - """Ensure that the parent directory of `path` exists""" - dirname = os.path.dirname(path) - if not os.path.isdir(dirname): - os.makedirs(dirname) - -def _unpack_zipfile(filename, extract_dir): - try: - import zipfile - except ImportError: - raise ReadError('zlib not supported, cannot unpack this archive.') - - if not zipfile.is_zipfile(filename): - raise ReadError("%s is not a zip file" % filename) - - zip = zipfile.ZipFile(filename) - try: - for info in zip.infolist(): - name = info.filename - if name.startswith('/') or '..' in name: - continue - - target = os.path.join(extract_dir, *name.split('/')) - if not target: - continue - - _ensure_directory(target) - if not name.endswith('/'): - # file - data = zip.read(info.filename) - f = open(target,'wb') - try: - f.write(data) - finally: - f.close() - del data - finally: - zip.close() - -def _unpack_tarfile(filename, extract_dir): - try: - tarobj = tarfile.open(filename) - except tarfile.TarError: - raise ReadError( - "%s is not a compressed or uncompressed tar file" % filename) - try: - tarobj.extractall(extract_dir) - finally: - tarobj.close() - - -_UNPACKERS = ( - (['.tar.gz', '.tgz', '.tar'], _unpack_tarfile), - (['.zip', '.egg'], _unpack_zipfile)) - - -def _unpack(filename, extract_dir=None): - if extract_dir is None: - extract_dir = os.path.dirname(filename) - - for formats, func in _UNPACKERS: - for format in formats: - if filename.endswith(format): - func(filename, extract_dir) - return extract_dir - - raise ValueError('Unknown archive format: %s' % filename) - - def _install_dist(dist, path): """Install a distribution into a path""" def _run_d1_install(archive_dir, path): @@ -152,11 +81,7 @@ # using our own install command raise NotImplementedError() - # download - archive = dist.download() - - # unarchive - where = _unpack(archive) + where = dist.unpack(archive) # get into the dir archive_dir = None diff --git a/distutils2/util.py b/distutils2/util.py --- a/distutils2/util.py +++ b/distutils2/util.py @@ -674,83 +674,6 @@ return base, ext -def unzip_file(filename, location, flatten=True): - """Unzip the file (zip file located at filename) to the destination - location""" - if not os.path.exists(location): - os.makedirs(location) - zipfp = open(filename, 'rb') - try: - zip = zipfile.ZipFile(zipfp) - leading = has_leading_dir(zip.namelist()) and flatten - for name in zip.namelist(): - data = zip.read(name) - fn = name - if leading: - fn = split_leading_dir(name)[1] - fn = os.path.join(location, fn) - dir = os.path.dirname(fn) - if not os.path.exists(dir): - os.makedirs(dir) - if fn.endswith('/') or fn.endswith('\\'): - # A directory - if not os.path.exists(fn): - os.makedirs(fn) - else: - fp = open(fn, 'wb') - try: - fp.write(data) - finally: - fp.close() - finally: - zipfp.close() - - -def untar_file(filename, location): - """Untar the file (tar file located at filename) to the destination - location - """ - if not os.path.exists(location): - os.makedirs(location) - if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): - mode = 'r:gz' - elif (filename.lower().endswith('.bz2') - or filename.lower().endswith('.tbz')): - mode = 'r:bz2' - elif filename.lower().endswith('.tar'): - mode = 'r' - else: - mode = 'r:*' - tar = tarfile.open(filename, mode) - try: - leading = has_leading_dir([member.name for member in tar.getmembers()]) - for member in tar.getmembers(): - fn = member.name - if leading: - fn = split_leading_dir(fn)[1] - path = os.path.join(location, fn) - if member.isdir(): - if not os.path.exists(path): - os.makedirs(path) - else: - try: - fp = tar.extractfile(member) - except (KeyError, AttributeError): - # Some corrupt tar files seem to produce this - # (specifically bad symlinks) - continue - if not os.path.exists(os.path.dirname(path)): - os.makedirs(os.path.dirname(path)) - destfp = open(path, 'wb') - try: - shutil.copyfileobj(fp, destfp) - finally: - destfp.close() - fp.close() - finally: - tar.close() - - def has_leading_dir(paths): """Returns true if all the paths have the same leading path name (i.e., everything is in one subdirectory in an archive)""" -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Update installer tests. Message-ID: tarek.ziade pushed 30c453712740 to distutils2: http://hg.python.org/distutils2/rev/30c453712740 changeset: 926:30c453712740 user: Alexis Metaireau date: Sat Jan 29 16:37:11 2011 +0100 summary: Update installer tests. files: distutils2/index/xmlrpc.py distutils2/install.py distutils2/tests/pypi_server.py distutils2/tests/test_install.py diff --git a/distutils2/index/xmlrpc.py b/distutils2/index/xmlrpc.py --- a/distutils2/index/xmlrpc.py +++ b/distutils2/index/xmlrpc.py @@ -131,7 +131,7 @@ Return a ReleaseInfo object, with metadata informations filled in. """ - # to be case-insensitive + # to be case-insensitive, get the informations from the XMLRPC API projects = [d['name'] for d in self.proxy.search({'name': project_name}) if d['name'].lower() == project_name] diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -139,7 +139,7 @@ # reverting for d in installed_dists: - _uninstall(d) + uninstall(d) raise e return installed_files @@ -226,8 +226,6 @@ Conflict contains all the conflicting distributions, if there is a conflict. """ - from ipdb import set_trace - set_trace() if not installed: logger.info('Reading installed distributions') installed = get_distributions(use_egg_info=True) @@ -237,16 +235,20 @@ predicate = get_version_predicate(requirements) found = False installed = list(installed) + + # check that the project isnt already installed for installed_project in installed: # is it a compatible project ? if predicate.name.lower() != installed_project.name.lower(): continue found = True logger.info('Found %s %s' % (installed_project.name, - installed_project.metadata.version)) - if predicate.match(installed_project.metadata.version): + installed_project.version)) + + # if we already have something installed, check it matches the + # requirements + if predicate.match(installed_project.version): return infos - break if not found: @@ -260,7 +262,7 @@ releases = index.get_releases(requirements) except (ReleaseNotFound, ProjectNotFound), e: raise InstallationException('Release not found: "%s"' % requirements) - + # Pick up a release, and try to get the dependency tree release = releases.get_last(requirements, prefer_final=prefer_final) @@ -284,7 +286,7 @@ # Get what the missing deps are dists = depgraph.missing[release] if dists: - logger.info("missing dependencies found, installing them") + logger.info("missing dependencies found, retrieving metadata") # we have missing deps for dist in dists: _update_infos(infos, get_infos(dist, index, installed)) @@ -333,7 +335,7 @@ install_path=install_path) except InstallationConflict, e: - projects = ['%s %s' % (p.name, p.metadata.version) for p in e.args[0]] + projects = ['%s %s' % (p.name, p.version) for p in e.args[0]] logger.info('"%s" conflicts with "%s"' % (project, ','.join(projects))) diff --git a/distutils2/tests/pypi_server.py b/distutils2/tests/pypi_server.py --- a/distutils2/tests/pypi_server.py +++ b/distutils2/tests/pypi_server.py @@ -375,6 +375,7 @@ def __init__(self, dists=[]): self._dists = dists + self._search_result = [] def add_distributions(self, dists): for dist in dists: diff --git a/distutils2/tests/test_install.py b/distutils2/tests/test_install.py --- a/distutils2/tests/test_install.py +++ b/distutils2/tests/test_install.py @@ -29,27 +29,16 @@ class ToInstallDist(object): """Distribution that will be installed""" - def __init__(self, raise_error=False, files=False): - self._raise_error = raise_error + def __init__(self, files=False): self._files = files - self.install_called = False - self.install_called_with = {} self.uninstall_called = False self._real_files = [] + self.name = "fake" + self.version = "fake" if files: for f in range(0,3): self._real_files.append(mkstemp()) - def install(self, *args): - self.install_called = True - self.install_called_with = args - if self._raise_error: - raise Exception('Oops !') - return ['/path/to/foo', '/path/to/bar'] - - def uninstall(self, **args): - self.uninstall_called = True - def get_installed_files(self, **args): if self._files: return [f[1] for f in self._real_files] @@ -58,7 +47,49 @@ return self.get_installed_files() +class MagicMock(object): + def __init__(self, return_value=None, raise_exception=False): + self.called = False + self._times_called = 0 + self._called_with = [] + self._return_value = return_value + self._raise = raise_exception + + def __call__(self, *args, **kwargs): + self.called = True + self._times_called = self._times_called + 1 + self._called_with.append((args, kwargs)) + iterable = hasattr(self._raise, '__iter__') + if self._raise: + if ((not iterable and self._raise) + or self._raise[self._times_called - 1]): + raise Exception + return self._return_value + + def called_with(self, *args, **kwargs): + return (args, kwargs) in self._called_with + + +def patch(parent, to_patch): + """monkey match a module""" + def wrapper(func): + print func + print dir(func) + old_func = getattr(parent, to_patch) + def wrapped(*args, **kwargs): + parent.__dict__[to_patch] = MagicMock() + try: + out = func(*args, **kwargs) + finally: + setattr(parent, to_patch, old_func) + return out + return wrapped + return wrapper + + def get_installed_dists(dists): + """Return a list of fake installed dists. + The list is name, version, deps""" objects = [] for (name, version, deps) in dists: objects.append(InstalledDist(name, version, deps)) @@ -69,6 +100,12 @@ def _get_client(self, server, *args, **kwargs): return Client(server.full_address, *args, **kwargs) + def _patch_run_install(self): + """Patch run install""" + + def _unpatch_run_install(self): + """Unpatch run install for d2 and d1""" + def _get_results(self, output): """return a list of results""" installed = [(o.name, '%s' % o.version) for o in output['install']] @@ -150,6 +187,8 @@ # Tests that conflicts are detected client = self._get_client(server) archive_path = '%s/distribution.tar.gz' % server.full_address + + # choxie depends on towel-stuff, which depends on bacon. server.xmlrpc.set_distributions([ {'name':'choxie', 'version': '2.0.0.9', @@ -164,7 +203,9 @@ 'requires_dist': [], 'url': archive_path}, ]) - already_installed = [('bacon', '0.1', []), + + # name, version, deps. + already_installed = [('bacon', '0.1', []), ('chicken', '1.1', ['bacon (0.1)'])] output = install.get_infos("choxie", index=client, installed= get_installed_dists(already_installed)) @@ -221,23 +262,39 @@ # if one of the distribution installation fails, call uninstall on all # installed distributions. - d1 = ToInstallDist() - d2 = ToInstallDist(raise_error=True) - self.assertRaises(Exception, install.install_dists, [d1, d2]) - for dist in (d1, d2): - self.assertTrue(dist.install_called) - self.assertTrue(d1.uninstall_called) - self.assertFalse(d2.uninstall_called) + old_install_dist = install._install_dist + old_uninstall = getattr(install, 'uninstall', None) + + install._install_dist = MagicMock(return_value=[], + raise_exception=(False, True)) + install.uninstall = MagicMock() + try: + d1 = ToInstallDist() + d2 = ToInstallDist() + path = self.mkdtemp() + self.assertRaises(Exception, install.install_dists, [d1, d2], path) + self.assertTrue(install._install_dist.called_with(d1, path)) + self.assertTrue(install.uninstall.called) + finally: + install._install_dist = old_install_dist + install.uninstall = old_uninstall + def test_install_dists_success(self): - # test that the install method is called on each of the distributions. - d1 = ToInstallDist() - d2 = ToInstallDist() - install.install_dists([d1, d2]) - for dist in (d1, d2): - self.assertTrue(dist.install_called) - self.assertFalse(d1.uninstall_called) - self.assertFalse(d2.uninstall_called) + old_install_dist = install._install_dist + install._install_dist = MagicMock(return_value=[]) + try: + # test that the install method is called on each of the distributions. + d1 = ToInstallDist() + d2 = ToInstallDist() + + # should call install + path = self.mkdtemp() + install.install_dists([d1, d2], path) + for dist in (d1, d2): + self.assertTrue(install._install_dist.called_with(dist, path)) + finally: + install._install_dist = old_install_dist def test_install_from_infos_conflict(self): # assert conflicts raise an exception @@ -262,29 +319,46 @@ install.install_dists = old_install_dists def test_install_from_infos_remove_rollback(self): - # assert that if an error occurs, the removed files are restored. - remove = [] - for i in range(0,2): - remove.append(ToInstallDist(files=True, raise_error=True)) - to_install = [ToInstallDist(raise_error=True), - ToInstallDist()] + old_install_dist = install._install_dist + old_uninstall = getattr(install, 'uninstall', None) - install.install_from_infos(remove=remove, install=to_install) - # assert that the files are in the same place - # assert that the files have been removed - for dist in remove: - for f in dist.get_installed_files(): - self.assertTrue(os.path.exists(f)) + install._install_dist = MagicMock(return_value=[], + raise_exception=(False, True)) + install.uninstall = MagicMock() + try: + # assert that if an error occurs, the removed files are restored. + remove = [] + for i in range(0,2): + remove.append(ToInstallDist(files=True)) + to_install = [ToInstallDist(), ToInstallDist()] + + self.assertRaises(Exception, install.install_from_infos, + remove=remove, install=to_install) + # assert that the files are in the same place + # assert that the files have been removed + for dist in remove: + for f in dist.get_installed_files(): + self.assertTrue(os.path.exists(f)) + finally: + install.install_dist = old_install_dist + install.uninstall = old_uninstall + def test_install_from_infos_install_succes(self): - # assert that the distribution can be installed - install_path = "my_install_path" - to_install = [ToInstallDist(), ToInstallDist()] + old_install_dist = install._install_dist + install._install_dist = MagicMock([]) + try: + # assert that the distribution can be installed + install_path = "my_install_path" + to_install = [ToInstallDist(), ToInstallDist()] - install.install_from_infos(install=to_install, - install_path=install_path) - for dist in to_install: - self.assertEqual(dist.install_called_with, (install_path,)) + install.install_from_infos(install=to_install, + install_path=install_path) + for dist in to_install: + install._install_dist.called_with(install_path) + finally: + install._install_dist = old_install_dist + def test_suite(): suite = unittest.TestSuite() -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: merge the installer Message-ID: tarek.ziade pushed 931794fdbd09 to distutils2: http://hg.python.org/distutils2/rev/931794fdbd09 changeset: 925:931794fdbd09 parent: 898:06870bf6581a parent: 924:4a41a15d1f9f user: Alexis Metaireau date: Sat Jan 29 10:34:44 2011 +0100 summary: merge the installer files: distutils2/_backport/shutil.py distutils2/index/dist.py distutils2/index/simple.py distutils2/install.py distutils2/run.py distutils2/tests/pypi_server.py diff --git a/distutils2/_backport/shutil.py b/distutils2/_backport/shutil.py --- a/distutils2/_backport/shutil.py +++ b/distutils2/_backport/shutil.py @@ -568,3 +568,72 @@ os.chdir(save_cwd) return filename + + +def _ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + +def _unpack_zipfile(filename, extract_dir): + try: + import zipfile + except ImportError: + raise ReadError('zlib not supported, cannot unpack this archive.') + + if not zipfile.is_zipfile(filename): + raise ReadError("%s is not a zip file" % filename) + + zip = zipfile.ZipFile(filename) + try: + for info in zip.infolist(): + name = info.filename + if name.startswith('/') or '..' in name: + continue + + target = os.path.join(extract_dir, *name.split('/')) + if not target: + continue + + _ensure_directory(target) + if not name.endswith('/'): + # file + data = zip.read(info.filename) + f = open(target,'wb') + try: + f.write(data) + finally: + f.close() + del data + finally: + zip.close() + +def _unpack_tarfile(filename, extract_dir): + try: + tarobj = tarfile.open(filename) + except tarfile.TarError: + raise ReadError( + "%s is not a compressed or uncompressed tar file" % filename) + try: + tarobj.extractall(extract_dir) + finally: + tarobj.close() + + +_UNPACKERS = ( + (['.tar.gz', '.tgz', '.tar'], _unpack_tarfile), + (['.zip', '.egg'], _unpack_zipfile)) + + +def unpack_archive(filename, extract_dir=None): + if extract_dir is None: + extract_dir = os.path.dirname(filename) + + for formats, func in _UNPACKERS: + for format in formats: + if filename.endswith(format): + func(filename, extract_dir) + return extract_dir + + raise ValueError('Unknown archive format: %s' % filename) diff --git a/distutils2/index/dist.py b/distutils2/index/dist.py --- a/distutils2/index/dist.py +++ b/distutils2/index/dist.py @@ -17,19 +17,19 @@ import urllib import urlparse import zipfile - try: import hashlib except ImportError: from distutils2._backport import hashlib +from distutils2._backport.shutil import unpack_archive from distutils2.errors import IrrationalVersionError from distutils2.index.errors import (HashDoesNotMatch, UnsupportedHashName, CantParseArchiveName) from distutils2.version import (suggest_normalized_version, NormalizedVersion, get_version_predicate) from distutils2.metadata import DistributionMetadata -from distutils2.util import untar_file, unzip_file, splitext +from distutils2.util import splitext __all__ = ['ReleaseInfo', 'DistInfo', 'ReleasesList', 'get_infos_from_url'] @@ -206,6 +206,7 @@ __hash__ = object.__hash__ + class DistInfo(IndexReference): """Represents a distribution retrieved from an index (sdist, bdist, ...) """ @@ -313,17 +314,8 @@ filename = self.download() content_type = mimetypes.guess_type(filename)[0] + self._unpacked_dir = unpack_archive(filename) - if (content_type == 'application/zip' - or filename.endswith('.zip') - or filename.endswith('.pybundle') - or zipfile.is_zipfile(filename)): - unzip_file(filename, path, flatten=not filename.endswith('.pybundle')) - elif (content_type == 'application/x-gzip' - or tarfile.is_tarfile(filename) - or splitext(filename)[1].lower() in ('.tar', '.tar.gz', '.tar.bz2', '.tgz', '.tbz')): - untar_file(filename, path) - self._unpacked_dir = path return self._unpacked_dir def _check_md5(self, filename): diff --git a/distutils2/index/xmlrpc.py b/distutils2/index/xmlrpc.py --- a/distutils2/index/xmlrpc.py +++ b/distutils2/index/xmlrpc.py @@ -127,10 +127,17 @@ return release def get_metadata(self, project_name, version): - """Retreive project metadatas. + """Retrieve project metadata. Return a ReleaseInfo object, with metadata informations filled in. """ + # to be case-insensitive + projects = [d['name'] for d in + self.proxy.search({'name': project_name}) + if d['name'].lower() == project_name] + if len(projects) > 0: + project_name = projects[0] + metadata = self.proxy.release_data(project_name, version) project = self._get_project(project_name) if version not in project.get_versions(): diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -1,14 +1,16 @@ from tempfile import mkdtemp -import logging import shutil import os import errno import itertools +from distutils2 import logger from distutils2._backport.pkgutil import get_distributions +from distutils2._backport.sysconfig import get_config_var from distutils2.depgraph import generate_graph from distutils2.index import wrapper from distutils2.index.errors import ProjectNotFound, ReleaseNotFound +from distutils2.version import get_version_predicate """Provides installations scripts. @@ -53,7 +55,63 @@ else: raise e os.rename(old, new) - yield(old, new) + yield (old, new) + + +def _run_d1_install(archive_dir, path): + # backward compat: using setuptools or plain-distutils + cmd = '%s setup.py install --root=%s --record=%s' + setup_py = os.path.join(archive_dir, 'setup.py') + if 'setuptools' in open(setup_py).read(): + cmd += ' --single-version-externally-managed' + + # how to place this file in the egg-info dir + # for non-distutils2 projects ? + record_file = os.path.join(archive_dir, 'RECORD') + os.system(cmd % (sys.executable, path, record_file)) + if not os.path.exists(record_file): + raise ValueError('Failed to install.') + return open(record_file).read().split('\n') + + +def _run_d2_install(archive_dir, path): + # using our own install command + raise NotImplementedError() + + +def _install_dist(dist, path): + """Install a distribution into a path. + + This: + + * unpack the distribution + * copy the files in "path" + * determine if the distribution is distutils2 or distutils1. + """ + where = dist.unpack(archive) + + # get into the dir + archive_dir = None + for item in os.listdir(where): + fullpath = os.path.join(where, item) + if os.path.isdir(fullpath): + archive_dir = fullpath + break + + if archive_dir is None: + raise ValueError('Cannot locate the unpacked archive') + + # install + old_dir = os.getcwd() + os.chdir(archive_dir) + try: + # distutils2 or distutils1 ? + if 'setup.py' in os.listdir(archive_dir): + return _run_d1_install(archive_dir, path) + else: + return _run_d2_install(archive_dir, path) + finally: + os.chdir(old_dir) def install_dists(dists, path=None): @@ -65,19 +123,23 @@ Return a list of installed files. :param dists: distributions to install - :param path: base path to install distribution on + :param path: base path to install distribution in """ if not path: path = mkdtemp() installed_dists, installed_files = [], [] for d in dists: + logger.info('Installing %s %s' % (d.name, d.version)) try: - installed_files.extend(d.install(path)) + installed_files.extend(_install_dist(d, path)) installed_dists.append(d) except Exception, e : + logger.info('Failed. %s' % str(e)) + + # reverting for d in installed_dists: - d.uninstall() + _uninstall(d) raise e return installed_files @@ -123,16 +185,26 @@ try: if install: installed_files = install_dists(install, install_path) # install to tmp first - for files in temp_files.itervalues(): - for old, new in files: - os.remove(new) - except Exception,e: + except: # if an error occurs, put back the files in the good place. - for files in temp_files.itervalues(): + for files in temp_files.values(): for old, new in files: shutil.move(new, old) + # now re-raising + raise + + # we can remove them for good + for files in temp_files.values(): + for old, new in files: + os.remove(new) + + +def _get_setuptools_deps(release): + # NotImplementedError + pass + def get_infos(requirements, index=None, installed=None, prefer_final=True): """Return the informations on what's going to be installed and upgraded. @@ -154,13 +226,35 @@ Conflict contains all the conflicting distributions, if there is a conflict. """ + from ipdb import set_trace + set_trace() + if not installed: + logger.info('Reading installed distributions') + installed = get_distributions(use_egg_info=True) + + infos = {'install': [], 'remove': [], 'conflict': []} + # Is a compatible version of the project is already installed ? + predicate = get_version_predicate(requirements) + found = False + installed = list(installed) + for installed_project in installed: + # is it a compatible project ? + if predicate.name.lower() != installed_project.name.lower(): + continue + found = True + logger.info('Found %s %s' % (installed_project.name, + installed_project.metadata.version)) + if predicate.match(installed_project.metadata.version): + return infos + + break + + if not found: + logger.info('Project not installed.') if not index: index = wrapper.ClientWrapper() - if not installed: - installed = get_distributions(use_egg_info=True) - # Get all the releases that match the requirements try: releases = index.get_releases(requirements) @@ -170,28 +264,34 @@ # Pick up a release, and try to get the dependency tree release = releases.get_last(requirements, prefer_final=prefer_final) - # Iter since we found something without conflicts + if release is None: + logger.info('Could not find a matching project') + return infos + + # this works for Metadata 1.2 metadata = release.fetch_metadata() - # Get the distributions already_installed on the system - # and add the one we want to install + # for earlier, we need to build setuptools deps if any + if 'requires_dist' not in metadata: + deps = _get_setuptools_deps(release) + else: + deps = metadata['requires_dist'] distributions = itertools.chain(installed, [release]) depgraph = generate_graph(distributions) # Store all the already_installed packages in a list, in case of rollback. - infos = {'install': [], 'remove': [], 'conflict': []} - # Get what the missing deps are - for dists in depgraph.missing.itervalues(): - if dists: - logging.info("missing dependencies found, installing them") - # we have missing deps - for dist in dists: - _update_infos(infos, get_infos(dist, index, installed)) + dists = depgraph.missing[release] + if dists: + logger.info("missing dependencies found, installing them") + # we have missing deps + for dist in dists: + _update_infos(infos, get_infos(dist, index, installed)) # Fill in the infos existing = [d for d in installed if d.name == release.name] + if existing: infos['remove'].append(existing[0]) infos['conflict'].extend(depgraph.reverse_list[existing[0]]) @@ -203,7 +303,7 @@ """extends the lists contained in the `info` dict with those contained in the `new_info` one """ - for key, value in infos.iteritems(): + for key, value in infos.items(): if key in new_infos: infos[key].extend(new_infos[key]) @@ -214,5 +314,28 @@ attrs['requirements'] = sys.argv[1] get_infos(**attrs) + +def install(project): + logger.info('Getting information about "%s".' % project) + try: + info = get_infos(project) + except InstallationException: + logger.info('Cound not find "%s".' % project) + return + + if info['install'] == []: + logger.info('Nothing to install.') + return + + install_path = get_config_var('base') + try: + install_from_infos(info['install'], info['remove'], info['conflict'], + install_path=install_path) + + except InstallationConflict, e: + projects = ['%s %s' % (p.name, p.metadata.version) for p in e.args[0]] + logger.info('"%s" conflicts with "%s"' % (project, ','.join(projects))) + + if __name__ == '__main__': main() diff --git a/distutils2/run.py b/distutils2/run.py --- a/distutils2/run.py +++ b/distutils2/run.py @@ -1,7 +1,9 @@ import os import sys from optparse import OptionParser +import logging +from distutils2 import logger from distutils2.util import grok_environment_error from distutils2.errors import (DistutilsSetupError, DistutilsArgError, DistutilsError, CCompilerError) @@ -9,6 +11,7 @@ from distutils2 import __version__ from distutils2._backport.pkgutil import get_distributions, get_distribution from distutils2.depgraph import generate_graph +from distutils2.install import install # This is a barebones help message generated displayed when the user # runs the setup script with no arguments at all. More useful help @@ -114,8 +117,17 @@ return dist +def _set_logger(): + logger.setLevel(logging.INFO) + sth = logging.StreamHandler(sys.stderr) + sth.setLevel(logging.INFO) + logger.addHandler(sth) + logger.propagate = 0 + + def main(): """Main entry point for Distutils2""" + _set_logger() parser = OptionParser() parser.disable_interspersed_args() parser.usage = '%prog [options] cmd1 cmd2 ..' @@ -136,6 +148,14 @@ action="store_true", dest="fgraph", default=False, help="Display the full graph for installed distributions.") + parser.add_option("-i", "--install", + action="store", dest="install", + help="Install a project.") + + parser.add_option("-r", "--remove", + action="store", dest="remove", + help="Remove a project.") + options, args = parser.parse_args() if options.version: print('Distutils2 %s' % __version__) @@ -169,6 +189,10 @@ print(graph) sys.exit(0) + if options.install is not None: + install(options.install) + sys.exit(0) + if len(args) == 0: parser.print_help() sys.exit(0) diff --git a/distutils2/util.py b/distutils2/util.py --- a/distutils2/util.py +++ b/distutils2/util.py @@ -674,83 +674,6 @@ return base, ext -def unzip_file(filename, location, flatten=True): - """Unzip the file (zip file located at filename) to the destination - location""" - if not os.path.exists(location): - os.makedirs(location) - zipfp = open(filename, 'rb') - try: - zip = zipfile.ZipFile(zipfp) - leading = has_leading_dir(zip.namelist()) and flatten - for name in zip.namelist(): - data = zip.read(name) - fn = name - if leading: - fn = split_leading_dir(name)[1] - fn = os.path.join(location, fn) - dir = os.path.dirname(fn) - if not os.path.exists(dir): - os.makedirs(dir) - if fn.endswith('/') or fn.endswith('\\'): - # A directory - if not os.path.exists(fn): - os.makedirs(fn) - else: - fp = open(fn, 'wb') - try: - fp.write(data) - finally: - fp.close() - finally: - zipfp.close() - - -def untar_file(filename, location): - """Untar the file (tar file located at filename) to the destination - location - """ - if not os.path.exists(location): - os.makedirs(location) - if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): - mode = 'r:gz' - elif (filename.lower().endswith('.bz2') - or filename.lower().endswith('.tbz')): - mode = 'r:bz2' - elif filename.lower().endswith('.tar'): - mode = 'r' - else: - mode = 'r:*' - tar = tarfile.open(filename, mode) - try: - leading = has_leading_dir([member.name for member in tar.getmembers()]) - for member in tar.getmembers(): - fn = member.name - if leading: - fn = split_leading_dir(fn)[1] - path = os.path.join(location, fn) - if member.isdir(): - if not os.path.exists(path): - os.makedirs(path) - else: - try: - fp = tar.extractfile(member) - except (KeyError, AttributeError): - # Some corrupt tar files seem to produce this - # (specifically bad symlinks) - continue - if not os.path.exists(os.path.dirname(path)): - os.makedirs(os.path.dirname(path)) - destfp = open(path, 'wb') - try: - shutil.copyfileobj(fp, destfp) - finally: - destfp.close() - fp.close() - finally: - tar.close() - - def has_leading_dir(paths): """Returns true if all the paths have the same leading path name (i.e., everything is in one subdirectory in an archive)""" -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Rename ambiguous record file in one test Message-ID: tarek.ziade pushed 2c55cceccac5 to distutils2: http://hg.python.org/distutils2/rev/2c55cceccac5 changeset: 928:2c55cceccac5 parent: 788:bacff78eb038 user: ?ric Araujo date: Sat Oct 30 11:07:24 2010 +0200 summary: Rename ambiguous record file in one test files: distutils2/tests/test_command_install_dist.py diff --git a/distutils2/tests/test_command_install_dist.py b/distutils2/tests/test_command_install_dist.py --- a/distutils2/tests/test_command_install_dist.py +++ b/distutils2/tests/test_command_install_dist.py @@ -177,8 +177,8 @@ cmd.user = 'user' self.assertRaises(DistutilsOptionError, cmd.finalize_options) - def test_record(self): - + def test_old_record(self): + # test pre-PEP 376 --record option (outside dist-info dir) install_dir = self.mkdtemp() pkgdir, dist = self.create_dist() @@ -186,11 +186,11 @@ cmd = install_dist(dist) dist.command_obj['install_dist'] = cmd cmd.root = install_dir - cmd.record = os.path.join(pkgdir, 'RECORD') + cmd.record = os.path.join(pkgdir, 'filelist') cmd.ensure_finalized() cmd.run() - # let's check the RECORD file was created with four + # let's check the record file was created with four # lines, one for each .dist-info entry: METADATA, # INSTALLER, REQUSTED, RECORD f = open(cmd.record) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Remove bogus argument from TempdirManager.create_dist Message-ID: tarek.ziade pushed a29094d8b515 to distutils2: http://hg.python.org/distutils2/rev/a29094d8b515 changeset: 929:a29094d8b515 user: ?ric Araujo date: Sat Oct 30 12:36:37 2010 +0200 summary: Remove bogus argument from TempdirManager.create_dist files: distutils2/tests/support.py diff --git a/distutils2/tests/support.py b/distutils2/tests/support.py --- a/distutils2/tests/support.py +++ b/distutils2/tests/support.py @@ -147,7 +147,7 @@ finally: f.close() - def create_dist(self, pkg_name='foo', **kw): + def create_dist(self, **kw): """Create a stub distribution object and files. This function creates a Distribution instance (use keyword arguments @@ -155,17 +155,19 @@ (currently an empty directory). It returns the path to the directory and the Distribution instance. - You can use TempdirManager.write_file to write any file in that + You can use self.write_file to write any file in that directory, e.g. setup scripts or Python modules. """ # Late import so that third parties can import support without # loading a ton of distutils2 modules in memory. from distutils2.dist import Distribution + if 'name' not in kw: + kw['name'] = 'foo' tmp_dir = self.mkdtemp() - pkg_dir = os.path.join(tmp_dir, pkg_name) - os.mkdir(pkg_dir) + project_dir = os.path.join(tmp_dir, kw['name']) + os.mkdir(project_dir) dist = Distribution(attrs=kw) - return pkg_dir, dist + return project_dir, dist class EnvironGuard(object): @@ -222,4 +224,3 @@ d.parse_config_files() d.parse_command_line() return d - -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: branch merge Message-ID: tarek.ziade pushed 11f13263c188 to distutils2: http://hg.python.org/distutils2/rev/11f13263c188 changeset: 927:11f13263c188 parent: 926:30c453712740 parent: 920:860a4bcab873 user: Alexis Metaireau date: Sat Jan 29 16:37:32 2011 +0100 summary: branch merge files: distutils2/install.py distutils2/run.py distutils2/util.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -660,14 +660,14 @@ _cache_generated_egg = False -def _yield_distributions(include_dist, include_egg): +def _yield_distributions(include_dist, include_egg, paths=sys.path): """ Yield .dist-info and .egg(-info) distributions, based on the arguments :parameter include_dist: yield .dist-info distributions :parameter include_egg: yield .egg(-info) distributions """ - for path in sys.path: + for path in paths: realpath = os.path.realpath(path) if not os.path.isdir(realpath): continue @@ -679,7 +679,7 @@ dir.endswith('.egg')): yield EggInfoDistribution(dist_path) -def _generate_cache(use_egg_info=False): +def _generate_cache(use_egg_info=False, paths=sys.path): global _cache_generated, _cache_generated_egg if _cache_generated_egg or (_cache_generated and not use_egg_info): @@ -688,7 +688,7 @@ gen_dist = not _cache_generated gen_egg = use_egg_info - for dist in _yield_distributions(gen_dist, gen_egg): + for dist in _yield_distributions(gen_dist, gen_egg, paths): if isinstance(dist, Distribution): _cache_path[dist.path] = dist if not dist.name in _cache_name: @@ -1017,7 +1017,7 @@ return '-'.join([name, normalized_version]) + file_extension -def get_distributions(use_egg_info=False): +def get_distributions(use_egg_info=False, paths=sys.path): """ Provides an iterator that looks for ``.dist-info`` directories in ``sys.path`` and returns :class:`Distribution` instances for each one of @@ -1028,7 +1028,7 @@ instances """ if not _cache_enabled: - for dist in _yield_distributions(True, use_egg_info): + for dist in _yield_distributions(True, use_egg_info, paths): yield dist else: _generate_cache(use_egg_info) @@ -1041,7 +1041,7 @@ yield dist -def get_distribution(name, use_egg_info=False): +def get_distribution(name, use_egg_info=False, paths=sys.path): """ Scans all elements in ``sys.path`` and looks for all directories ending with ``.dist-info``. Returns a :class:`Distribution` @@ -1059,7 +1059,7 @@ :rtype: :class:`Distribution` or :class:`EggInfoDistribution` or None """ if not _cache_enabled: - for dist in _yield_distributions(True, use_egg_info): + for dist in _yield_distributions(True, use_egg_info, paths): if dist.name == name: return dist else: diff --git a/distutils2/command/build_py.py b/distutils2/command/build_py.py --- a/distutils2/command/build_py.py +++ b/distutils2/command/build_py.py @@ -66,10 +66,9 @@ self.packages = self.distribution.packages self.py_modules = self.distribution.py_modules self.package_data = self.distribution.package_data - self.package_dir = {} - if self.distribution.package_dir: - for name, path in self.distribution.package_dir.iteritems(): - self.package_dir[name] = convert_path(path) + self.package_dir = None + if self.distribution.package_dir is not None: + self.package_dir = convert_path(self.distribution.package_dir) self.data_files = self.get_data_files() # Ick, copied straight from install_lib.py (fancy_getopt needs a @@ -179,41 +178,14 @@ """Return the directory, relative to the top of the source distribution, where package 'package' should be found (at least according to the 'package_dir' option, if any).""" + path = package.split('.') + if self.package_dir is not None: + path.insert(0, self.package_dir) - path = package.split('.') + if len(path) > 0: + return os.path.join(*path) - if not self.package_dir: - if path: - return os.path.join(*path) - else: - return '' - else: - tail = [] - while path: - try: - pdir = self.package_dir['.'.join(path)] - except KeyError: - tail.insert(0, path[-1]) - del path[-1] - else: - tail.insert(0, pdir) - return os.path.join(*tail) - else: - # Oops, got all the way through 'path' without finding a - # match in package_dir. If package_dir defines a directory - # for the root (nameless) package, then fallback on it; - # otherwise, we might as well have not consulted - # package_dir at all, as we just use the directory implied - # by 'tail' (which should be the same as the original value - # of 'path' at this point). - pdir = self.package_dir.get('') - if pdir is not None: - tail.insert(0, pdir) - - if tail: - return os.path.join(*tail) - else: - return '' + return '' def check_package(self, package, package_dir): """Helper function for `find_package_modules()` and `find_modules()'. diff --git a/distutils2/command/sdist.py b/distutils2/command/sdist.py --- a/distutils2/command/sdist.py +++ b/distutils2/command/sdist.py @@ -18,7 +18,8 @@ from distutils2.command import get_command_names from distutils2.command.cmd import Command from distutils2.errors import (DistutilsPlatformError, DistutilsOptionError, - DistutilsTemplateError, DistutilsModuleError) + DistutilsTemplateError, DistutilsModuleError, + DistutilsFileError) from distutils2.manifest import Manifest from distutils2 import logger from distutils2.util import convert_path, resolve_name @@ -214,8 +215,6 @@ def add_defaults(self): """Add all the default files to self.filelist: - - README or README.txt - - test/test*.py - all pure Python modules mentioned in setup script - all files pointed by package_data (build_py) - all files defined in data_files. @@ -225,32 +224,6 @@ Warns if (README or README.txt) or setup.py are missing; everything else is optional. """ - standards = [('README', 'README.txt')] - for fn in standards: - if isinstance(fn, tuple): - alts = fn - got_it = 0 - for fn in alts: - if os.path.exists(fn): - got_it = 1 - self.filelist.append(fn) - break - - if not got_it: - self.warn("standard file not found: should have one of " + - string.join(alts, ', ')) - else: - if os.path.exists(fn): - self.filelist.append(fn) - else: - self.warn("standard file '%s' not found" % fn) - - optional = ['test/test*.py', 'setup.cfg'] - for pattern in optional: - files = filter(os.path.isfile, glob(pattern)) - if files: - self.filelist.extend(files) - for cmd_name in get_command_names(): try: cmd_obj = self.get_finalized_command(cmd_name) @@ -319,6 +292,12 @@ logger.warn("no files to distribute -- empty manifest?") else: logger.info(msg) + + for file in self.distribution.metadata.requires_files: + if file not in files: + msg = "'%s' must be included explicitly in 'extra_files'" % file + raise DistutilsFileError(msg) + for file in files: if not os.path.isfile(file): logger.warn("'%s' not a regular file -- skipping" % file) @@ -376,4 +355,3 @@ # Now create them for dir in need_dirs: self.mkpath(dir, mode, verbose=verbose, dry_run=dry_run) - diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -76,10 +76,9 @@ return value def _multiline(self, value): - if '\n' in value: - value = [v for v in - [v.strip() for v in value.split('\n')] - if v != ''] + value = [v for v in + [v.strip() for v in value.split('\n')] + if v != ''] return value def _read_setup_cfg(self, parser): @@ -100,7 +99,9 @@ if 'metadata' in content: for key, value in content['metadata'].iteritems(): key = key.replace('_', '-') - value = self._multiline(value) + if metadata.is_multi_field(key): + value = self._multiline(value) + if key == 'project-url': value = [(label.strip(), url.strip()) for label, url in @@ -112,30 +113,45 @@ "mutually exclusive") raise DistutilsOptionError(msg) - f = open(value) # will raise if file not found - try: - value = f.read() - finally: - f.close() + if isinstance(value, list): + filenames = value + else: + filenames = value.split() + + # concatenate each files + value = '' + for filename in filenames: + f = open(filename) # will raise if file not found + try: + value += f.read().strip() + '\n' + finally: + f.close() + # add filename as a required file + if filename not in metadata.requires_files: + metadata.requires_files.append(filename) + value = value.strip() key = 'description' if metadata.is_metadata_field(key): metadata[key] = self._convert_metadata(key, value) + if 'files' in content: - files = dict([(key, self._multiline(value)) + def _convert(key, value): + if key not in ('packages_root',): + value = self._multiline(value) + return value + + files = dict([(key, _convert(key, value)) for key, value in content['files'].iteritems()]) self.dist.packages = [] - self.dist.package_dir = {} + self.dist.package_dir = pkg_dir = files.get('packages_root') packages = files.get('packages', []) if isinstance(packages, str): packages = [packages] for package in packages: - if ':' in package: - dir_, package = package.split(':') - self.dist.package_dir[package] = dir_ self.dist.packages.append(package) self.dist.py_modules = files.get('modules', []) diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -310,6 +310,13 @@ infos[key].extend(new_infos[key]) +def remove(project_name): + """Removes a single project from the installation""" + pass + + + + def main(**attrs): if 'script_args' not in attrs: import sys diff --git a/distutils2/markers.py b/distutils2/markers.py new file mode 100644 --- /dev/null +++ b/distutils2/markers.py @@ -0,0 +1,194 @@ +""" Micro-language for PEP 345 environment markers +""" +import sys +import platform +import os +from tokenize import tokenize, NAME, OP, STRING, ENDMARKER +from StringIO import StringIO + +__all__ = ['interpret'] + + +# allowed operators +_OPERATORS = {'==': lambda x, y: x == y, + '!=': lambda x, y: x != y, + '>': lambda x, y: x > y, + '>=': lambda x, y: x >= y, + '<': lambda x, y: x < y, + '<=': lambda x, y: x <= y, + 'in': lambda x, y: x in y, + 'not in': lambda x, y: x not in y} + + +def _operate(operation, x, y): + return _OPERATORS[operation](x, y) + + +# restricted set of variables +_VARS = {'sys.platform': sys.platform, + 'python_version': sys.version[:3], + 'python_full_version': sys.version.split(' ', 1)[0], + 'os.name': os.name, + 'platform.version': platform.version(), + 'platform.machine': platform.machine()} + + +class _Operation(object): + + def __init__(self, execution_context=None): + self.left = None + self.op = None + self.right = None + if execution_context is None: + execution_context = {} + self.execution_context = execution_context + + def _get_var(self, name): + if name in self.execution_context: + return self.execution_context[name] + return _VARS[name] + + def __repr__(self): + return '%s %s %s' % (self.left, self.op, self.right) + + def _is_string(self, value): + if value is None or len(value) < 2: + return False + for delimiter in '"\'': + if value[0] == value[-1] == delimiter: + return True + return False + + def _is_name(self, value): + return value in _VARS + + def _convert(self, value): + if value in _VARS: + return self._get_var(value) + return value.strip('"\'') + + def _check_name(self, value): + if value not in _VARS: + raise NameError(value) + + def _nonsense_op(self): + msg = 'This operation is not supported : "%s"' % self + raise SyntaxError(msg) + + def __call__(self): + # make sure we do something useful + if self._is_string(self.left): + if self._is_string(self.right): + self._nonsense_op() + self._check_name(self.right) + else: + if not self._is_string(self.right): + self._nonsense_op() + self._check_name(self.left) + + if self.op not in _OPERATORS: + raise TypeError('Operator not supported "%s"' % self.op) + + left = self._convert(self.left) + right = self._convert(self.right) + return _operate(self.op, left, right) + + +class _OR(object): + def __init__(self, left, right=None): + self.left = left + self.right = right + + def filled(self): + return self.right is not None + + def __repr__(self): + return 'OR(%r, %r)' % (self.left, self.right) + + def __call__(self): + return self.left() or self.right() + + +class _AND(object): + def __init__(self, left, right=None): + self.left = left + self.right = right + + def filled(self): + return self.right is not None + + def __repr__(self): + return 'AND(%r, %r)' % (self.left, self.right) + + def __call__(self): + return self.left() and self.right() + + +class _CHAIN(object): + + def __init__(self, execution_context=None): + self.ops = [] + self.op_starting = True + self.execution_context = execution_context + + def eat(self, toktype, tokval, rowcol, line, logical_line): + if toktype not in (NAME, OP, STRING, ENDMARKER): + raise SyntaxError('Type not supported "%s"' % tokval) + + if self.op_starting: + op = _Operation(self.execution_context) + if len(self.ops) > 0: + last = self.ops[-1] + if isinstance(last, (_OR, _AND)) and not last.filled(): + last.right = op + else: + self.ops.append(op) + else: + self.ops.append(op) + self.op_starting = False + else: + op = self.ops[-1] + + if (toktype == ENDMARKER or + (toktype == NAME and tokval in ('and', 'or'))): + if toktype == NAME and tokval == 'and': + self.ops.append(_AND(self.ops.pop())) + elif toktype == NAME and tokval == 'or': + self.ops.append(_OR(self.ops.pop())) + self.op_starting = True + return + + if isinstance(op, (_OR, _AND)) and op.right is not None: + op = op.right + + if ((toktype in (NAME, STRING) and tokval not in ('in', 'not')) + or (toktype == OP and tokval == '.')): + if op.op is None: + if op.left is None: + op.left = tokval + else: + op.left += tokval + else: + if op.right is None: + op.right = tokval + else: + op.right += tokval + elif toktype == OP or tokval in ('in', 'not'): + if tokval == 'in' and op.op == 'not': + op.op = 'not in' + else: + op.op = tokval + + def result(self): + for op in self.ops: + if not op(): + return False + return True + + +def interpret(marker, execution_context=None): + """Interpret a marker and return a result depending on environment.""" + marker = marker.strip() + operations = _CHAIN(execution_context) + tokenize(StringIO(marker).readline, operations.eat) + return operations.result() diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -5,13 +5,12 @@ import os import sys -import platform import re from StringIO import StringIO from email import message_from_file -from tokenize import tokenize, NAME, OP, STRING, ENDMARKER from distutils2 import logger +from distutils2.markers import interpret from distutils2.version import (is_valid_predicate, is_valid_version, is_valid_versions) from distutils2.errors import (MetadataMissingError, @@ -78,13 +77,13 @@ 'Obsoletes-Dist', 'Requires-External', 'Maintainer', 'Maintainer-email', 'Project-URL') +_345_REQUIRED = ('Name', 'Version') + _ALL_FIELDS = set() _ALL_FIELDS.update(_241_FIELDS) _ALL_FIELDS.update(_314_FIELDS) _ALL_FIELDS.update(_345_FIELDS) -_345_REQUIRED = ('Name', 'Version') - def _version2fieldlist(version): if version == '1.0': return _241_FIELDS @@ -174,14 +173,19 @@ _LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes', 'Requires', 'Provides', 'Obsoletes-Dist', 'Provides-Dist', 'Requires-Dist', 'Requires-External', - 'Project-URL') + 'Project-URL', 'Supported-Platform') _LISTTUPLEFIELDS = ('Project-URL',) _ELEMENTSFIELD = ('Keywords',) _UNICODEFIELDS = ('Author', 'Maintainer', 'Summary', 'Description') -_MISSING = object() +class NoDefault(object): + """Marker object used for clean representation""" + def __repr__(self): + return '' + +_MISSING = NoDefault() class DistributionMetadata(object): """The metadata of a release. @@ -202,6 +206,7 @@ self._fields = {} self.display_warnings = display_warnings self.version = None + self.requires_files = [] self.docutils_support = _HAS_DOCUTILS self.platform_dependent = platform_dependent self.execution_context = execution_context @@ -285,7 +290,7 @@ if not self.platform_dependent or ';' not in value: return True, value value, marker = value.split(';') - return _interpret(marker, self.execution_context), value + return interpret(marker, self.execution_context), value def _remove_line_prefix(self, value): return _LINE_PREFIX.sub('\n', value) @@ -294,13 +299,20 @@ # Public API # def get_fullname(self): + """Return the distribution name with version""" return '%s-%s' % (self['Name'], self['Version']) def is_metadata_field(self, name): + """return True if name is a valid metadata key""" name = self._convert_name(name) return name in _ALL_FIELDS + def is_multi_field(self, name): + name = self._convert_name(name) + return name in _LISTFIELDS + def read(self, filepath): + """Read the metadata values from a file path.""" self.read_file(open(filepath)) def read_file(self, fileob): @@ -454,7 +466,8 @@ return value def check(self, strict=False): - """Check if the metadata is compliant.""" + """Check if the metadata is compliant. If strict is False then raise if + no Name or Version are provided""" # XXX should check the versions (if the file was loaded) missing, warnings = [], [] @@ -494,198 +507,13 @@ return missing, warnings def keys(self): + """Dict like api""" return _version2fieldlist(self.version) def values(self): + """Dict like api""" return [self[key] for key in self.keys()] def items(self): + """Dict like api""" return [(key, self[key]) for key in self.keys()] - - -# -# micro-language for PEP 345 environment markers -# - -# allowed operators -_OPERATORS = {'==': lambda x, y: x == y, - '!=': lambda x, y: x != y, - '>': lambda x, y: x > y, - '>=': lambda x, y: x >= y, - '<': lambda x, y: x < y, - '<=': lambda x, y: x <= y, - 'in': lambda x, y: x in y, - 'not in': lambda x, y: x not in y} - - -def _operate(operation, x, y): - return _OPERATORS[operation](x, y) - -# restricted set of variables -_VARS = {'sys.platform': sys.platform, - 'python_version': sys.version[:3], - 'python_full_version': sys.version.split(' ', 1)[0], - 'os.name': os.name, - 'platform.version': platform.version(), - 'platform.machine': platform.machine()} - - -class _Operation(object): - - def __init__(self, execution_context=None): - self.left = None - self.op = None - self.right = None - if execution_context is None: - execution_context = {} - self.execution_context = execution_context - - def _get_var(self, name): - if name in self.execution_context: - return self.execution_context[name] - return _VARS[name] - - def __repr__(self): - return '%s %s %s' % (self.left, self.op, self.right) - - def _is_string(self, value): - if value is None or len(value) < 2: - return False - for delimiter in '"\'': - if value[0] == value[-1] == delimiter: - return True - return False - - def _is_name(self, value): - return value in _VARS - - def _convert(self, value): - if value in _VARS: - return self._get_var(value) - return value.strip('"\'') - - def _check_name(self, value): - if value not in _VARS: - raise NameError(value) - - def _nonsense_op(self): - msg = 'This operation is not supported : "%s"' % self - raise SyntaxError(msg) - - def __call__(self): - # make sure we do something useful - if self._is_string(self.left): - if self._is_string(self.right): - self._nonsense_op() - self._check_name(self.right) - else: - if not self._is_string(self.right): - self._nonsense_op() - self._check_name(self.left) - - if self.op not in _OPERATORS: - raise TypeError('Operator not supported "%s"' % self.op) - - left = self._convert(self.left) - right = self._convert(self.right) - return _operate(self.op, left, right) - - -class _OR(object): - def __init__(self, left, right=None): - self.left = left - self.right = right - - def filled(self): - return self.right is not None - - def __repr__(self): - return 'OR(%r, %r)' % (self.left, self.right) - - def __call__(self): - return self.left() or self.right() - - -class _AND(object): - def __init__(self, left, right=None): - self.left = left - self.right = right - - def filled(self): - return self.right is not None - - def __repr__(self): - return 'AND(%r, %r)' % (self.left, self.right) - - def __call__(self): - return self.left() and self.right() - - -class _CHAIN(object): - - def __init__(self, execution_context=None): - self.ops = [] - self.op_starting = True - self.execution_context = execution_context - - def eat(self, toktype, tokval, rowcol, line, logical_line): - if toktype not in (NAME, OP, STRING, ENDMARKER): - raise SyntaxError('Type not supported "%s"' % tokval) - - if self.op_starting: - op = _Operation(self.execution_context) - if len(self.ops) > 0: - last = self.ops[-1] - if isinstance(last, (_OR, _AND)) and not last.filled(): - last.right = op - else: - self.ops.append(op) - else: - self.ops.append(op) - self.op_starting = False - else: - op = self.ops[-1] - - if (toktype == ENDMARKER or - (toktype == NAME and tokval in ('and', 'or'))): - if toktype == NAME and tokval == 'and': - self.ops.append(_AND(self.ops.pop())) - elif toktype == NAME and tokval == 'or': - self.ops.append(_OR(self.ops.pop())) - self.op_starting = True - return - - if isinstance(op, (_OR, _AND)) and op.right is not None: - op = op.right - - if ((toktype in (NAME, STRING) and tokval not in ('in', 'not')) - or (toktype == OP and tokval == '.')): - if op.op is None: - if op.left is None: - op.left = tokval - else: - op.left += tokval - else: - if op.right is None: - op.right = tokval - else: - op.right += tokval - elif toktype == OP or tokval in ('in', 'not'): - if tokval == 'in' and op.op == 'not': - op.op = 'not in' - else: - op.op = tokval - - def result(self): - for op in self.ops: - if not op(): - return False - return True - - -def _interpret(marker, execution_context=None): - """Interpret a marker and return a result depending on environment.""" - marker = marker.strip() - operations = _CHAIN(execution_context) - tokenize(StringIO(marker).readline, operations.eat) - return operations.result() diff --git a/distutils2/run.py b/distutils2/run.py --- a/distutils2/run.py +++ b/distutils2/run.py @@ -112,6 +112,7 @@ except (DistutilsError, CCompilerError), msg: + raise raise SystemExit, "error: " + str(msg) return dist @@ -136,6 +137,10 @@ action="store_true", dest="version", default=False, help="Prints out the version of Distutils2 and exits.") + parser.add_option("-m", "--metadata", + action="append", dest="metadata", default=[], + help="List METADATA metadata or 'all' for all metadatas.") + parser.add_option("-s", "--search", action="store", dest="search", default=None, help="Search for installed distributions.") @@ -161,6 +166,31 @@ print('Distutils2 %s' % __version__) # sys.exit(0) + if len(options.metadata): + from distutils2.dist import Distribution + dist = Distribution() + dist.parse_config_files() + metadata = dist.metadata + + if 'all' in options.metadata: + keys = metadata.keys() + else: + keys = options.metadata + if len(keys) == 1: + print metadata[keys[0]] + sys.exit(0) + + for key in keys: + if key in metadata: + print(metadata._convert_name(key)+':') + value = metadata[key] + if isinstance(value, list): + for v in value: + print(' '+v) + else: + print(' '+value.replace('\n', '\n ')) + sys.exit(0) + if options.search is not None: search = options.search.lower() for dist in get_distributions(use_egg_info=True): diff --git a/distutils2/tests/test_command_build_ext.py b/distutils2/tests/test_command_build_ext.py --- a/distutils2/tests/test_command_build_ext.py +++ b/distutils2/tests/test_command_build_ext.py @@ -289,7 +289,7 @@ # inplace = 0, cmd.package = 'bar' build_py = cmd.get_finalized_command('build_py') - build_py.package_dir = {'': 'bar'} + build_py.package_dir = 'bar' path = cmd.get_ext_fullpath('foo') # checking that the last directory is the build_dir path = os.path.split(path)[0] @@ -318,7 +318,7 @@ dist = Distribution() cmd = build_ext(dist) cmd.inplace = 1 - cmd.distribution.package_dir = {'': 'src'} + cmd.distribution.package_dir = 'src' cmd.distribution.packages = ['lxml', 'lxml.html'] curdir = os.getcwd() wanted = os.path.join(curdir, 'src', 'lxml', 'etree' + ext) @@ -334,7 +334,7 @@ # building twisted.runner.portmap not inplace build_py = cmd.get_finalized_command('build_py') - build_py.package_dir = {} + build_py.package_dir = None cmd.distribution.packages = ['twisted', 'twisted.runner.portmap'] path = cmd.get_ext_fullpath('twisted.runner.portmap') wanted = os.path.join(curdir, 'tmpdir', 'twisted', 'runner', diff --git a/distutils2/tests/test_command_build_py.py b/distutils2/tests/test_command_build_py.py --- a/distutils2/tests/test_command_build_py.py +++ b/distutils2/tests/test_command_build_py.py @@ -17,12 +17,14 @@ def test_package_data(self): sources = self.mkdtemp() - f = open(os.path.join(sources, "__init__.py"), "w") + pkg_dir = os.path.join(sources, 'pkg') + os.mkdir(pkg_dir) + f = open(os.path.join(pkg_dir, "__init__.py"), "w") try: f.write("# Pretend this is a package.") finally: f.close() - f = open(os.path.join(sources, "README.txt"), "w") + f = open(os.path.join(pkg_dir, "README.txt"), "w") try: f.write("Info about this package") finally: @@ -31,8 +33,9 @@ destination = self.mkdtemp() dist = Distribution({"packages": ["pkg"], - "package_dir": {"pkg": sources}}) + "package_dir": sources}) # script_name need not exist, it just need to be initialized + dist.script_name = os.path.join(sources, "setup.py") dist.command_obj["build"] = support.DummyCommand( force=0, @@ -42,7 +45,7 @@ use_2to3=False) dist.packages = ["pkg"] dist.package_data = {"pkg": ["README.txt"]} - dist.package_dir = {"pkg": sources} + dist.package_dir = sources cmd = build_py(dist) cmd.compile = 1 @@ -68,19 +71,20 @@ # create the distribution files. sources = self.mkdtemp() - open(os.path.join(sources, "__init__.py"), "w").close() - - testdir = os.path.join(sources, "doc") + pkg = os.path.join(sources, 'pkg') + os.mkdir(pkg) + open(os.path.join(pkg, "__init__.py"), "w").close() + testdir = os.path.join(pkg, "doc") os.mkdir(testdir) open(os.path.join(testdir, "testfile"), "w").close() os.chdir(sources) old_stdout = sys.stdout - sys.stdout = StringIO.StringIO() + #sys.stdout = StringIO.StringIO() try: dist = Distribution({"packages": ["pkg"], - "package_dir": {"pkg": ""}, + "package_dir": sources, "package_data": {"pkg": ["doc/*"]}}) # script_name need not exist, it just need to be initialized dist.script_name = os.path.join(sources, "setup.py") @@ -89,7 +93,7 @@ try: dist.run_commands() - except DistutilsFileError: + except DistutilsFileError, e: self.fail("failed package_data test when package_dir is ''") finally: # Restore state. diff --git a/distutils2/tests/test_command_sdist.py b/distutils2/tests/test_command_sdist.py --- a/distutils2/tests/test_command_sdist.py +++ b/distutils2/tests/test_command_sdist.py @@ -45,7 +45,6 @@ MANIFEST = """\ # file GENERATED by distutils, do NOT edit -README inroot.txt data%(sep)sdata.dt scripts%(sep)sscript.py @@ -141,7 +140,7 @@ zip_file.close() # making sure everything has been pruned correctly - self.assertEqual(len(content), 3) + self.assertEqual(len(content), 2) @unittest.skipUnless(zlib, "requires zlib") def test_make_distribution(self): @@ -236,7 +235,7 @@ zip_file.close() # making sure everything was added - self.assertEqual(len(content), 10) + self.assertEqual(len(content), 9) # checking the MANIFEST manifest = open(join(self.tmp_dir, 'MANIFEST')).read() @@ -362,8 +361,7 @@ if line.strip() != ''] finally: f.close() - - self.assertEqual(len(manifest), 4) + self.assertEqual(len(manifest), 3) # adding a file self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#') @@ -383,7 +381,7 @@ f.close() # do we have the new file in MANIFEST ? - self.assertEqual(len(manifest2), 5) + self.assertEqual(len(manifest2), 4) self.assertIn('doc2.txt', manifest2[-1]) def test_manifest_marker(self): diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -5,6 +5,8 @@ from StringIO import StringIO from distutils2.tests import unittest, support, run_unittest +from distutils2.command.sdist import sdist +from distutils2.errors import DistutilsFileError SETUP_CFG = """ @@ -16,7 +18,7 @@ maintainer = ??ric Araujo maintainer_email = merwok at netwok.org summary = A sample project demonstrating distutils2 packaging -description-file = README +description-file = %(description-file)s keywords = distutils2, packaging, sample project classifier = @@ -47,9 +49,11 @@ Fork in progress, http://bitbucket.org/Merwok/sample-distutils2-project [files] +packages_root = src + packages = one - src:two - src2:three + two + three modules = haven @@ -66,6 +70,8 @@ config = cfg/data.cfg /etc/init.d = init-script +extra_files = %(extra-files)s + # Replaces MANIFEST.in sdist_extra = include THANKS HACKING @@ -130,22 +136,33 @@ self.addCleanup(setattr, sys, 'stderr', sys.stderr) self.addCleanup(os.chdir, os.getcwd()) - def test_config(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) - self.write_file('setup.cfg', SETUP_CFG) - self.write_file('README', 'yeah') + def write_setup(self, kwargs=None): + opts = {'description-file': 'README', 'extra-files':''} + if kwargs: + opts.update(kwargs) + self.write_file('setup.cfg', SETUP_CFG % opts) - # try to load the metadata now + + def run_setup(self, *args): + # run setup with args sys.stdout = StringIO() - sys.argv[:] = ['setup.py', '--version'] + sys.argv[:] = [''] + list(args) old_sys = sys.argv[:] - try: from distutils2.run import commands_main dist = commands_main() finally: sys.argv[:] = old_sys + return dist + + def test_config(self): + tempdir = self.mkdtemp() + os.chdir(tempdir) + self.write_setup() + self.write_file('README', 'yeah') + + # try to load the metadata now + dist = self.run_setup('--version') # sanity check self.assertEqual(sys.stdout.getvalue(), '0.6.4.dev1' + os.linesep) @@ -184,7 +201,6 @@ 'http://bitbucket.org/Merwok/sample-distutils2-project')] self.assertEqual(dist.metadata['Project-Url'], urls) - self.assertEqual(dist.packages, ['one', 'two', 'three']) self.assertEqual(dist.py_modules, ['haven']) self.assertEqual(dist.package_data, {'cheese': 'data/templates/*'}) @@ -192,7 +208,8 @@ [('bitmaps ', ['bm/b1.gif', 'bm/b2.gif']), ('config ', ['cfg/data.cfg']), ('/etc/init.d ', ['init-script'])]) - self.assertEqual(dist.package_dir['two'], 'src') + + self.assertEqual(dist.package_dir, 'src') # Make sure we get the foo command loaded. We use a string comparison # instead of assertIsInstance because the class is not the same when @@ -213,10 +230,94 @@ d = new_compiler(compiler='d') self.assertEqual(d.description, 'D Compiler') + + def test_multiple_description_file(self): + tempdir = self.mkdtemp() + os.chdir(tempdir) + + self.write_setup({'description-file': 'README CHANGES'}) + self.write_file('README', 'yeah') + self.write_file('CHANGES', 'changelog2') + dist = self.run_setup('--version') + self.assertEqual(dist.metadata.requires_files, ['README', 'CHANGES']) + + def test_multiline_description_file(self): + tempdir = self.mkdtemp() + os.chdir(tempdir) + + self.write_setup({'description-file': 'README\n CHANGES'}) + self.write_file('README', 'yeah') + self.write_file('CHANGES', 'changelog') + dist = self.run_setup('--version') + self.assertEqual(dist.metadata['description'], 'yeah\nchangelog') + self.assertEqual(dist.metadata.requires_files, ['README', 'CHANGES']) + + def test_metadata_requires_description_files_missing(self): + tempdir = self.mkdtemp() + os.chdir(tempdir) + self.write_setup({'description-file': 'README\n README2'}) + self.write_file('README', 'yeah') + self.write_file('README2', 'yeah') + self.write_file('haven.py', '#') + self.write_file('script1.py', '#') + os.mkdir('scripts') + self.write_file(os.path.join('scripts', 'find-coconuts'), '#') + os.mkdir('bin') + self.write_file(os.path.join('bin', 'taunt'), '#') + + os.mkdir('src') + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) + os.mkdir(pkg) + self.write_file(os.path.join(pkg, '__init__.py'), '#') + + dist = self.run_setup('--version') + cmd = sdist(dist) + cmd.finalize_options() + cmd.get_file_list() + self.assertRaises(DistutilsFileError, cmd.make_distribution) + + def test_metadata_requires_description_files(self): + tempdir = self.mkdtemp() + os.chdir(tempdir) + self.write_setup({'description-file': 'README\n README2', + 'extra-files':'\n README2'}) + self.write_file('README', 'yeah') + self.write_file('README2', 'yeah') + self.write_file('haven.py', '#') + self.write_file('script1.py', '#') + os.mkdir('scripts') + self.write_file(os.path.join('scripts', 'find-coconuts'), '#') + os.mkdir('bin') + self.write_file(os.path.join('bin', 'taunt'), '#') + + os.mkdir('src') + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) + os.mkdir(pkg) + self.write_file(os.path.join(pkg, '__init__.py'), '#') + + dist = self.run_setup('--description') + self.assertIn('yeah\nyeah\n', sys.stdout.getvalue()) + + cmd = sdist(dist) + cmd.finalize_options() + cmd.get_file_list() + self.assertRaises(DistutilsFileError, cmd.make_distribution) + + self.write_setup({'description-file': 'README\n README2', + 'extra-files': '\n README2\n README'}) + dist = self.run_setup('--description') + cmd = sdist(dist) + cmd.finalize_options() + cmd.get_file_list() + cmd.make_distribution() + self.assertIn('README\nREADME2\n', open('MANIFEST').read()) + def test_sub_commands(self): tempdir = self.mkdtemp() os.chdir(tempdir) - self.write_file('setup.cfg', SETUP_CFG) + self.write_setup() self.write_file('README', 'yeah') self.write_file('haven.py', '#') self.write_file('script1.py', '#') @@ -224,20 +325,15 @@ self.write_file(os.path.join('scripts', 'find-coconuts'), '#') os.mkdir('bin') self.write_file(os.path.join('bin', 'taunt'), '#') + os.mkdir('src') - for pkg in ('one', 'src', 'src2'): + for pkg in ('one', 'two', 'three'): + pkg = os.path.join('src', pkg) os.mkdir(pkg) self.write_file(os.path.join(pkg, '__init__.py'), '#') # try to run the install command to see if foo is called - sys.stdout = sys.stderr = StringIO() - sys.argv[:] = ['', 'install_dist'] - old_sys = sys.argv[:] - try: - from distutils2.run import main - dist = main() - finally: - sys.argv[:] = old_sys + dist = self.run_setup('install_dist') self.assertEqual(dist.foo_was_here, 1) diff --git a/distutils2/tests/test_markers.py b/distutils2/tests/test_markers.py new file mode 100644 --- /dev/null +++ b/distutils2/tests/test_markers.py @@ -0,0 +1,69 @@ +"""Tests for distutils.metadata.""" +import os +import sys +import platform +from StringIO import StringIO + +from distutils2.markers import interpret +from distutils2.tests import run_unittest, unittest +from distutils2.tests.support import LoggingCatcher, WarningsCatcher + + +class MarkersTestCase(LoggingCatcher, WarningsCatcher, + unittest.TestCase): + + def test_interpret(self): + sys_platform = sys.platform + version = sys.version.split()[0] + os_name = os.name + platform_version = platform.version() + platform_machine = platform.machine() + + self.assertTrue(interpret("sys.platform == '%s'" % sys_platform)) + self.assertTrue(interpret( + "sys.platform == '%s' or python_version == '2.4'" % sys_platform)) + self.assertTrue(interpret( + "sys.platform == '%s' and python_full_version == '%s'" % + (sys_platform, version))) + self.assertTrue(interpret("'%s' == sys.platform" % sys_platform)) + self.assertTrue(interpret('os.name == "%s"' % os_name)) + self.assertTrue(interpret( + 'platform.version == "%s" and platform.machine == "%s"' % + (platform_version, platform_machine))) + + # stuff that need to raise a syntax error + ops = ('os.name == os.name', 'os.name == 2', "'2' == '2'", + 'okpjonon', '', 'os.name ==', 'python_version == 2.4') + for op in ops: + self.assertRaises(SyntaxError, interpret, op) + + # combined operations + OP = 'os.name == "%s"' % os_name + AND = ' and ' + OR = ' or ' + self.assertTrue(interpret(OP + AND + OP)) + self.assertTrue(interpret(OP + AND + OP + AND + OP)) + self.assertTrue(interpret(OP + OR + OP)) + self.assertTrue(interpret(OP + OR + OP + OR + OP)) + + # other operators + self.assertTrue(interpret("os.name != 'buuuu'")) + self.assertTrue(interpret("python_version > '1.0'")) + self.assertTrue(interpret("python_version < '5.0'")) + self.assertTrue(interpret("python_version <= '5.0'")) + self.assertTrue(interpret("python_version >= '1.0'")) + self.assertTrue(interpret("'%s' in os.name" % os_name)) + self.assertTrue(interpret("'buuuu' not in os.name")) + self.assertTrue(interpret( + "'buuuu' not in os.name and '%s' in os.name" % os_name)) + + # execution context + self.assertTrue(interpret('python_version == "0.1"', + {'python_version': '0.1'})) + + +def test_suite(): + return unittest.makeSuite(MarkersTestCase) + +if __name__ == '__main__': + run_unittest(test_suite()) diff --git a/distutils2/tests/test_metadata.py b/distutils2/tests/test_metadata.py --- a/distutils2/tests/test_metadata.py +++ b/distutils2/tests/test_metadata.py @@ -1,10 +1,10 @@ -"""Tests for distutils.command.bdist.""" +"""Tests for distutils.metadata.""" import os import sys import platform from StringIO import StringIO -from distutils2.metadata import (DistributionMetadata, _interpret, +from distutils2.metadata import (DistributionMetadata, PKG_INFO_PREFERRED_VERSION) from distutils2.tests import run_unittest, unittest from distutils2.tests.support import LoggingCatcher, WarningsCatcher @@ -46,55 +46,6 @@ self.assertRaises(TypeError, DistributionMetadata, PKG_INFO, mapping=m, fileobj=fp) - def test_interpret(self): - sys_platform = sys.platform - version = sys.version.split()[0] - os_name = os.name - platform_version = platform.version() - platform_machine = platform.machine() - - self.assertTrue(_interpret("sys.platform == '%s'" % sys_platform)) - self.assertTrue(_interpret( - "sys.platform == '%s' or python_version == '2.4'" % sys_platform)) - self.assertTrue(_interpret( - "sys.platform == '%s' and python_full_version == '%s'" % - (sys_platform, version))) - self.assertTrue(_interpret("'%s' == sys.platform" % sys_platform)) - self.assertTrue(_interpret('os.name == "%s"' % os_name)) - self.assertTrue(_interpret( - 'platform.version == "%s" and platform.machine == "%s"' % - (platform_version, platform_machine))) - - # stuff that need to raise a syntax error - ops = ('os.name == os.name', 'os.name == 2', "'2' == '2'", - 'okpjonon', '', 'os.name ==', 'python_version == 2.4') - for op in ops: - self.assertRaises(SyntaxError, _interpret, op) - - # combined operations - OP = 'os.name == "%s"' % os_name - AND = ' and ' - OR = ' or ' - self.assertTrue(_interpret(OP + AND + OP)) - self.assertTrue(_interpret(OP + AND + OP + AND + OP)) - self.assertTrue(_interpret(OP + OR + OP)) - self.assertTrue(_interpret(OP + OR + OP + OR + OP)) - - # other operators - self.assertTrue(_interpret("os.name != 'buuuu'")) - self.assertTrue(_interpret("python_version > '1.0'")) - self.assertTrue(_interpret("python_version < '5.0'")) - self.assertTrue(_interpret("python_version <= '5.0'")) - self.assertTrue(_interpret("python_version >= '1.0'")) - self.assertTrue(_interpret("'%s' in os.name" % os_name)) - self.assertTrue(_interpret("'buuuu' not in os.name")) - self.assertTrue(_interpret( - "'buuuu' not in os.name and '%s' in os.name" % os_name)) - - # execution context - self.assertTrue(_interpret('python_version == "0.1"', - {'python_version': '0.1'})) - def test_metadata_read_write(self): PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO') metadata = DistributionMetadata(PKG_INFO) diff --git a/distutils2/util.py b/distutils2/util.py --- a/distutils2/util.py +++ b/distutils2/util.py @@ -15,6 +15,7 @@ from copy import copy from fnmatch import fnmatchcase from ConfigParser import RawConfigParser +from inspect import getsource from distutils2.errors import (DistutilsPlatformError, DistutilsFileError, DistutilsByteCompileError, DistutilsExecError) @@ -1050,3 +1051,117 @@ """ Issues a call to util.run_2to3. """ return run_2to3(files, doctests_only, self.fixer_names, self.options, self.explicit) + + +def generate_distutils_kwargs_from_setup_cfg(file='setup.cfg'): + """ Distutils2 to distutils1 compatibility util. + + This method uses an existing setup.cfg to generate a dictionnary of + keywords that can be used by distutils.core.setup(kwargs**). + + :param file: + The setup.cfg path. + :raises DistutilsFileError: + When the setup.cfg file is not found. + + """ + # We need to declare the following constants here so that it's easier to + # generate the setup.py afterwards, using inspect.getsource. + D1_D2_SETUP_ARGS = { + # D1 name : (D2_section, D2_name) + "name" : ("metadata",), + "version" : ("metadata",), + "author" : ("metadata",), + "author_email" : ("metadata",), + "maintainer" : ("metadata",), + "maintainer_email" : ("metadata",), + "url" : ("metadata", "home_page"), + "description" : ("metadata", "summary"), + "long_description" : ("metadata", "description"), + "download-url" : ("metadata",), + "classifiers" : ("metadata", "classifier"), + "platforms" : ("metadata", "platform"), # Needs testing + "license" : ("metadata",), + "requires" : ("metadata", "requires_dist"), + "provides" : ("metadata", "provides_dist"), # Needs testing + "obsoletes" : ("metadata", "obsoletes_dist"), # Needs testing + + "packages" : ("files",), + "scripts" : ("files",), + "py_modules" : ("files", "modules"), # Needs testing + } + + MULTI_FIELDS = ("classifiers", + "requires", + "platforms", + "packages", + "scripts") + + def has_get_option(config, section, option): + if config.has_option(section, option): + return config.get(section, option) + elif config.has_option(section, option.replace('_', '-')): + return config.get(section, option.replace('_', '-')) + else: + return False + + # The method source code really starts here. + config = RawConfigParser() + if not os.path.exists(file): + raise DistutilsFileError("file '%s' does not exist" % + os.path.abspath(file)) + config.read(file) + + kwargs = {} + for arg in D1_D2_SETUP_ARGS: + if len(D1_D2_SETUP_ARGS[arg]) == 2: + # The distutils field name is different than distutils2's. + section, option = D1_D2_SETUP_ARGS[arg] + + elif len(D1_D2_SETUP_ARGS[arg]) == 1: + # The distutils field name is the same thant distutils2's. + section = D1_D2_SETUP_ARGS[arg][0] + option = arg + + in_cfg_value = has_get_option(config, section, option) + if not in_cfg_value: + # There is no such option in the setup.cfg + if arg == "long_description": + filename = has_get_option(config, section, "description_file") + print "We have a filename", filename + if filename: + in_cfg_value = open(filename).read() + else: + continue + + if arg in MULTI_FIELDS: + # Special behaviour when we have a multi line option + if "\n" in in_cfg_value: + in_cfg_value = in_cfg_value.strip().split('\n') + else: + in_cfg_value = list((in_cfg_value,)) + + kwargs[arg] = in_cfg_value + + return kwargs + + +def generate_distutils_setup_py(): + """ Generate a distutils compatible setup.py using an existing setup.cfg. + + :raises DistutilsFileError: + When a setup.py already exists. + """ + if os.path.exists("setup.py"): + raise DistutilsFileError("A pre existing setup.py file exists") + + handle = open("setup.py", "w") + handle.write("# Distutils script using distutils2 setup.cfg to call the\n") + handle.write("# distutils.core.setup() with the right args.\n\n\n") + handle.write("import os\n") + handle.write("from distutils.core import setup\n") + handle.write("from ConfigParser import RawConfigParser\n\n") + handle.write(getsource(generate_distutils_kwargs_from_setup_cfg)) + handle.write("\n\nkwargs = generate_distutils_kwargs_from_setup_cfg()\n") + handle.write("setup(**kwargs)") + handle.close() diff --git a/docs/source/distutils/apiref.rst b/docs/source/distutils/apiref.rst --- a/docs/source/distutils/apiref.rst +++ b/docs/source/distutils/apiref.rst @@ -1055,6 +1055,13 @@ Create a file called *filename* and write *contents* (a sequence of strings without line terminators) to it. +:mod:`distutils2.metadata` --- Metadata handling +================================================================ + +.. module:: distutils2.metadata + +.. autoclass:: distutils2.metadata.DistributionMetadata + :members: :mod:`distutils2.util` --- Miscellaneous other utility functions ================================================================ diff --git a/docs/source/distutils/examples.rst b/docs/source/distutils/examples.rst --- a/docs/source/distutils/examples.rst +++ b/docs/source/distutils/examples.rst @@ -301,7 +301,7 @@ :class:`distutils2.dist.DistributionMetadata` class and its :func:`read_pkg_file` method:: - >>> from distutils2.dist import DistributionMetadata + >>> from distutils2.metadata import DistributionMetadata >>> metadata = DistributionMetadata() >>> metadata.read_pkg_file(open('distribute-0.6.8-py2.7.egg-info')) >>> metadata.name diff --git a/docs/source/library/distutils2.metadata.rst b/docs/source/library/distutils2.metadata.rst --- a/docs/source/library/distutils2.metadata.rst +++ b/docs/source/library/distutils2.metadata.rst @@ -2,7 +2,9 @@ Metadata ======== -Distutils2 provides a :class:`DistributionMetadata` class that can read and +.. module:: distutils2.metadata + +Distutils2 provides a :class:`~distutils2.metadata.DistributionMetadata` class that can read and write metadata files. This class is compatible with all metadata versions: * 1.0: :PEP:`241` @@ -17,7 +19,7 @@ Reading metadata ================ -The :class:`DistributionMetadata` class can be instantiated with the path of +The :class:`~distutils2.metadata.DistributionMetadata` class can be instantiated with the path of the metadata file, and provides a dict-like interface to the values:: >>> from distutils2.metadata import DistributionMetadata @@ -33,7 +35,7 @@ The fields that supports environment markers can be automatically ignored if the object is instantiated using the ``platform_dependent`` option. -:class:`DistributionMetadata` will interpret in the case the markers and will +:class:`~distutils2.metadata.DistributionMetadata` will interpret in the case the markers and will automatically remove the fields that are not compliant with the running environment. Here's an example under Mac OS X. The win32 dependency we saw earlier is ignored:: diff --git a/docs/source/setupcfg.rst b/docs/source/setupcfg.rst --- a/docs/source/setupcfg.rst +++ b/docs/source/setupcfg.rst @@ -128,6 +128,8 @@ This section describes the files included in the project. +- **packages_root**: the root directory containing all packages. If not provided + Distutils2 will use the current directory. *\*optional* - **packages**: a list of packages the project includes *\*optional* *\*multi* - **modules**: a list of packages the project includes *\*optional* *\*multi* - **scripts**: a list of scripts the project includes *\*optional* *\*multi* @@ -136,6 +138,7 @@ Example:: [files] + packages_root = src packages = pypi2rpm pypi2rpm.command diff --git a/setup.py b/setup.py --- a/setup.py +++ b/setup.py @@ -7,11 +7,15 @@ from distutils2 import __version__ as VERSION from distutils2.util import find_packages from distutils import log -from distutils.core import setup, Extension from distutils.ccompiler import new_compiler from distutils.command.sdist import sdist from distutils.command.install import install +try: + from setuptools import setup, Extension +except ImportError: + from distutils.core import setup, Extension + f = open('README.txt') try: README = f.read() -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Fix attribute error Message-ID: tarek.ziade pushed dd51d4c1fe22 to distutils2: http://hg.python.org/distutils2/rev/dd51d4c1fe22 changeset: 930:dd51d4c1fe22 user: ?ric Araujo date: Thu Dec 09 03:35:18 2010 +0100 summary: Fix attribute error files: distutils2/command/cmd.py diff --git a/distutils2/command/cmd.py b/distutils2/command/cmd.py --- a/distutils2/command/cmd.py +++ b/distutils2/command/cmd.py @@ -165,7 +165,10 @@ header = "command options for '%s':" % self.get_command_name() self.announce(indent + header, level=log.INFO) indent = indent + " " + negative_opt = getattr(self, 'negative_opt', ()) for (option, _, _) in self.user_options: + if option in negative_opt: + continue option = option.replace('-', '_') if option[-1] == "=": option = option[:-1] -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Fix syntax in code blocks that were not colorized Message-ID: tarek.ziade pushed f9925b0b6c7f to distutils2: http://hg.python.org/distutils2/rev/f9925b0b6c7f changeset: 931:f9925b0b6c7f user: ?ric Araujo date: Sun Oct 31 11:48:42 2010 +0100 summary: Fix syntax in code blocks that were not colorized files: docs/source/library/distutils2.tests.pypi_server.rst diff --git a/docs/source/library/distutils2.tests.pypi_server.rst b/docs/source/library/distutils2.tests.pypi_server.rst --- a/docs/source/library/distutils2.tests.pypi_server.rst +++ b/docs/source/library/distutils2.tests.pypi_server.rst @@ -77,6 +77,7 @@ @use_pypi_server() def test_somthing(self, server): # your tests goes here + ... The decorator will instantiate the server for you, and run and stop it just before and after your method call. You also can pass the server initializer, @@ -85,4 +86,4 @@ class SampleTestCase(TestCase): @use_pypi_server("test_case_name") def test_something(self, server): - # something + ... -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Add documentation for useful pkgutil functions and classes (#7303). Message-ID: tarek.ziade pushed 9349f038ba41 to distutils2: http://hg.python.org/distutils2/rev/9349f038ba41 changeset: 932:9349f038ba41 user: ?ric Araujo date: Sun Oct 31 12:26:44 2010 +0100 summary: Add documentation for useful pkgutil functions and classes (#7303). This is a backport from Python 3.2 with some additions (edits to the introduction and structure of the file). files: docs/source/library/pkgutil.rst diff --git a/docs/source/library/pkgutil.rst b/docs/source/library/pkgutil.rst --- a/docs/source/library/pkgutil.rst +++ b/docs/source/library/pkgutil.rst @@ -4,77 +4,204 @@ .. module:: pkgutil :synopsis: Utilities to support packages. -.. TODO Follow the reST conventions used in the stdlib +This module provides utilities to manipulate packages: support for the +Importer protocol defined in :PEP:`302` and implementation of the API +described in :PEP:`376` to work with the database of installed Python +distributions. -This module provides functions to manipulate packages, as well as -the necessary functions to provide support for the "Importer Protocol" as -described in :PEP:`302` and for working with the database of installed Python -distributions which is specified in :PEP:`376`. In addition to the functions -required in :PEP:`376`, back support for older ``.egg`` and ``.egg-info`` -distributions is provided as well. These distributions are represented by the -class :class:`~distutils2._backport.pkgutil.EggInfoDistribution` and most -functions provide an extra argument ``use_egg_info`` which indicates if -they should consider these old styled distributions. This document details -first the functions and classes available and then presents several use cases. - +Import system utilities +----------------------- .. function:: extend_path(path, name) - Extend the search path for the modules which comprise a package. Intended use is - to place the following code in a package's :file:`__init__.py`:: + Extend the search path for the modules which comprise a package. Intended + use is to place the following code in a package's :file:`__init__.py`:: from pkgutil import extend_path __path__ = extend_path(__path__, __name__) - This will add to the package's ``__path__`` all subdirectories of directories on - ``sys.path`` named after the package. This is useful if one wants to distribute - different parts of a single logical package as multiple directories. + This will add to the package's ``__path__`` all subdirectories of directories + on :data:`sys.path` named after the package. This is useful if one wants to + distribute different parts of a single logical package as multiple + directories. - It also looks for :file:`\*.pkg` files beginning where ``*`` matches the *name* - argument. This feature is similar to :file:`\*.pth` files (see the :mod:`site` - module for more information), except that it doesn't special-case lines starting - with ``import``. A :file:`\*.pkg` file is trusted at face value: apart from - checking for duplicates, all entries found in a :file:`\*.pkg` file are added to - the path, regardless of whether they exist on the filesystem. (This is a - feature.) + It also looks for :file:`\*.pkg` files beginning where ``*`` matches the + *name* argument. This feature is similar to :file:`\*.pth` files (see the + :mod:`site` module for more information), except that it doesn't special-case + lines starting with ``import``. A :file:`\*.pkg` file is trusted at face + value: apart from checking for duplicates, all entries found in a + :file:`\*.pkg` file are added to the path, regardless of whether they exist + on the filesystem. (This is a feature.) If the input path is not a list (as is the case for frozen packages) it is returned unchanged. The input path is not modified; an extended copy is returned. Items are only appended to the copy at the end. - It is assumed that ``sys.path`` is a sequence. Items of ``sys.path`` that are - not strings referring to existing directories are ignored. Unicode items on - ``sys.path`` that cause errors when used as filenames may cause this function - to raise an exception (in line with :func:`os.path.isdir` behavior). + It is assumed that :data:`sys.path` is a sequence. Items of :data:`sys.path` + that are not strings referring to existing directories are ignored. Unicode + items on :data:`sys.path` that cause errors when used as filenames may cause + this function to raise an exception (in line with :func:`os.path.isdir` + behavior). + + +.. class:: ImpImporter(dirname=None) + + :pep:`302` Importer that wraps Python's "classic" import algorithm. + + If *dirname* is a string, a :pep:`302` importer is created that searches that + directory. If *dirname* is ``None``, a :pep:`302` importer is created that + searches the current :data:`sys.path`, plus any modules that are frozen or + built-in. + + Note that :class:`ImpImporter` does not currently support being used by + placement on :data:`sys.meta_path`. + + +.. class:: ImpLoader(fullname, file, filename, etc) + + :pep:`302` Loader that wraps Python's "classic" import algorithm. + + +.. function:: find_loader(fullname) + + Find a :pep:`302` "loader" object for *fullname*. + + If *fullname* contains dots, path must be the containing package's + ``__path__``. Returns ``None`` if the module cannot be found or imported. + This function uses :func:`iter_importers`, and is thus subject to the same + limitations regarding platform-specific special import locations such as the + Windows registry. + + +.. function:: get_importer(path_item) + + Retrieve a :pep:`302` importer for the given *path_item*. + + The returned importer is cached in :data:`sys.path_importer_cache` if it was + newly created by a path hook. + + If there is no importer, a wrapper around the basic import machinery is + returned. This wrapper is never inserted into the importer cache (None is + inserted instead). + + The cache (or part of it) can be cleared manually if a rescan of + :data:`sys.path_hooks` is necessary. + + +.. function:: get_loader(module_or_name) + + Get a :pep:`302` "loader" object for *module_or_name*. + + If the module or package is accessible via the normal import mechanism, a + wrapper around the relevant part of that machinery is returned. Returns + ``None`` if the module cannot be found or imported. If the named module is + not already imported, its containing package (if any) is imported, in order + to establish the package ``__path__``. + + This function uses :func:`iter_importers`, and is thus subject to the same + limitations regarding platform-specific special import locations such as the + Windows registry. + + +.. function:: iter_importers(fullname='') + + Yield :pep:`302` importers for the given module name. + + If fullname contains a '.', the importers will be for the package containing + fullname, otherwise they will be importers for :data:`sys.meta_path`, + :data:`sys.path`, and Python's "classic" import machinery, in that order. If + the named module is in a package, that package is imported as a side effect + of invoking this function. + + Non-:pep:`302` mechanisms (e.g. the Windows registry) used by the standard + import machinery to find files in alternative locations are partially + supported, but are searched *after* :data:`sys.path`. Normally, these + locations are searched *before* :data:`sys.path`, preventing :data:`sys.path` + entries from shadowing them. + + For this to cause a visible difference in behaviour, there must be a module + or package name that is accessible via both :data:`sys.path` and one of the + non-:pep:`302` file system mechanisms. In this case, the emulation will find + the former version, while the builtin import mechanism will find the latter. + + Items of the following types can be affected by this discrepancy: + ``imp.C_EXTENSION``, ``imp.PY_SOURCE``, ``imp.PY_COMPILED``, + ``imp.PKG_DIRECTORY``. + + +.. function:: iter_modules(path=None, prefix='') + + Yields ``(module_loader, name, ispkg)`` for all submodules on *path*, or, if + path is ``None``, all top-level modules on :data:`sys.path`. + + *path* should be either ``None`` or a list of paths to look for modules in. + + *prefix* is a string to output on the front of every module name on output. + + +.. function:: walk_packages(path=None, prefix='', onerror=None) + + Yields ``(module_loader, name, ispkg)`` for all modules recursively on + *path*, or, if path is ``None``, all accessible modules. + + *path* should be either ``None`` or a list of paths to look for modules in. + + *prefix* is a string to output on the front of every module name on output. + + Note that this function must import all *packages* (*not* all modules!) on + the given *path*, in order to access the ``__path__`` attribute to find + submodules. + + *onerror* is a function which gets called with one argument (the name of the + package which was being imported) if any exception occurs while trying to + import a package. If no *onerror* function is supplied, :exc:`ImportError`\s + are caught and ignored, while all other exceptions are propagated, + terminating the search. + + Examples:: + + # list all modules python can access + walk_packages() + + # list all submodules of ctypes + walk_packages(ctypes.__path__, ctypes.__name__ + '.') + .. function:: get_data(package, resource) Get a resource from a package. - This is a wrapper for the :pep:`302` loader :func:`get_data` API. The package - argument should be the name of a package, in standard module format - (foo.bar). The resource argument should be in the form of a relative - filename, using ``/`` as the path separator. The parent directory name + This is a wrapper for the :pep:`302` loader :func:`get_data` API. The + *package* argument should be the name of a package, in standard module format + (``foo.bar``). The *resource* argument should be in the form of a relative + filename, using ``/`` as the path separator. The parent directory name ``..`` is not allowed, and nor is a rooted name (starting with a ``/``). - The function returns a binary string that is the contents of the - specified resource. + The function returns a binary string that is the contents of the specified + resource. For packages located in the filesystem, which have already been imported, this is the rough equivalent of:: - d = os.path.dirname(sys.modules[package].__file__) - data = open(os.path.join(d, resource), 'rb').read() + d = os.path.dirname(sys.modules[package].__file__) + data = open(os.path.join(d, resource), 'rb').read() If the package cannot be located or loaded, or it uses a :pep:`302` loader - which does not support :func:`get_data`, then None is returned. + which does not support :func:`get_data`, then ``None`` is returned. -API Reference -============= +Installed distributions database +-------------------------------- -.. automodule:: distutils2._backport.pkgutil - :members: +Installed Python distributions are represented by instances of +:class:`~distutils2._backport.pkgutil.Distribution`, or its subclass +:class:`~distutils2._backport.pkgutil.EggInfoDistribution` for legacy ``.egg`` +and ``.egg-info`` formats). Most functions also provide an extra argument +``use_egg_info`` to take legacy distributions into account. + +.. TODO write docs here, don't rely on automodule + classes: Distribution and descendents + functions: provides, obsoletes, replaces, etc. Caching +++++++ @@ -86,11 +213,10 @@ :func:`~distutils2._backport.pkgutil.clear_cache`. +Examples +-------- -Example Usage -============= - -Print All Information About a Distribution +Print all information about a distribution ++++++++++++++++++++++++++++++++++++++++++ Given a path to a ``.dist-info`` distribution, we shall print out all @@ -182,7 +308,7 @@ ===== * It was installed as a dependency -Find Out Obsoleted Distributions +Find out obsoleted distributions ++++++++++++++++++++++++++++++++ Now, we take tackle a different problem, we are interested in finding out -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Fix wrong name (thanks pyflakes) Message-ID: tarek.ziade pushed cba732cdef62 to distutils2: http://hg.python.org/distutils2/rev/cba732cdef62 changeset: 933:cba732cdef62 user: ?ric Araujo date: Sun Oct 31 15:25:59 2010 +0100 summary: Fix wrong name (thanks pyflakes) files: distutils2/_backport/pkgutil.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -650,7 +650,7 @@ def clear_cache(): """ Clears the internal cache. """ - global _cache_name, _cache_name_egg, cache_path, _cache_path_egg, \ + global _cache_name, _cache_name_egg, _cache_path, _cache_path_egg, \ _cache_generated, _cache_generated_egg _cache_name = {} -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Clean up imports in pkgutil Message-ID: tarek.ziade pushed 34158703254b to distutils2: http://hg.python.org/distutils2/rev/34158703254b changeset: 935:34158703254b user: ?ric Araujo date: Sun Oct 31 15:33:42 2010 +0100 summary: Clean up imports in pkgutil files: distutils2/_backport/pkgutil.py distutils2/_backport/tests/test_pkgutil.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -6,19 +6,17 @@ import os import sys import imp -import os.path +import re +import warnings from csv import reader as csv_reader from types import ModuleType from distutils2.errors import DistutilsError from distutils2.metadata import DistributionMetadata from distutils2.version import suggest_normalized_version, VersionPredicate -import zipimport try: import cStringIO as StringIO except ImportError: import StringIO -import re -import warnings __all__ = [ @@ -28,7 +26,7 @@ 'Distribution', 'EggInfoDistribution', 'distinfo_dirname', 'get_distributions', 'get_distribution', 'get_file_users', 'provides_distribution', 'obsoletes_distribution', - 'enable_cache', 'disable_cache', 'clear_cache' + 'enable_cache', 'disable_cache', 'clear_cache', ] @@ -888,6 +886,7 @@ except IOError: requires = None else: + # FIXME handle the case where zipfile is not available zipf = zipimport.zipimporter(path) fileobj = StringIO.StringIO(zipf.get_data('EGG-INFO/PKG-INFO')) self.metadata = DistributionMetadata(fileobj=fileobj) diff --git a/distutils2/_backport/tests/test_pkgutil.py b/distutils2/_backport/tests/test_pkgutil.py --- a/distutils2/_backport/tests/test_pkgutil.py +++ b/distutils2/_backport/tests/test_pkgutil.py @@ -12,10 +12,15 @@ except ImportError: from distutils2._backport.hashlib import md5 -from test.test_support import TESTFN +from distutils2.errors import DistutilsError +from distutils2.metadata import DistributionMetadata from distutils2.tests import unittest, run_unittest from distutils2._backport import pkgutil +from distutils2._backport.pkgutil import ( + Distribution, EggInfoDistribution, get_distribution, get_distributions, + provides_distribution, obsoletes_distribution, get_file_users, + distinfo_dirname, _yield_distributions) try: from os.path import relpath @@ -231,9 +236,6 @@ def test_instantiation(self): # Test the Distribution class's instantiation provides us with usable # attributes. - # Import the Distribution class - from distutils2._backport.pkgutil import distinfo_dirname, Distribution - here = os.path.abspath(os.path.dirname(__file__)) name = 'choxie' version = '2.0.0.9' @@ -242,7 +244,6 @@ dist = Distribution(dist_path) self.assertEqual(dist.name, name) - from distutils2.metadata import DistributionMetadata self.assertTrue(isinstance(dist.metadata, DistributionMetadata)) self.assertEqual(dist.metadata['version'], version) self.assertTrue(isinstance(dist.requested, type(bool()))) @@ -250,7 +251,6 @@ def test_installed_files(self): # Test the iteration of installed files. # Test the distribution's installed files - from distutils2._backport.pkgutil import Distribution for distinfo_dir in self.distinfo_dirs: dist = Distribution(distinfo_dir) for path, md5_, size in dist.get_installed_files(): @@ -273,14 +273,12 @@ false_path = relpath(os.path.join(*false_path), sys.prefix) # Test if the distribution uses the file in question - from distutils2._backport.pkgutil import Distribution dist = Distribution(distinfo_dir) self.assertTrue(dist.uses(true_path)) self.assertFalse(dist.uses(false_path)) def test_get_distinfo_file(self): # Test the retrieval of dist-info file objects. - from distutils2._backport.pkgutil import Distribution distinfo_name = 'choxie-2.0.0.9' other_distinfo_name = 'grammar-1.0a4' distinfo_dir = os.path.join(self.fake_dists_path, @@ -301,7 +299,6 @@ # Is it the correct file? self.assertEqual(value.name, os.path.join(distinfo_dir, distfile)) - from distutils2.errors import DistutilsError # Test an absolute path that is part of another distributions dist-info other_distinfo_file = os.path.join(self.fake_dists_path, other_distinfo_name + '.dist-info', 'REQUESTED') @@ -313,7 +310,6 @@ def test_get_distinfo_files(self): # Test for the iteration of RECORD path entries. - from distutils2._backport.pkgutil import Distribution distinfo_name = 'towel_stuff-0.1' distinfo_dir = os.path.join(self.fake_dists_path, distinfo_name + '.dist-info') @@ -362,7 +358,6 @@ ] # Import the function in question - from distutils2._backport.pkgutil import distinfo_dirname # Loop through the items to validate the results for name, version, standard_dirname in items: @@ -376,11 +371,6 @@ ('towel-stuff', '0.1')] found_dists = [] - # Import the function in question - from distutils2._backport.pkgutil import get_distributions, \ - Distribution, \ - EggInfoDistribution - # Verify the fake dists have been found. dists = [dist for dist in get_distributions()] for dist in dists: @@ -423,11 +413,6 @@ # Test the lookup of the towel-stuff distribution name = 'towel-stuff' # Note: This is different from the directory name - # Import the function in question - from distutils2._backport.pkgutil import get_distribution, \ - Distribution, \ - EggInfoDistribution - # Lookup the distribution dist = get_distribution(name) self.assertTrue(isinstance(dist, Distribution)) @@ -466,7 +451,6 @@ def test_get_file_users(self): # Test the iteration of distributions that use a file. - from distutils2._backport.pkgutil import get_file_users, Distribution name = 'towel_stuff-0.1' path = os.path.join(self.fake_dists_path, name, 'towel_stuff', '__init__.py') @@ -476,9 +460,6 @@ def test_provides(self): # Test for looking up distributions by what they provide - from distutils2._backport.pkgutil import provides_distribution - from distutils2.errors import DistutilsError - checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) l = [dist.name for dist in provides_distribution('truffles')] @@ -548,9 +529,6 @@ def test_obsoletes(self): # Test looking for distributions based on what they obsolete - from distutils2._backport.pkgutil import obsoletes_distribution - from distutils2.errors import DistutilsError - checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) l = [dist.name for dist in obsoletes_distribution('truffles', '1.0')] @@ -580,7 +558,6 @@ def test_yield_distribution(self): # tests the internal function _yield_distributions - from distutils2._backport.pkgutil import _yield_distributions checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) eggs = [('bacon', '0.1'), ('banana', '0.4'), ('strawberry', '0.6'), -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Prevent pydoc failure with zipfile on sys.path (#4005 backport) Message-ID: tarek.ziade pushed 04e872076657 to distutils2: http://hg.python.org/distutils2/rev/04e872076657 changeset: 934:04e872076657 user: ?ric Araujo date: Sun Oct 31 15:28:58 2010 +0100 summary: Prevent pydoc failure with zipfile on sys.path (#4005 backport) files: distutils2/_backport/pkgutil.py distutils2/_backport/tests/test_pkgutil.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -343,8 +343,7 @@ from zipimport import zipimporter def iter_zipimport_modules(importer, prefix=''): - dirlist = zipimport._zip_directory_cache[importer.archive].keys() - dirlist.sort() + dirlist = sorted(zipimport._zip_directory_cache[importer.archive]) _prefix = importer.prefix plen = len(_prefix) yielded = {} diff --git a/distutils2/_backport/tests/test_pkgutil.py b/distutils2/_backport/tests/test_pkgutil.py --- a/distutils2/_backport/tests/test_pkgutil.py +++ b/distutils2/_backport/tests/test_pkgutil.py @@ -108,6 +108,12 @@ self.assertEqual(res1, RESOURCE_DATA) res2 = pkgutil.get_data(pkg, 'sub/res.txt') self.assertEqual(res2, RESOURCE_DATA) + + names = [] + for loader, name, ispkg in pkgutil.iter_modules([zip_file]): + names.append(name) + self.assertEqual(names, ['test_getdata_zipfile']) + del sys.path[0] del sys.modules[pkg] -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Remove unneeded function Message-ID: tarek.ziade pushed cfa01cfd4666 to distutils2: http://hg.python.org/distutils2/rev/cfa01cfd4666 changeset: 936:cfa01cfd4666 user: ?ric Araujo date: Sun Oct 31 15:34:45 2010 +0100 summary: Remove unneeded function files: distutils2/_backport/pkgutil.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -966,12 +966,6 @@ __hash__ = object.__hash__ -def _normalize_dist_name(name): - """Returns a normalized name from the given *name*. - :rtype: string""" - return name.replace('-', '_') - - def distinfo_dirname(name, version): """ The *name* and *version* parameters are converted into their @@ -991,7 +985,7 @@ :returns: directory name :rtype: string""" file_extension = '.dist-info' - name = _normalize_dist_name(name) + name = name.replace('-', '_') normalized_version = suggest_normalized_version(version) # Because this is a lookup procedure, something will be returned even if # it is a version that cannot be normalized -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Touch up some comments, fix pyflakes and pep8 warnings Message-ID: tarek.ziade pushed a31fbfdf3cbb to distutils2: http://hg.python.org/distutils2/rev/a31fbfdf3cbb changeset: 937:a31fbfdf3cbb user: ?ric Araujo date: Sun Oct 31 15:35:43 2010 +0100 summary: Touch up some comments, fix pyflakes and pep8 warnings files: distutils2/_backport/pkgutil.py distutils2/_backport/tests/test_pkgutil.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -1,8 +1,5 @@ """Utilities to support packages.""" -# NOTE: This module must remain compatible with Python 2.3, as it is shared -# by setuptools for distribution with Python 2.3 and up. - import os import sys import imp @@ -30,6 +27,10 @@ ] +########################## +# PEP 302 Implementation # +########################## + def read_code(stream): # This helper is needed in order for the :pep:`302` emulation to # correctly handle compiled files @@ -39,7 +40,7 @@ if magic != imp.get_magic(): return None - stream.read(4) # Skip timestamp + stream.read(4) # Skip timestamp return marshal.load(stream) @@ -171,7 +172,6 @@ #@simplegeneric def iter_importer_modules(importer, prefix=''): - "" if not hasattr(importer, 'iter_modules'): return [] return importer.iter_modules(prefix) @@ -329,9 +329,9 @@ def get_filename(self, fullname=None): fullname = self._fix_name(fullname) mod_type = self.etc[2] - if self.etc[2] == imp.PKG_DIRECTORY: + if mod_type == imp.PKG_DIRECTORY: return self._get_delegate().get_filename() - elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION): + elif mod_type in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION): return self.filename return None @@ -430,7 +430,8 @@ import mechanism will find the latter. Items of the following types can be affected by this discrepancy: - ``imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY`` + :data:`imp.C_EXTENSION`, :data:`imp.PY_SOURCE`, :data:`imp.PY_COMPILED`, + :data:`imp.PKG_DIRECTORY` """ if fullname.startswith('.'): raise ImportError("Relative module names not supported") @@ -532,13 +533,13 @@ # frozen package. Return the path unchanged in that case. return path - pname = os.path.join(*name.split('.')) # Reconstitute as relative path + pname = os.path.join(*name.split('.')) # Reconstitute as relative path # Just in case os.extsep != '.' sname = os.extsep.join(name.split('.')) sname_pkg = sname + os.extsep + "pkg" init_py = "__init__" + os.extsep + "py" - path = path[:] # Start with a copy of the existing path + path = path[:] # Start with a copy of the existing path for dir in sys.path: if not isinstance(dir, basestring) or not os.path.isdir(dir): @@ -563,7 +564,7 @@ line = line.rstrip('\n') if not line or line.startswith('#'): continue - path.append(line) # Don't check for existence! + path.append(line) # Don't check for existence! f.close() return path @@ -607,6 +608,7 @@ resource_name = os.path.join(*parts) return loader.get_data(resource_name) + ########################## # PEP 376 Implementation # ########################## @@ -614,12 +616,12 @@ DIST_FILES = ('INSTALLER', 'METADATA', 'RECORD', 'REQUESTED',) # Cache -_cache_name = {} # maps names to Distribution instances -_cache_name_egg = {} # maps names to EggInfoDistribution instances -_cache_path = {} # maps paths to Distribution instances -_cache_path_egg = {} # maps paths to EggInfoDistribution instances -_cache_generated = False # indicates if .dist-info distributions are cached -_cache_generated_egg = False # indicates if .dist-info and .egg are cached +_cache_name = {} # maps names to Distribution instances +_cache_name_egg = {} # maps names to EggInfoDistribution instances +_cache_path = {} # maps paths to Distribution instances +_cache_path_egg = {} # maps paths to EggInfoDistribution instances +_cache_generated = False # indicates if .dist-info distributions are cached +_cache_generated_egg = False # indicates if .dist-info and .egg are cached _cache_enabled = True @@ -634,6 +636,7 @@ _cache_enabled = True + def disable_cache(): """ Disables the internal cache. @@ -645,6 +648,7 @@ _cache_enabled = False + def clear_cache(): """ Clears the internal cache. """ global _cache_name, _cache_name_egg, _cache_path, _cache_path_egg, \ @@ -868,7 +872,8 @@ if isinstance(strs, basestring): for s in strs.splitlines(): s = s.strip() - if s and not s.startswith('#'): # skip blank lines/comments + # skip blank lines/comments + if s and not s.startswith('#'): yield s else: for ss in strs: @@ -939,7 +944,7 @@ version = match.group('first') if match.group('rest'): version += match.group('rest') - version = version.replace(' ', '') # trim spaces + version = version.replace(' ', '') # trim spaces if version is None: reqs.append(name) else: @@ -1126,7 +1131,7 @@ raise DistutilsError(('Distribution %s has invalid ' + 'provides field: %s') \ % (dist.name, p)) - p_ver = p_ver[1:-1] # trim off the parenthesis + p_ver = p_ver[1:-1] # trim off the parenthesis if p_name == name and predicate.match(p_ver): yield dist break diff --git a/distutils2/_backport/tests/test_pkgutil.py b/distutils2/_backport/tests/test_pkgutil.py --- a/distutils2/_backport/tests/test_pkgutil.py +++ b/distutils2/_backport/tests/test_pkgutil.py @@ -216,7 +216,7 @@ record_writer.writerow(record_pieces( os.path.join(distinfo_dir, file))) record_writer.writerow([relpath(record_file, sys.prefix)]) - del record_writer # causes the RECORD file to close + del record_writer # causes the RECORD file to close record_reader = csv.reader(open(record_file, 'rb')) record_data = [] for row in record_reader: @@ -346,7 +346,7 @@ # Given a name and a version, we expect the distinfo_dirname function # to return a standard distribution information directory name. - items = [# (name, version, standard_dirname) + items = [ # (name, version, standard_dirname) # Test for a very simple single word name and decimal # version number ('docutils', '0.5', 'docutils-0.5.dist-info'), @@ -411,7 +411,7 @@ def test_get_distribution(self): # Test for looking up a distribution by name. # Test the lookup of the towel-stuff distribution - name = 'towel-stuff' # Note: This is different from the directory name + name = 'towel-stuff' # Note: This is different from the directory name # Lookup the distribution dist = get_distribution(name) @@ -508,12 +508,10 @@ use_egg_info=True)] checkLists(l, ['strawberry']) - l = [dist.name for dist in provides_distribution('strawberry', '>0.6', use_egg_info=True)] checkLists(l, []) - l = [dist.name for dist in provides_distribution('banana', '0.4', use_egg_info=True)] checkLists(l, ['banana']) @@ -522,7 +520,6 @@ use_egg_info=True)] checkLists(l, ['banana']) - l = [dist.name for dist in provides_distribution('banana', '!=0.4', use_egg_info=True)] checkLists(l, []) @@ -538,7 +535,6 @@ use_egg_info=True)] checkLists(l, ['cheese', 'bacon']) - l = [dist.name for dist in obsoletes_distribution('truffles', '0.8')] checkLists(l, ['choxie']) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Fix one bug and one warning found by pyflakes. Will backport to stdlib. Message-ID: tarek.ziade pushed 49443233cf92 to distutils2: http://hg.python.org/distutils2/rev/49443233cf92 changeset: 939:49443233cf92 user: ?ric Araujo date: Mon Nov 01 15:24:07 2010 +0100 summary: Fix one bug and one warning found by pyflakes. Will backport to stdlib. files: distutils2/_backport/shutil.py distutils2/_backport/tests/test_shutil.py diff --git a/distutils2/_backport/shutil.py b/distutils2/_backport/shutil.py --- a/distutils2/_backport/shutil.py +++ b/distutils2/_backport/shutil.py @@ -285,7 +285,7 @@ else: try: os.remove(fullname) - except os.error, err: + except os.error: onerror(os.remove, fullname, sys.exc_info()) try: os.rmdir(path) diff --git a/distutils2/_backport/tests/test_shutil.py b/distutils2/_backport/tests/test_shutil.py --- a/distutils2/_backport/tests/test_shutil.py +++ b/distutils2/_backport/tests/test_shutil.py @@ -518,6 +518,7 @@ # check if the compressed tarball was created tarball = base_name + '.zip' + self.assertTrue(os.path.exists(tarball)) def test_make_archive(self): -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Synchronize shutil with latest py3k version (with tests). Message-ID: tarek.ziade pushed f8c85eb52c98 to distutils2: http://hg.python.org/distutils2/rev/f8c85eb52c98 changeset: 938:f8c85eb52c98 user: ?ric Araujo date: Mon Nov 01 15:17:00 2010 +0100 summary: Synchronize shutil with latest py3k version (with tests). The code has been adapted to be compatible with 2.4 and the tests have been copied from the standard library. Some tests are skipped because the code does not use the with statement. files: distutils2/_backport/shutil.py distutils2/_backport/tests/test_shutil.py diff --git a/distutils2/_backport/shutil.py b/distutils2/_backport/shutil.py --- a/distutils2/_backport/shutil.py +++ b/distutils2/_backport/shutil.py @@ -1,4 +1,4 @@ -"""Utility functions for copying files and directory trees. +"""Utility functions for copying and archiving files and directory trees. XXX The functions here don't copy the resource fork or other metadata on Mac. @@ -9,7 +9,13 @@ import stat from os.path import abspath import fnmatch -from warnings import warn +import errno + +try: + import bz2 + _BZ2_SUPPORTED = True +except ImportError: + _BZ2_SUPPORTED = False try: from pwd import getpwnam @@ -21,9 +27,12 @@ except ImportError: getgrnam = None -__all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2", - "copytree","move","rmtree","Error", "SpecialFileError", - "ExecError","make_archive"] +__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", + "copytree", "move", "rmtree", "Error", "SpecialFileError", + "ExecError", "make_archive", "get_archive_formats", + "register_archive_format", "unregister_archive_format", + "get_unpack_formats", "register_unpack_format", + "unregister_unpack_format", "unpack_archive"] class Error(EnvironmentError): pass @@ -35,6 +44,14 @@ class ExecError(EnvironmentError): """Raised when a command could not be executed""" +class ReadError(EnvironmentError): + """Raised when an archive cannot be read""" + +class RegistryError(Exception): + """Raised when a registery operation with the archiving + and unpacking registeries fails""" + + try: WindowsError except NameError: @@ -50,7 +67,7 @@ def _samefile(src, dst): # Macintosh, Unix. - if hasattr(os.path,'samefile'): + if hasattr(os.path, 'samefile'): try: return os.path.samefile(src, dst) except OSError: @@ -63,10 +80,8 @@ def copyfile(src, dst): """Copy data from src to dst""" if _samefile(src, dst): - raise Error, "`%s` and `%s` are the same file" % (src, dst) + raise Error("`%s` and `%s` are the same file" % (src, dst)) - fsrc = None - fdst = None for fn in [src, dst]: try: st = os.stat(fn) @@ -77,15 +92,16 @@ # XXX What about other special files? (sockets, devices...) if stat.S_ISFIFO(st.st_mode): raise SpecialFileError("`%s` is a named pipe" % fn) + + fsrc = open(src, 'rb') try: - fsrc = open(src, 'rb') fdst = open(dst, 'wb') - copyfileobj(fsrc, fdst) + try: + copyfileobj(fsrc, fdst) + finally: + fdst.close() finally: - if fdst: - fdst.close() - if fsrc: - fsrc.close() + fsrc.close() def copymode(src, dst): """Copy mode bits from src to dst""" @@ -103,8 +119,12 @@ if hasattr(os, 'chmod'): os.chmod(dst, mode) if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): - os.chflags(dst, st.st_flags) - + try: + os.chflags(dst, st.st_flags) + except OSError, why: + if (not hasattr(errno, 'EOPNOTSUPP') or + why.errno != errno.EOPNOTSUPP): + raise def copy(src, dst): """Copy data and mode bits ("cp src dst"). @@ -140,8 +160,9 @@ return set(ignored_names) return _ignore_patterns -def copytree(src, dst, symlinks=False, ignore=None): - """Recursively copy a directory tree using copy2(). +def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, + ignore_dangling_symlinks=False): + """Recursively copy a directory tree. The destination directory must not already exist. If exception(s) occur, an Error is raised with a list of reasons. @@ -149,7 +170,13 @@ If the optional symlinks flag is true, symbolic links in the source tree result in symbolic links in the destination tree; if it is false, the contents of the files pointed to by symbolic - links are copied. + links are copied. If the file pointed by the symlink doesn't + exist, an exception will be added in the list of errors raised in + an Error exception at the end of the copy process. + + You can set the optional ignore_dangling_symlinks flag to true if you + want to silence this exception. Notice that this has no effect on + platforms that don't support os.symlink. The optional ignore argument is a callable. If given, it is called with the `src` parameter, which is the directory @@ -163,7 +190,10 @@ list of names relative to the `src` directory that should not be copied. - XXX Consider this example code rather than the ultimate tool. + The optional copy_function argument is a callable that will be used + to copy each file. It will be called with the source path and the + destination path as arguments. By default, copy2() is used, but any + function that supports the same signature (like copy()) can be used. """ names = os.listdir(src) @@ -182,14 +212,21 @@ srcname = os.path.join(src, name) dstname = os.path.join(dst, name) try: - if symlinks and os.path.islink(srcname): + if os.path.islink(srcname): linkto = os.readlink(srcname) - os.symlink(linkto, dstname) + if symlinks: + os.symlink(linkto, dstname) + else: + # ignore dangling symlink if the flag is on + if not os.path.exists(linkto) and ignore_dangling_symlinks: + continue + # otherwise let the copy occurs. copy2 will raise an error + copy_function(srcname, dstname) elif os.path.isdir(srcname): - copytree(srcname, dstname, symlinks, ignore) + copytree(srcname, dstname, symlinks, ignore, copy_function) else: # Will raise a SpecialFileError for unsupported file types - copy2(srcname, dstname) + copy_function(srcname, dstname) # catch the Error from the recursive copytree so that we can # continue with other files except Error, err: @@ -205,7 +242,7 @@ else: errors.extend((src, dst, str(why))) if errors: - raise Error, errors + raise Error(errors) def rmtree(path, ignore_errors=False, onerror=None): """Recursively delete a directory tree. @@ -282,13 +319,13 @@ if os.path.isdir(dst): real_dst = os.path.join(dst, _basename(src)) if os.path.exists(real_dst): - raise Error, "Destination path '%s' already exists" % real_dst + raise Error("Destination path '%s' already exists" % real_dst) try: os.rename(src, real_dst) except OSError: if os.path.isdir(src): if _destinsrc(src, dst): - raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst) + raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) copytree(src, real_dst, symlinks=True) rmtree(src) else: @@ -333,40 +370,41 @@ """Create a (possibly compressed) tar file from all the files under 'base_dir'. - 'compress' must be "gzip" (the default), "compress", "bzip2", or None. - (compress will be deprecated in Python 3.2) + 'compress' must be "gzip" (the default), "bzip2", or None. 'owner' and 'group' can be used to define an owner and a group for the archive that is being built. If not provided, the current owner and group will be used. The output tar file will be named 'base_dir' + ".tar", possibly plus - the appropriate compression extension (".gz", ".bz2" or ".Z"). + the appropriate compression extension (".gz", or ".bz2"). Returns the output filename. """ - tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', None: '', 'compress': ''} - compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'compress': '.Z'} + tar_compression = {'gzip': 'gz', None: ''} + compress_ext = {'gzip': '.gz'} + + if _BZ2_SUPPORTED: + tar_compression['bzip2'] = 'bz2' + compress_ext['bzip2'] = '.bz2' # flags for compression program, each element of list will be an argument if compress is not None and compress not in compress_ext.keys(): - raise ValueError, \ - ("bad value for 'compress': must be None, 'gzip', 'bzip2' " - "or 'compress'") + raise ValueError("bad value for 'compress', or compression format not " + "supported: %s" % compress) - archive_name = base_name + '.tar' - if compress != 'compress': - archive_name += compress_ext.get(compress, '') + archive_name = base_name + '.tar' + compress_ext.get(compress, '') + archive_dir = os.path.dirname(archive_name) - archive_dir = os.path.dirname(archive_name) if not os.path.exists(archive_dir): if logger is not None: - logger.info("creating %s" % archive_dir) + logger.info("creating %s", archive_dir) if not dry_run: os.makedirs(archive_dir) - # creating the tarball + # XXX late import because of circular dependency between shutil and + # tarfile :( from distutils2._backport import tarfile if logger is not None: @@ -391,23 +429,9 @@ finally: tar.close() - # compression using `compress` - # XXX this block will be removed in Python 3.2 - if compress == 'compress': - warn("'compress' will be deprecated.", PendingDeprecationWarning) - # the option varies depending on the platform - compressed_name = archive_name + compress_ext[compress] - if sys.platform == 'win32': - cmd = [compress, archive_name, compressed_name] - else: - cmd = [compress, '-f', archive_name] - from distutils2.spawn import spawn - spawn(cmd, dry_run=dry_run) - return compressed_name - return archive_name -def _call_external_zip(directory, verbose=False): +def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False): # XXX see if we want to keep an external call here if verbose: zipoptions = "-r" @@ -420,8 +444,7 @@ except DistutilsExecError: # XXX really should distinguish between "couldn't find # external 'zip' command" and "zip failed". - raise ExecError, \ - ("unable to create zip file '%s': " + raise ExecError("unable to create zip file '%s': " "could neither import the 'zipfile' module nor " "find a standalone zip utility") % zip_filename @@ -451,7 +474,7 @@ zipfile = None if zipfile is None: - _call_external_zip(base_dir, verbose) + _call_external_zip(base_dir, zip_filename, verbose, dry_run) else: if logger is not None: logger.info("creating '%s' and adding '%s' to it", @@ -475,12 +498,14 @@ _ARCHIVE_FORMATS = { 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), 'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), - 'ztar': (_make_tarball, [('compress', 'compress')], - "compressed tar file"), 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"), 'zip': (_make_zipfile, [],"ZIP file") } +if _BZ2_SUPPORTED: + _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], + "bzip2'ed tar-file") + def get_archive_formats(): """Returns a list of supported formats for archiving and unarchiving. @@ -520,7 +545,7 @@ """Create an archive file (eg. zip or tar). 'base_name' is the name of the file to create, minus any format-specific - extension; 'format' is the archive format: one of "zip", "tar", "ztar", + extension; 'format' is the archive format: one of "zip", "tar", "bztar" or "gztar". 'root_dir' is a directory that will be the root directory of the @@ -549,7 +574,7 @@ try: format_info = _ARCHIVE_FORMATS[format] except KeyError: - raise ValueError, "unknown archive format '%s'" % format + raise ValueError("unknown archive format '%s'" % format) func = format_info[0] for arg, val in format_info[1]: @@ -568,3 +593,169 @@ os.chdir(save_cwd) return filename + + +def get_unpack_formats(): + """Returns a list of supported formats for unpacking. + + Each element of the returned sequence is a tuple + (name, extensions, description) + """ + formats = [(name, info[0], info[3]) for name, info in + _UNPACK_FORMATS.items()] + formats.sort() + return formats + +def _check_unpack_options(extensions, function, extra_args): + """Checks what gets registered as an unpacker.""" + # first make sure no other unpacker is registered for this extension + existing_extensions = {} + for name, info in _UNPACK_FORMATS.items(): + for ext in info[0]: + existing_extensions[ext] = name + + for extension in extensions: + if extension in existing_extensions: + msg = '%s is already registered for "%s"' + raise RegistryError(msg % (extension, + existing_extensions[extension])) + + if not callable(function): + raise TypeError('The registered function must be a callable') + + +def register_unpack_format(name, extensions, function, extra_args=None, + description=''): + """Registers an unpack format. + + `name` is the name of the format. `extensions` is a list of extensions + corresponding to the format. + + `function` is the callable that will be + used to unpack archives. The callable will receive archives to unpack. + If it's unable to handle an archive, it needs to raise a ReadError + exception. + + If provided, `extra_args` is a sequence of + (name, value) tuples that will be passed as arguments to the callable. + description can be provided to describe the format, and will be returned + by the get_unpack_formats() function. + """ + if extra_args is None: + extra_args = [] + _check_unpack_options(extensions, function, extra_args) + _UNPACK_FORMATS[name] = extensions, function, extra_args, description + +def unregister_unpack_format(name): + """Removes the pack format from the registery.""" + del _UNPACK_FORMATS[name] + +def _ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + +def _unpack_zipfile(filename, extract_dir): + """Unpack zip `filename` to `extract_dir` + """ + try: + import zipfile + except ImportError: + raise ReadError('zlib not supported, cannot unpack this archive.') + + if not zipfile.is_zipfile(filename): + raise ReadError("%s is not a zip file" % filename) + + zip = zipfile.ZipFile(filename) + try: + for info in zip.infolist(): + name = info.filename + + # don't extract absolute paths or ones with .. in them + if name.startswith('/') or '..' in name: + continue + + target = os.path.join(extract_dir, *name.split('/')) + if not target: + continue + + _ensure_directory(target) + if not name.endswith('/'): + # file + data = zip.read(info.filename) + f = open(target,'wb') + try: + f.write(data) + finally: + f.close() + del data + finally: + zip.close() + +def _unpack_tarfile(filename, extract_dir): + """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` + """ + from distutils2._backport import tarfile + try: + tarobj = tarfile.open(filename) + except tarfile.TarError: + raise ReadError( + "%s is not a compressed or uncompressed tar file" % filename) + try: + tarobj.extractall(extract_dir) + finally: + tarobj.close() + +_UNPACK_FORMATS = { + 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"), + 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"), + 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file") + } + +if _BZ2_SUPPORTED: + _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], + "bzip2'ed tar-file") + +def _find_unpack_format(filename): + for name, info in _UNPACK_FORMATS.items(): + for extension in info[0]: + if filename.endswith(extension): + return name + return None + +def unpack_archive(filename, extract_dir=None, format=None): + """Unpack an archive. + + `filename` is the name of the archive. + + `extract_dir` is the name of the target directory, where the archive + is unpacked. If not provided, the current working directory is used. + + `format` is the archive format: one of "zip", "tar", or "gztar". Or any + other registered format. If not provided, unpack_archive will use the + filename extension and see if an unpacker was registered for that + extension. + + In case none is found, a ValueError is raised. + """ + if extract_dir is None: + extract_dir = os.getcwd() + + if format is not None: + try: + format_info = _UNPACK_FORMATS[format] + except KeyError: + raise ValueError("Unknown unpack format '{0}'".format(format)) + + func = format_info[0] + func(filename, extract_dir, **dict(format_info[1])) + else: + # we need to look at the registered unpackers supported extensions + format = _find_unpack_format(filename) + if format is None: + raise ReadError("Unknown archive format '{0}'".format(filename)) + + func = _UNPACK_FORMATS[format][1] + kwargs = dict(_UNPACK_FORMATS[format][2]) + func(filename, extract_dir, **kwargs) diff --git a/distutils2/_backport/tests/test_shutil.py b/distutils2/_backport/tests/test_shutil.py new file mode 100644 --- /dev/null +++ b/distutils2/_backport/tests/test_shutil.py @@ -0,0 +1,935 @@ +import os +import sys +import tempfile +import stat +import tarfile +from os.path import splitdrive +from StringIO import StringIO + +from distutils.spawn import find_executable, spawn +from distutils2._backport import shutil +from distutils2._backport.shutil import ( + _make_tarball, _make_zipfile, make_archive, unpack_archive, + register_archive_format, unregister_archive_format, get_archive_formats, + register_unpack_format, unregister_unpack_format, get_unpack_formats, + Error, RegistryError) + +from distutils2.tests import unittest, support, TESTFN + +try: + import bz2 + BZ2_SUPPORTED = True +except ImportError: + BZ2_SUPPORTED = False + +TESTFN2 = TESTFN + "2" + +try: + import grp + import pwd + UID_GID_SUPPORT = True +except ImportError: + UID_GID_SUPPORT = False + +try: + import zlib +except ImportError: + zlib = None + +try: + import zipfile + ZIP_SUPPORT = True +except ImportError: + ZIP_SUPPORT = find_executable('zip') + +class TestShutil(unittest.TestCase): + + def setUp(self): + super(TestShutil, self).setUp() + self.tempdirs = [] + + def tearDown(self): + super(TestShutil, self).tearDown() + while self.tempdirs: + d = self.tempdirs.pop() + shutil.rmtree(d, os.name in ('nt', 'cygwin')) + + def write_file(self, path, content='xxx'): + """Writes a file in the given path. + + + path can be a string or a sequence. + """ + if isinstance(path, (list, tuple)): + path = os.path.join(*path) + f = open(path, 'w') + try: + f.write(content) + finally: + f.close() + + def mkdtemp(self): + """Create a temporary directory that will be cleaned up. + + Returns the path of the directory. + """ + d = tempfile.mkdtemp() + self.tempdirs.append(d) + return d + + def test_rmtree_errors(self): + # filename is guaranteed not to exist + filename = tempfile.mktemp() + self.assertRaises(OSError, shutil.rmtree, filename) + + # See bug #1071513 for why we don't run this on cygwin + # and bug #1076467 for why we don't run this as root. + if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin' + and not (hasattr(os, 'geteuid') and os.geteuid() == 0)): + def test_on_error(self): + self.errorState = 0 + os.mkdir(TESTFN) + self.childpath = os.path.join(TESTFN, 'a') + f = open(self.childpath, 'w') + f.close() + old_dir_mode = os.stat(TESTFN).st_mode + old_child_mode = os.stat(self.childpath).st_mode + # Make unwritable. + os.chmod(self.childpath, stat.S_IREAD) + os.chmod(TESTFN, stat.S_IREAD) + + shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) + # Test whether onerror has actually been called. + self.assertEqual(self.errorState, 2, + "Expected call to onerror function did not happen.") + + # Make writable again. + os.chmod(TESTFN, old_dir_mode) + os.chmod(self.childpath, old_child_mode) + + # Clean up. + shutil.rmtree(TESTFN) + + def check_args_to_onerror(self, func, arg, exc): + # test_rmtree_errors deliberately runs rmtree + # on a directory that is chmod 400, which will fail. + # This function is run when shutil.rmtree fails. + # 99.9% of the time it initially fails to remove + # a file in the directory, so the first time through + # func is os.remove. + # However, some Linux machines running ZFS on + # FUSE experienced a failure earlier in the process + # at os.listdir. The first failure may legally + # be either. + if self.errorState == 0: + if func is os.remove: + self.assertEqual(arg, self.childpath) + else: + self.assertIs(func, os.listdir, + "func must be either os.remove or os.listdir") + self.assertEqual(arg, TESTFN) + self.assertTrue(issubclass(exc[0], OSError)) + self.errorState = 1 + else: + self.assertEqual(func, os.rmdir) + self.assertEqual(arg, TESTFN) + self.assertTrue(issubclass(exc[0], OSError)) + self.errorState = 2 + + def test_rmtree_dont_delete_file(self): + # When called on a file instead of a directory, don't delete it. + handle, path = tempfile.mkstemp() + os.fdopen(handle).close() + self.assertRaises(OSError, shutil.rmtree, path) + os.remove(path) + + def _write_data(self, path, data): + f = open(path, "w") + f.write(data) + f.close() + + def test_copytree_simple(self): + + def read_data(path): + f = open(path) + data = f.read() + f.close() + return data + + src_dir = tempfile.mkdtemp() + dst_dir = os.path.join(tempfile.mkdtemp(), 'destination') + self._write_data(os.path.join(src_dir, 'test.txt'), '123') + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + + try: + shutil.copytree(src_dir, dst_dir) + self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt'))) + self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir'))) + self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir', + 'test.txt'))) + actual = read_data(os.path.join(dst_dir, 'test.txt')) + self.assertEqual(actual, '123') + actual = read_data(os.path.join(dst_dir, 'test_dir', 'test.txt')) + self.assertEqual(actual, '456') + finally: + for path in ( + os.path.join(src_dir, 'test.txt'), + os.path.join(dst_dir, 'test.txt'), + os.path.join(src_dir, 'test_dir', 'test.txt'), + os.path.join(dst_dir, 'test_dir', 'test.txt'), + ): + if os.path.exists(path): + os.remove(path) + for path in (src_dir, + os.path.dirname(dst_dir) + ): + if os.path.exists(path): + shutil.rmtree(path) + + def test_copytree_with_exclude(self): + + def read_data(path): + f = open(path) + data = f.read() + f.close() + return data + + # creating data + join = os.path.join + exists = os.path.exists + src_dir = tempfile.mkdtemp() + try: + dst_dir = join(tempfile.mkdtemp(), 'destination') + self._write_data(join(src_dir, 'test.txt'), '123') + self._write_data(join(src_dir, 'test.tmp'), '123') + os.mkdir(join(src_dir, 'test_dir')) + self._write_data(join(src_dir, 'test_dir', 'test.txt'), '456') + os.mkdir(join(src_dir, 'test_dir2')) + self._write_data(join(src_dir, 'test_dir2', 'test.txt'), '456') + os.mkdir(join(src_dir, 'test_dir2', 'subdir')) + os.mkdir(join(src_dir, 'test_dir2', 'subdir2')) + self._write_data(join(src_dir, 'test_dir2', 'subdir', 'test.txt'), + '456') + self._write_data(join(src_dir, 'test_dir2', 'subdir2', 'test.py'), + '456') + + + # testing glob-like patterns + try: + patterns = shutil.ignore_patterns('*.tmp', 'test_dir2') + shutil.copytree(src_dir, dst_dir, ignore=patterns) + # checking the result: some elements should not be copied + self.assertTrue(exists(join(dst_dir, 'test.txt'))) + self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2'))) + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + try: + patterns = shutil.ignore_patterns('*.tmp', 'subdir*') + shutil.copytree(src_dir, dst_dir, ignore=patterns) + # checking the result: some elements should not be copied + self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + + # testing callable-style + try: + def _filter(src, names): + res = [] + for name in names: + path = os.path.join(src, name) + + if (os.path.isdir(path) and + path.split()[-1] == 'subdir'): + res.append(name) + elif os.path.splitext(path)[-1] in ('.py'): + res.append(name) + return res + + shutil.copytree(src_dir, dst_dir, ignore=_filter) + + # checking the result: some elements should not be copied + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2', + 'test.py'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) + + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + finally: + shutil.rmtree(src_dir) + shutil.rmtree(os.path.dirname(dst_dir)) + + @support.skip_unless_symlink + def test_dont_copy_file_onto_link_to_itself(self): + # bug 851123. + os.mkdir(TESTFN) + src = os.path.join(TESTFN, 'cheese') + dst = os.path.join(TESTFN, 'shop') + try: + f = open(src, 'w') + f.write('cheddar') + f.close() + + if hasattr(os, "link"): + os.link(src, dst) + self.assertRaises(shutil.Error, shutil.copyfile, src, dst) + f = open(src, 'r') + try: + self.assertEqual(f.read(), 'cheddar') + finally: + f.close() + os.remove(dst) + + # Using `src` here would mean we end up with a symlink pointing + # to TESTFN/TESTFN/cheese, while it should point at + # TESTFN/cheese. + os.symlink('cheese', dst) + self.assertRaises(shutil.Error, shutil.copyfile, src, dst) + f = open(src, 'r') + try: + self.assertEqual(f.read(), 'cheddar') + finally: + f.close() + os.remove(dst) + finally: + try: + shutil.rmtree(TESTFN) + except OSError: + pass + + @support.skip_unless_symlink + def test_rmtree_on_symlink(self): + # bug 1669. + os.mkdir(TESTFN) + try: + src = os.path.join(TESTFN, 'cheese') + dst = os.path.join(TESTFN, 'shop') + os.mkdir(src) + os.symlink(src, dst) + self.assertRaises(OSError, shutil.rmtree, dst) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + if hasattr(os, "mkfifo"): + # Issue #3002: copyfile and copytree block indefinitely on named pipes + def test_copyfile_named_pipe(self): + os.mkfifo(TESTFN) + try: + self.assertRaises(shutil.SpecialFileError, + shutil.copyfile, TESTFN, TESTFN2) + self.assertRaises(shutil.SpecialFileError, + shutil.copyfile, __file__, TESTFN) + finally: + os.remove(TESTFN) + + @unittest.skipUnless(hasattr(os, 'mkfifo'), 'requires os.mkfifo') + def test_copytree_named_pipe(self): + os.mkdir(TESTFN) + try: + subdir = os.path.join(TESTFN, "subdir") + os.mkdir(subdir) + pipe = os.path.join(subdir, "mypipe") + os.mkfifo(pipe) + try: + shutil.copytree(TESTFN, TESTFN2) + except shutil.Error, e: + errors = e.args[0] + self.assertEqual(len(errors), 1) + src, dst, error_msg = errors[0] + self.assertEqual("`%s` is a named pipe" % pipe, error_msg) + else: + self.fail("shutil.Error should have been raised") + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + shutil.rmtree(TESTFN2, ignore_errors=True) + + def test_copytree_special_func(self): + + src_dir = self.mkdtemp() + dst_dir = os.path.join(self.mkdtemp(), 'destination') + self._write_data(os.path.join(src_dir, 'test.txt'), '123') + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + + copied = [] + def _copy(src, dst): + copied.append((src, dst)) + + shutil.copytree(src_dir, dst_dir, copy_function=_copy) + self.assertEquals(len(copied), 2) + + @support.skip_unless_symlink + def test_copytree_dangling_symlinks(self): + + # a dangling symlink raises an error at the end + src_dir = self.mkdtemp() + dst_dir = os.path.join(self.mkdtemp(), 'destination') + os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt')) + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + self.assertRaises(Error, shutil.copytree, src_dir, dst_dir) + + # a dangling symlink is ignored with the proper flag + dst_dir = os.path.join(self.mkdtemp(), 'destination2') + shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True) + self.assertNotIn('test.txt', os.listdir(dst_dir)) + + # a dangling symlink is copied if symlinks=True + dst_dir = os.path.join(self.mkdtemp(), 'destination3') + shutil.copytree(src_dir, dst_dir, symlinks=True) + self.assertIn('test.txt', os.listdir(dst_dir)) + + @unittest.skipUnless(zlib, "requires zlib") + def test_make_tarball(self): + # creating something to tar + tmpdir = self.mkdtemp() + self.write_file([tmpdir, 'file1'], 'xxx') + self.write_file([tmpdir, 'file2'], 'xxx') + os.mkdir(os.path.join(tmpdir, 'sub')) + self.write_file([tmpdir, 'sub', 'file3'], 'xxx') + + tmpdir2 = self.mkdtemp() + unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0], + "source and target should be on same drive") + + base_name = os.path.join(tmpdir2, 'archive') + + # working with relative paths to avoid tar warnings + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(splitdrive(base_name)[1], '.') + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + tarball = base_name + '.tar.gz' + self.assertTrue(os.path.exists(tarball)) + + # trying an uncompressed one + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(splitdrive(base_name)[1], '.', compress=None) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + def _tarinfo(self, path): + tar = tarfile.open(path) + try: + names = tar.getnames() + names.sort() + return tuple(names) + finally: + tar.close() + + def _create_files(self): + # creating something to tar + tmpdir = self.mkdtemp() + dist = os.path.join(tmpdir, 'dist') + os.mkdir(dist) + self.write_file([dist, 'file1'], 'xxx') + self.write_file([dist, 'file2'], 'xxx') + os.mkdir(os.path.join(dist, 'sub')) + self.write_file([dist, 'sub', 'file3'], 'xxx') + os.mkdir(os.path.join(dist, 'sub2')) + tmpdir2 = self.mkdtemp() + base_name = os.path.join(tmpdir2, 'archive') + return tmpdir, tmpdir2, base_name + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(find_executable('tar') and find_executable('gzip'), + 'Need the tar command to run') + def test_tarfile_vs_tar(self): + tmpdir, tmpdir2, base_name = self._create_files() + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist') + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + tarball = base_name + '.tar.gz' + self.assertTrue(os.path.exists(tarball)) + + # now create another tarball using `tar` + tarball2 = os.path.join(tmpdir, 'archive2.tar.gz') + tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist'] + gzip_cmd = ['gzip', '-f9', 'archive2.tar'] + old_dir = os.getcwd() + old_stdout = sys.stdout + os.chdir(tmpdir) + sys.stdout = StringIO() + + try: + spawn(tar_cmd) + spawn(gzip_cmd) + finally: + os.chdir(old_dir) + sys.stdout = old_stdout + + self.assertTrue(os.path.exists(tarball2)) + # let's compare both tarballs + self.assertEquals(self._tarinfo(tarball), self._tarinfo(tarball2)) + + # trying an uncompressed one + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist', compress=None) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + # now for a dry_run + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist', compress=None, dry_run=True) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run') + def test_make_zipfile(self): + # creating something to tar + tmpdir = self.mkdtemp() + self.write_file([tmpdir, 'file1'], 'xxx') + self.write_file([tmpdir, 'file2'], 'xxx') + + tmpdir2 = self.mkdtemp() + base_name = os.path.join(tmpdir2, 'archive') + _make_zipfile(base_name, tmpdir) + + # check if the compressed tarball was created + tarball = base_name + '.zip' + + + def test_make_archive(self): + tmpdir = self.mkdtemp() + base_name = os.path.join(tmpdir, 'archive') + self.assertRaises(ValueError, make_archive, base_name, 'xxx') + + @unittest.skipUnless(zlib, "Requires zlib") + def test_make_archive_owner_group(self): + # testing make_archive with owner and group, with various combinations + # this works even if there's not gid/uid support + if UID_GID_SUPPORT: + group = grp.getgrgid(0)[0] + owner = pwd.getpwuid(0)[0] + else: + group = owner = 'root' + + base_dir, root_dir, base_name = self._create_files() + base_name = os.path.join(self.mkdtemp() , 'archive') + res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner, + group=group) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'zip', root_dir, base_dir) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'tar', root_dir, base_dir, + owner=owner, group=group) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'tar', root_dir, base_dir, + owner='kjhkjhkjg', group='oihohoh') + self.assertTrue(os.path.exists(res)) + + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") + def test_tarfile_root_owner(self): + tmpdir, tmpdir2, base_name = self._create_files() + old_dir = os.getcwd() + os.chdir(tmpdir) + group = grp.getgrgid(0)[0] + owner = pwd.getpwuid(0)[0] + try: + archive_name = _make_tarball(base_name, 'dist', compress=None, + owner=owner, group=group) + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + self.assertTrue(os.path.exists(archive_name)) + + # now checks the rights + archive = tarfile.open(archive_name) + try: + for member in archive.getmembers(): + self.assertEquals(member.uid, 0) + self.assertEquals(member.gid, 0) + finally: + archive.close() + + def test_make_archive_cwd(self): + current_dir = os.getcwd() + def _breaks(*args, **kw): + raise RuntimeError() + + register_archive_format('xxx', _breaks, [], 'xxx file') + try: + try: + make_archive('xxx', 'xxx', root_dir=self.mkdtemp()) + except Exception: + pass + self.assertEquals(os.getcwd(), current_dir) + finally: + unregister_archive_format('xxx') + + def test_register_archive_format(self): + + self.assertRaises(TypeError, register_archive_format, 'xxx', 1) + self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x, + 1) + self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x, + [(1, 2), (1, 2, 3)]) + + register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file') + formats = [name for name, params in get_archive_formats()] + self.assertIn('xxx', formats) + + unregister_archive_format('xxx') + formats = [name for name, params in get_archive_formats()] + self.assertNotIn('xxx', formats) + + def _compare_dirs(self, dir1, dir2): + # check that dir1 and dir2 are equivalent, + # return the diff + diff = [] + for root, dirs, files in os.walk(dir1): + for file_ in files: + path = os.path.join(root, file_) + target_path = os.path.join(dir2, os.path.split(path)[-1]) + if not os.path.exists(target_path): + diff.append(file_) + return diff + + @unittest.skipUnless(zlib, "Requires zlib") + def test_unpack_archive(self): + formats = ['tar', 'gztar', 'zip'] + if BZ2_SUPPORTED: + formats.append('bztar') + + for format in formats: + tmpdir = self.mkdtemp() + base_dir, root_dir, base_name = self._create_files() + tmpdir2 = self.mkdtemp() + filename = make_archive(base_name, format, root_dir, base_dir) + + # let's try to unpack it now + unpack_archive(filename, tmpdir2) + diff = self._compare_dirs(tmpdir, tmpdir2) + self.assertEquals(diff, []) + + def test_unpack_registery(self): + + formats = get_unpack_formats() + + def _boo(filename, extract_dir, extra): + self.assertEquals(extra, 1) + self.assertEquals(filename, 'stuff.boo') + self.assertEquals(extract_dir, 'xx') + + register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)]) + unpack_archive('stuff.boo', 'xx') + + # trying to register a .boo unpacker again + self.assertRaises(RegistryError, register_unpack_format, 'Boo2', + ['.boo'], _boo) + + # should work now + unregister_unpack_format('Boo') + register_unpack_format('Boo2', ['.boo'], _boo) + self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats()) + self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats()) + + # let's leave a clean state + unregister_unpack_format('Boo2') + self.assertEquals(get_unpack_formats(), formats) + + +class TestMove(unittest.TestCase): + + def setUp(self): + filename = "foo" + self.src_dir = tempfile.mkdtemp() + self.dst_dir = tempfile.mkdtemp() + self.src_file = os.path.join(self.src_dir, filename) + self.dst_file = os.path.join(self.dst_dir, filename) + # Try to create a dir in the current directory, hoping that it is + # not located on the same filesystem as the system tmp dir. + try: + self.dir_other_fs = tempfile.mkdtemp( + dir=os.path.dirname(__file__)) + self.file_other_fs = os.path.join(self.dir_other_fs, + filename) + except OSError: + self.dir_other_fs = None + f = open(self.src_file, "wb") + try: + f.write("spam") + finally: + f.close() + + def tearDown(self): + for d in (self.src_dir, self.dst_dir, self.dir_other_fs): + try: + if d: + shutil.rmtree(d) + except: + pass + + def _check_move_file(self, src, dst, real_dst): + f = open(src, "rb") + try: + contents = f.read() + finally: + f.close() + + shutil.move(src, dst) + f = open(real_dst, "rb") + try: + self.assertEqual(contents, f.read()) + finally: + f.close() + + self.assertFalse(os.path.exists(src)) + + def _check_move_dir(self, src, dst, real_dst): + contents = sorted(os.listdir(src)) + shutil.move(src, dst) + self.assertEqual(contents, sorted(os.listdir(real_dst))) + self.assertFalse(os.path.exists(src)) + + def test_move_file(self): + # Move a file to another location on the same filesystem. + self._check_move_file(self.src_file, self.dst_file, self.dst_file) + + def test_move_file_to_dir(self): + # Move a file inside an existing dir on the same filesystem. + self._check_move_file(self.src_file, self.dst_dir, self.dst_file) + + def test_move_file_other_fs(self): + # Move a file to an existing dir on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_file(self.src_file, self.file_other_fs, + self.file_other_fs) + + def test_move_file_to_dir_other_fs(self): + # Move a file to another location on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_file(self.src_file, self.dir_other_fs, + self.file_other_fs) + + def test_move_dir(self): + # Move a dir to another location on the same filesystem. + dst_dir = tempfile.mktemp() + try: + self._check_move_dir(self.src_dir, dst_dir, dst_dir) + finally: + try: + shutil.rmtree(dst_dir) + except: + pass + + def test_move_dir_other_fs(self): + # Move a dir to another location on another filesystem. + if not self.dir_other_fs: + # skip + return + dst_dir = tempfile.mktemp(dir=self.dir_other_fs) + try: + self._check_move_dir(self.src_dir, dst_dir, dst_dir) + finally: + try: + shutil.rmtree(dst_dir) + except: + pass + + def test_move_dir_to_dir(self): + # Move a dir inside an existing dir on the same filesystem. + self._check_move_dir(self.src_dir, self.dst_dir, + os.path.join(self.dst_dir, os.path.basename(self.src_dir))) + + def test_move_dir_to_dir_other_fs(self): + # Move a dir inside an existing dir on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_dir(self.src_dir, self.dir_other_fs, + os.path.join(self.dir_other_fs, os.path.basename(self.src_dir))) + + def test_existing_file_inside_dest_dir(self): + # A file with the same name inside the destination dir already exists. + f = open(self.dst_file, "wb") + try: + pass + finally: + f.close() + self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir) + + def test_dont_move_dir_in_itself(self): + # Moving a dir inside itself raises an Error. + dst = os.path.join(self.src_dir, "bar") + self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst) + + def test_destinsrc_false_negative(self): + os.mkdir(TESTFN) + try: + for src, dst in [('srcdir', 'srcdir/dest')]: + src = os.path.join(TESTFN, src) + dst = os.path.join(TESTFN, dst) + self.assertTrue(shutil._destinsrc(src, dst), + msg='_destinsrc() wrongly concluded that ' + 'dst (%s) is not in src (%s)' % (dst, src)) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + def test_destinsrc_false_positive(self): + os.mkdir(TESTFN) + try: + for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]: + src = os.path.join(TESTFN, src) + dst = os.path.join(TESTFN, dst) + self.assertFalse(shutil._destinsrc(src, dst), + msg='_destinsrc() wrongly concluded that ' + 'dst (%s) is in src (%s)' % (dst, src)) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + +class TestCopyFile(unittest.TestCase): + + _delete = False + + class Faux(object): + _entered = False + _exited_with = None + _raised = False + + def __init__(self, raise_in_exit=False, suppress_at_exit=True): + self._raise_in_exit = raise_in_exit + self._suppress_at_exit = suppress_at_exit + + def read(self, *args): + return '' + + def __enter__(self): + self._entered = True + + def __exit__(self, exc_type, exc_val, exc_tb): + self._exited_with = exc_type, exc_val, exc_tb + if self._raise_in_exit: + self._raised = True + raise IOError("Cannot close") + return self._suppress_at_exit + + def tearDown(self): + if self._delete: + del shutil.open + + def _set_shutil_open(self, func): + shutil.open = func + self._delete = True + + def test_w_source_open_fails(self): + def _open(filename, mode='r'): + if filename == 'srcfile': + raise IOError('Cannot open "srcfile"') + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile') + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_dest_open_fails(self): + + srcfile = self.Faux() + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + raise IOError('Cannot open "destfile"') + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + shutil.copyfile('srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(srcfile._exited_with[0] is IOError) + self.assertEqual(srcfile._exited_with[1].args, + ('Cannot open "destfile"',)) + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_dest_close_fails(self): + + srcfile = self.Faux() + destfile = self.Faux(True) + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + return destfile + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + shutil.copyfile('srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(destfile._entered) + self.assertTrue(destfile._raised) + self.assertTrue(srcfile._exited_with[0] is IOError) + self.assertEqual(srcfile._exited_with[1].args, + ('Cannot close',)) + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_source_close_fails(self): + + srcfile = self.Faux(True) + destfile = self.Faux() + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + return destfile + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + self.assertRaises(IOError, + shutil.copyfile, 'srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(destfile._entered) + self.assertFalse(destfile._raised) + self.assertTrue(srcfile._exited_with[0] is None) + self.assertTrue(srcfile._raised) + + +if __name__ == '__main__': + unittest.main() -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Fix two NameErrors (#11057) Message-ID: tarek.ziade pushed 801c90825cc1 to distutils2: http://hg.python.org/distutils2/rev/801c90825cc1 changeset: 941:801c90825cc1 parent: 927:11f13263c188 user: ?ric Araujo date: Sat Jan 29 17:06:35 2011 +0100 summary: Fix two NameErrors (#11057) files: distutils2/command/build_py.py distutils2/config.py diff --git a/distutils2/command/build_py.py b/distutils2/command/build_py.py --- a/distutils2/command/build_py.py +++ b/distutils2/command/build_py.py @@ -8,7 +8,6 @@ import logging from glob import glob -import distutils2 from distutils2.command.cmd import Command from distutils2.errors import DistutilsOptionError, DistutilsFileError from distutils2.util import convert_path @@ -163,11 +162,13 @@ Helper function for `run()`. """ + # FIXME add tests for this method for package, src_dir, build_dir, filenames in self.data_files: for filename in filenames: target = os.path.join(build_dir, filename) + srcfile = os.path.join(src_dir, filename) self.mkpath(os.path.dirname(target)) - outf, copied = self.copy_file(os.path.join(src_dir, filename), + outf, copied = self.copy_file(srcfile, target, preserve_mode=False) if copied and srcfile in self.distribution.convert_2to3.doctests: self._doctests_2to3.append(outf) diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -7,7 +7,8 @@ from ConfigParser import RawConfigParser from distutils2 import logger -from distutils2.util import check_environ, resolve_name +from distutils2.errors import DistutilsOptionError +from distutils2.util import check_environ, resolve_name, strtobool from distutils2.compiler import set_compiler from distutils2.command import set_command -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: Remove unused any Message-ID: tarek.ziade pushed b8f163d9fcd7 to distutils2: http://hg.python.org/distutils2/rev/b8f163d9fcd7 changeset: 942:b8f163d9fcd7 user: ?ric Araujo date: Sat Jan 29 17:11:14 2011 +0100 summary: Remove unused any files: distutils2/_backport/__init__.py diff --git a/distutils2/_backport/__init__.py b/distutils2/_backport/__init__.py --- a/distutils2/_backport/__init__.py +++ b/distutils2/_backport/__init__.py @@ -1,8 +1,2 @@ """Things that will land in the Python 3.3 std lib but which we must drag along with us for now to support 2.x.""" - -def any(seq): - for elem in seq: - if elem: - return True - return False -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: add assertIsFile Message-ID: tarek.ziade pushed c7deaaa88de8 to distutils2: http://hg.python.org/distutils2/rev/c7deaaa88de8 changeset: 944:c7deaaa88de8 parent: 913:317bff9e4495 user: Gael Pasgrimaud date: Sat Jan 29 16:05:20 2011 +0100 summary: add assertIsFile files: distutils2/tests/support.py diff --git a/distutils2/tests/support.py b/distutils2/tests/support.py --- a/distutils2/tests/support.py +++ b/distutils2/tests/support.py @@ -155,6 +155,18 @@ dist = Distribution(attrs=kw) return pkg_dir, dist + def assertIsFile(self, *args): + path = os.path.join(*args) + dirname = os.path.dirname(path) + file = os.path.basename(path) + if os.path.isdir(dirname): + files = os.listdir(dirname) + msg = "%s not found in %s: %s" % (file, dirname, files) + assert os.path.isfile(path), msg + else: + raise AssertionError( + '%s not found. %s does not exist' % (file, dirname)) + class EnvironGuard(object): """TestCase-compatible mixin to save and restore the environment.""" -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:57 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:57 +0100 Subject: [Python-checkins] distutils2: Branch merge Message-ID: tarek.ziade pushed b1ce3723fe28 to distutils2: http://hg.python.org/distutils2/rev/b1ce3723fe28 changeset: 940:b1ce3723fe28 parent: 920:860a4bcab873 parent: 939:49443233cf92 user: ?ric Araujo date: Sat Jan 29 17:05:30 2011 +0100 summary: Branch merge files: distutils2/_backport/pkgutil.py distutils2/_backport/shutil.py distutils2/_backport/tests/test_pkgutil.py distutils2/_backport/tests/test_shutil.py distutils2/_backport/tests/test_sysconfig.py distutils2/command/cmd.py distutils2/tests/support.py distutils2/tests/test_command_install_dist.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -1,24 +1,19 @@ """Utilities to support packages.""" -# NOTE: This module must remain compatible with Python 2.3, as it is shared -# by setuptools for distribution with Python 2.3 and up. - import os import sys import imp -import os.path +import re +import warnings from csv import reader as csv_reader from types import ModuleType from distutils2.errors import DistutilsError from distutils2.metadata import DistributionMetadata from distutils2.version import suggest_normalized_version, VersionPredicate -import zipimport try: import cStringIO as StringIO except ImportError: import StringIO -import re -import warnings __all__ = [ @@ -28,10 +23,14 @@ 'Distribution', 'EggInfoDistribution', 'distinfo_dirname', 'get_distributions', 'get_distribution', 'get_file_users', 'provides_distribution', 'obsoletes_distribution', - 'enable_cache', 'disable_cache', 'clear_cache' + 'enable_cache', 'disable_cache', 'clear_cache', ] +########################## +# PEP 302 Implementation # +########################## + def read_code(stream): # This helper is needed in order for the :pep:`302` emulation to # correctly handle compiled files @@ -41,7 +40,7 @@ if magic != imp.get_magic(): return None - stream.read(4) # Skip timestamp + stream.read(4) # Skip timestamp return marshal.load(stream) @@ -173,7 +172,6 @@ #@simplegeneric def iter_importer_modules(importer, prefix=''): - "" if not hasattr(importer, 'iter_modules'): return [] return importer.iter_modules(prefix) @@ -331,9 +329,9 @@ def get_filename(self, fullname=None): fullname = self._fix_name(fullname) mod_type = self.etc[2] - if self.etc[2] == imp.PKG_DIRECTORY: + if mod_type == imp.PKG_DIRECTORY: return self._get_delegate().get_filename() - elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION): + elif mod_type in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION): return self.filename return None @@ -432,7 +430,8 @@ import mechanism will find the latter. Items of the following types can be affected by this discrepancy: - ``imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY`` + :data:`imp.C_EXTENSION`, :data:`imp.PY_SOURCE`, :data:`imp.PY_COMPILED`, + :data:`imp.PKG_DIRECTORY` """ if fullname.startswith('.'): raise ImportError("Relative module names not supported") @@ -534,13 +533,13 @@ # frozen package. Return the path unchanged in that case. return path - pname = os.path.join(*name.split('.')) # Reconstitute as relative path + pname = os.path.join(*name.split('.')) # Reconstitute as relative path # Just in case os.extsep != '.' sname = os.extsep.join(name.split('.')) sname_pkg = sname + os.extsep + "pkg" init_py = "__init__" + os.extsep + "py" - path = path[:] # Start with a copy of the existing path + path = path[:] # Start with a copy of the existing path for dir in sys.path: if not isinstance(dir, basestring) or not os.path.isdir(dir): @@ -565,7 +564,7 @@ line = line.rstrip('\n') if not line or line.startswith('#'): continue - path.append(line) # Don't check for existence! + path.append(line) # Don't check for existence! f.close() return path @@ -609,6 +608,7 @@ resource_name = os.path.join(*parts) return loader.get_data(resource_name) + ########################## # PEP 376 Implementation # ########################## @@ -616,12 +616,12 @@ DIST_FILES = ('INSTALLER', 'METADATA', 'RECORD', 'REQUESTED',) # Cache -_cache_name = {} # maps names to Distribution instances -_cache_name_egg = {} # maps names to EggInfoDistribution instances -_cache_path = {} # maps paths to Distribution instances -_cache_path_egg = {} # maps paths to EggInfoDistribution instances -_cache_generated = False # indicates if .dist-info distributions are cached -_cache_generated_egg = False # indicates if .dist-info and .egg are cached +_cache_name = {} # maps names to Distribution instances +_cache_name_egg = {} # maps names to EggInfoDistribution instances +_cache_path = {} # maps paths to Distribution instances +_cache_path_egg = {} # maps paths to EggInfoDistribution instances +_cache_generated = False # indicates if .dist-info distributions are cached +_cache_generated_egg = False # indicates if .dist-info and .egg are cached _cache_enabled = True @@ -636,6 +636,7 @@ _cache_enabled = True + def disable_cache(): """ Disables the internal cache. @@ -647,9 +648,10 @@ _cache_enabled = False + def clear_cache(): """ Clears the internal cache. """ - global _cache_name, _cache_name_egg, cache_path, _cache_path_egg, \ + global _cache_name, _cache_name_egg, _cache_path, _cache_path_egg, \ _cache_generated, _cache_generated_egg _cache_name = {} @@ -872,7 +874,8 @@ if isinstance(strs, basestring): for s in strs.splitlines(): s = s.strip() - if s and not s.startswith('#'): # skip blank lines/comments + # skip blank lines/comments + if s and not s.startswith('#'): yield s else: for ss in strs: @@ -890,6 +893,7 @@ except IOError: requires = None else: + # FIXME handle the case where zipfile is not available zipf = zipimport.zipimporter(path) fileobj = StringIO.StringIO(zipf.get_data('EGG-INFO/PKG-INFO')) self.metadata = DistributionMetadata(fileobj=fileobj) @@ -952,7 +956,7 @@ version = match.group('first') if match.group('rest'): version += match.group('rest') - version = version.replace(' ', '') # trim spaces + version = version.replace(' ', '') # trim spaces if version is None: reqs.append(name) else: @@ -982,12 +986,6 @@ __hash__ = object.__hash__ -def _normalize_dist_name(name): - """Returns a normalized name from the given *name*. - :rtype: string""" - return name.replace('-', '_') - - def distinfo_dirname(name, version): """ The *name* and *version* parameters are converted into their @@ -1007,7 +1005,7 @@ :returns: directory name :rtype: string""" file_extension = '.dist-info' - name = _normalize_dist_name(name) + name = name.replace('-', '_') normalized_version = suggest_normalized_version(version) # Because this is a lookup procedure, something will be returned even if # it is a version that cannot be normalized @@ -1148,7 +1146,7 @@ raise DistutilsError(('Distribution %s has invalid ' + 'provides field: %s') \ % (dist.name, p)) - p_ver = p_ver[1:-1] # trim off the parenthesis + p_ver = p_ver[1:-1] # trim off the parenthesis if p_name == name and predicate.match(p_ver): yield dist break diff --git a/distutils2/_backport/shutil.py b/distutils2/_backport/shutil.py --- a/distutils2/_backport/shutil.py +++ b/distutils2/_backport/shutil.py @@ -1,4 +1,4 @@ -"""Utility functions for copying files and directory trees. +"""Utility functions for copying and archiving files and directory trees. XXX The functions here don't copy the resource fork or other metadata on Mac. @@ -9,7 +9,13 @@ import stat from os.path import abspath import fnmatch -from warnings import warn +import errno + +try: + import bz2 + _BZ2_SUPPORTED = True +except ImportError: + _BZ2_SUPPORTED = False try: from pwd import getpwnam @@ -21,9 +27,12 @@ except ImportError: getgrnam = None -__all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2", - "copytree","move","rmtree","Error", "SpecialFileError", - "ExecError","make_archive"] +__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", + "copytree", "move", "rmtree", "Error", "SpecialFileError", + "ExecError", "make_archive", "get_archive_formats", + "register_archive_format", "unregister_archive_format", + "get_unpack_formats", "register_unpack_format", + "unregister_unpack_format", "unpack_archive"] class Error(EnvironmentError): pass @@ -35,6 +44,14 @@ class ExecError(EnvironmentError): """Raised when a command could not be executed""" +class ReadError(EnvironmentError): + """Raised when an archive cannot be read""" + +class RegistryError(Exception): + """Raised when a registery operation with the archiving + and unpacking registeries fails""" + + try: WindowsError except NameError: @@ -50,7 +67,7 @@ def _samefile(src, dst): # Macintosh, Unix. - if hasattr(os.path,'samefile'): + if hasattr(os.path, 'samefile'): try: return os.path.samefile(src, dst) except OSError: @@ -63,10 +80,8 @@ def copyfile(src, dst): """Copy data from src to dst""" if _samefile(src, dst): - raise Error, "`%s` and `%s` are the same file" % (src, dst) + raise Error("`%s` and `%s` are the same file" % (src, dst)) - fsrc = None - fdst = None for fn in [src, dst]: try: st = os.stat(fn) @@ -77,15 +92,16 @@ # XXX What about other special files? (sockets, devices...) if stat.S_ISFIFO(st.st_mode): raise SpecialFileError("`%s` is a named pipe" % fn) + + fsrc = open(src, 'rb') try: - fsrc = open(src, 'rb') fdst = open(dst, 'wb') - copyfileobj(fsrc, fdst) + try: + copyfileobj(fsrc, fdst) + finally: + fdst.close() finally: - if fdst: - fdst.close() - if fsrc: - fsrc.close() + fsrc.close() def copymode(src, dst): """Copy mode bits from src to dst""" @@ -103,8 +119,12 @@ if hasattr(os, 'chmod'): os.chmod(dst, mode) if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): - os.chflags(dst, st.st_flags) - + try: + os.chflags(dst, st.st_flags) + except OSError, why: + if (not hasattr(errno, 'EOPNOTSUPP') or + why.errno != errno.EOPNOTSUPP): + raise def copy(src, dst): """Copy data and mode bits ("cp src dst"). @@ -140,8 +160,9 @@ return set(ignored_names) return _ignore_patterns -def copytree(src, dst, symlinks=False, ignore=None): - """Recursively copy a directory tree using copy2(). +def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, + ignore_dangling_symlinks=False): + """Recursively copy a directory tree. The destination directory must not already exist. If exception(s) occur, an Error is raised with a list of reasons. @@ -149,7 +170,13 @@ If the optional symlinks flag is true, symbolic links in the source tree result in symbolic links in the destination tree; if it is false, the contents of the files pointed to by symbolic - links are copied. + links are copied. If the file pointed by the symlink doesn't + exist, an exception will be added in the list of errors raised in + an Error exception at the end of the copy process. + + You can set the optional ignore_dangling_symlinks flag to true if you + want to silence this exception. Notice that this has no effect on + platforms that don't support os.symlink. The optional ignore argument is a callable. If given, it is called with the `src` parameter, which is the directory @@ -163,7 +190,10 @@ list of names relative to the `src` directory that should not be copied. - XXX Consider this example code rather than the ultimate tool. + The optional copy_function argument is a callable that will be used + to copy each file. It will be called with the source path and the + destination path as arguments. By default, copy2() is used, but any + function that supports the same signature (like copy()) can be used. """ names = os.listdir(src) @@ -182,14 +212,21 @@ srcname = os.path.join(src, name) dstname = os.path.join(dst, name) try: - if symlinks and os.path.islink(srcname): + if os.path.islink(srcname): linkto = os.readlink(srcname) - os.symlink(linkto, dstname) + if symlinks: + os.symlink(linkto, dstname) + else: + # ignore dangling symlink if the flag is on + if not os.path.exists(linkto) and ignore_dangling_symlinks: + continue + # otherwise let the copy occurs. copy2 will raise an error + copy_function(srcname, dstname) elif os.path.isdir(srcname): - copytree(srcname, dstname, symlinks, ignore) + copytree(srcname, dstname, symlinks, ignore, copy_function) else: # Will raise a SpecialFileError for unsupported file types - copy2(srcname, dstname) + copy_function(srcname, dstname) # catch the Error from the recursive copytree so that we can # continue with other files except Error, err: @@ -205,7 +242,7 @@ else: errors.extend((src, dst, str(why))) if errors: - raise Error, errors + raise Error(errors) def rmtree(path, ignore_errors=False, onerror=None): """Recursively delete a directory tree. @@ -235,7 +272,7 @@ names = [] try: names = os.listdir(path) - except os.error, err: + except os.error: onerror(os.listdir, path, sys.exc_info()) for name in names: fullname = os.path.join(path, name) @@ -248,7 +285,7 @@ else: try: os.remove(fullname) - except os.error, err: + except os.error: onerror(os.remove, fullname, sys.exc_info()) try: os.rmdir(path) @@ -282,13 +319,13 @@ if os.path.isdir(dst): real_dst = os.path.join(dst, _basename(src)) if os.path.exists(real_dst): - raise Error, "Destination path '%s' already exists" % real_dst + raise Error("Destination path '%s' already exists" % real_dst) try: os.rename(src, real_dst) except OSError: if os.path.isdir(src): if _destinsrc(src, dst): - raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst) + raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) copytree(src, real_dst, symlinks=True) rmtree(src) else: @@ -333,40 +370,41 @@ """Create a (possibly compressed) tar file from all the files under 'base_dir'. - 'compress' must be "gzip" (the default), "compress", "bzip2", or None. - (compress will be deprecated in Python 3.2) + 'compress' must be "gzip" (the default), "bzip2", or None. 'owner' and 'group' can be used to define an owner and a group for the archive that is being built. If not provided, the current owner and group will be used. The output tar file will be named 'base_dir' + ".tar", possibly plus - the appropriate compression extension (".gz", ".bz2" or ".Z"). + the appropriate compression extension (".gz", or ".bz2"). Returns the output filename. """ - tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', None: '', 'compress': ''} - compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'compress': '.Z'} + tar_compression = {'gzip': 'gz', None: ''} + compress_ext = {'gzip': '.gz'} + + if _BZ2_SUPPORTED: + tar_compression['bzip2'] = 'bz2' + compress_ext['bzip2'] = '.bz2' # flags for compression program, each element of list will be an argument if compress is not None and compress not in compress_ext: - raise ValueError, \ - ("bad value for 'compress': must be None, 'gzip', 'bzip2' " - "or 'compress'") + raise ValueError("bad value for 'compress', or compression format not " + "supported: %s" % compress) - archive_name = base_name + '.tar' - if compress != 'compress': - archive_name += compress_ext.get(compress, '') + archive_name = base_name + '.tar' + compress_ext.get(compress, '') + archive_dir = os.path.dirname(archive_name) - archive_dir = os.path.dirname(archive_name) if not os.path.exists(archive_dir): if logger is not None: - logger.info("creating %s" % archive_dir) + logger.info("creating %s", archive_dir) if not dry_run: os.makedirs(archive_dir) - # creating the tarball + # XXX late import because of circular dependency between shutil and + # tarfile :( from distutils2._backport import tarfile if logger is not None: @@ -391,23 +429,9 @@ finally: tar.close() - # compression using `compress` - # XXX this block will be removed in Python 3.2 - if compress == 'compress': - warn("'compress' will be deprecated.", PendingDeprecationWarning) - # the option varies depending on the platform - compressed_name = archive_name + compress_ext[compress] - if sys.platform == 'win32': - cmd = [compress, archive_name, compressed_name] - else: - cmd = [compress, '-f', archive_name] - from distutils2.spawn import spawn - spawn(cmd, dry_run=dry_run) - return compressed_name - return archive_name -def _call_external_zip(directory, verbose=False): +def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False): # XXX see if we want to keep an external call here if verbose: zipoptions = "-r" @@ -420,8 +444,7 @@ except DistutilsExecError: # XXX really should distinguish between "couldn't find # external 'zip' command" and "zip failed". - raise ExecError, \ - ("unable to create zip file '%s': " + raise ExecError("unable to create zip file '%s': " "could neither import the 'zipfile' module nor " "find a standalone zip utility") % zip_filename @@ -451,7 +474,7 @@ zipfile = None if zipfile is None: - _call_external_zip(base_dir, verbose) + _call_external_zip(base_dir, zip_filename, verbose, dry_run) else: if logger is not None: logger.info("creating '%s' and adding '%s' to it", @@ -475,12 +498,14 @@ _ARCHIVE_FORMATS = { 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), 'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), - 'ztar': (_make_tarball, [('compress', 'compress')], - "compressed tar file"), 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"), - 'zip': (_make_zipfile, [],"ZIP file") + 'zip': (_make_zipfile, [], "ZIP file"), } +if _BZ2_SUPPORTED: + _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], + "bzip2'ed tar-file") + def get_archive_formats(): """Returns a list of supported formats for archiving and unarchiving. @@ -507,7 +532,7 @@ if not isinstance(extra_args, (tuple, list)): raise TypeError('extra_args needs to be a sequence') for element in extra_args: - if not isinstance(element, (tuple, list)) or len(element) !=2 : + if not isinstance(element, (tuple, list)) or len(element) !=2: raise TypeError('extra_args elements are : (arg_name, value)') _ARCHIVE_FORMATS[name] = (function, extra_args, description) @@ -520,7 +545,7 @@ """Create an archive file (eg. zip or tar). 'base_name' is the name of the file to create, minus any format-specific - extension; 'format' is the archive format: one of "zip", "tar", "ztar", + extension; 'format' is the archive format: one of "zip", "tar", "bztar" or "gztar". 'root_dir' is a directory that will be the root directory of the @@ -549,7 +574,7 @@ try: format_info = _ARCHIVE_FORMATS[format] except KeyError: - raise ValueError, "unknown archive format '%s'" % format + raise ValueError("unknown archive format '%s'" % format) func = format_info[0] for arg, val in format_info[1]: @@ -568,3 +593,169 @@ os.chdir(save_cwd) return filename + + +def get_unpack_formats(): + """Returns a list of supported formats for unpacking. + + Each element of the returned sequence is a tuple + (name, extensions, description) + """ + formats = [(name, info[0], info[3]) for name, info in + _UNPACK_FORMATS.iteritems()] + formats.sort() + return formats + +def _check_unpack_options(extensions, function, extra_args): + """Checks what gets registered as an unpacker.""" + # first make sure no other unpacker is registered for this extension + existing_extensions = {} + for name, info in _UNPACK_FORMATS.iteritems(): + for ext in info[0]: + existing_extensions[ext] = name + + for extension in extensions: + if extension in existing_extensions: + msg = '%s is already registered for "%s"' + raise RegistryError(msg % (extension, + existing_extensions[extension])) + + if not callable(function): + raise TypeError('The registered function must be a callable') + + +def register_unpack_format(name, extensions, function, extra_args=None, + description=''): + """Registers an unpack format. + + `name` is the name of the format. `extensions` is a list of extensions + corresponding to the format. + + `function` is the callable that will be + used to unpack archives. The callable will receive archives to unpack. + If it's unable to handle an archive, it needs to raise a ReadError + exception. + + If provided, `extra_args` is a sequence of + (name, value) tuples that will be passed as arguments to the callable. + description can be provided to describe the format, and will be returned + by the get_unpack_formats() function. + """ + if extra_args is None: + extra_args = [] + _check_unpack_options(extensions, function, extra_args) + _UNPACK_FORMATS[name] = extensions, function, extra_args, description + +def unregister_unpack_format(name): + """Removes the pack format from the registery.""" + del _UNPACK_FORMATS[name] + +def _ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + +def _unpack_zipfile(filename, extract_dir): + """Unpack zip `filename` to `extract_dir` + """ + try: + import zipfile + except ImportError: + raise ReadError('zlib not supported, cannot unpack this archive.') + + if not zipfile.is_zipfile(filename): + raise ReadError("%s is not a zip file" % filename) + + zip = zipfile.ZipFile(filename) + try: + for info in zip.infolist(): + name = info.filename + + # don't extract absolute paths or ones with .. in them + if name.startswith('/') or '..' in name: + continue + + target = os.path.join(extract_dir, *name.split('/')) + if not target: + continue + + _ensure_directory(target) + if not name.endswith('/'): + # file + data = zip.read(info.filename) + f = open(target, 'wb') + try: + f.write(data) + finally: + f.close() + del data + finally: + zip.close() + +def _unpack_tarfile(filename, extract_dir): + """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` + """ + from distutils2._backport import tarfile + try: + tarobj = tarfile.open(filename) + except tarfile.TarError: + raise ReadError( + "%s is not a compressed or uncompressed tar file" % filename) + try: + tarobj.extractall(extract_dir) + finally: + tarobj.close() + +_UNPACK_FORMATS = { + 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"), + 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"), + 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file") + } + +if _BZ2_SUPPORTED: + _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], + "bzip2'ed tar-file") + +def _find_unpack_format(filename): + for name, info in _UNPACK_FORMATS.iteritems(): + for extension in info[0]: + if filename.endswith(extension): + return name + return None + +def unpack_archive(filename, extract_dir=None, format=None): + """Unpack an archive. + + `filename` is the name of the archive. + + `extract_dir` is the name of the target directory, where the archive + is unpacked. If not provided, the current working directory is used. + + `format` is the archive format: one of "zip", "tar", or "gztar". Or any + other registered format. If not provided, unpack_archive will use the + filename extension and see if an unpacker was registered for that + extension. + + In case none is found, a ValueError is raised. + """ + if extract_dir is None: + extract_dir = os.getcwd() + + if format is not None: + try: + format_info = _UNPACK_FORMATS[format] + except KeyError: + raise ValueError("Unknown unpack format '{0}'".format(format)) + + func = format_info[0] + func(filename, extract_dir, **dict(format_info[1])) + else: + # we need to look at the registered unpackers supported extensions + format = _find_unpack_format(filename) + if format is None: + raise ReadError("Unknown archive format '{0}'".format(filename)) + + func = _UNPACK_FORMATS[format][1] + kwargs = dict(_UNPACK_FORMATS[format][2]) + func(filename, extract_dir, **kwargs) diff --git a/distutils2/_backport/tests/test_pkgutil.py b/distutils2/_backport/tests/test_pkgutil.py --- a/distutils2/_backport/tests/test_pkgutil.py +++ b/distutils2/_backport/tests/test_pkgutil.py @@ -12,10 +12,15 @@ except ImportError: from distutils2._backport.hashlib import md5 -from test.test_support import TESTFN +from distutils2.errors import DistutilsError +from distutils2.metadata import DistributionMetadata +from distutils2.tests import unittest, run_unittest, support -from distutils2.tests import unittest, run_unittest, support from distutils2._backport import pkgutil +from distutils2._backport.pkgutil import ( + Distribution, EggInfoDistribution, get_distribution, get_distributions, + provides_distribution, obsoletes_distribution, get_file_users, + distinfo_dirname, _yield_distributions) try: from os.path import relpath @@ -108,6 +113,12 @@ self.assertEqual(res1, RESOURCE_DATA) res2 = pkgutil.get_data(pkg, 'sub/res.txt') self.assertEqual(res2, RESOURCE_DATA) + + names = [] + for loader, name, ispkg in pkgutil.iter_modules([zip_file]): + names.append(name) + self.assertEqual(names, ['test_getdata_zipfile']) + del sys.path[0] del sys.modules[pkg] @@ -205,7 +216,7 @@ record_writer.writerow(record_pieces( os.path.join(distinfo_dir, file))) record_writer.writerow([relpath(record_file, sys.prefix)]) - del record_writer # causes the RECORD file to close + del record_writer # causes the RECORD file to close record_reader = csv.reader(open(record_file, 'rb')) record_data = [] for row in record_reader: @@ -225,9 +236,6 @@ def test_instantiation(self): # Test the Distribution class's instantiation provides us with usable # attributes. - # Import the Distribution class - from distutils2._backport.pkgutil import distinfo_dirname, Distribution - here = os.path.abspath(os.path.dirname(__file__)) name = 'choxie' version = '2.0.0.9' @@ -236,7 +244,6 @@ dist = Distribution(dist_path) self.assertEqual(dist.name, name) - from distutils2.metadata import DistributionMetadata self.assertTrue(isinstance(dist.metadata, DistributionMetadata)) self.assertEqual(dist.metadata['version'], version) self.assertTrue(isinstance(dist.requested, type(bool()))) @@ -244,7 +251,6 @@ def test_installed_files(self): # Test the iteration of installed files. # Test the distribution's installed files - from distutils2._backport.pkgutil import Distribution for distinfo_dir in self.distinfo_dirs: dist = Distribution(distinfo_dir) for path, md5_, size in dist.get_installed_files(): @@ -267,14 +273,12 @@ false_path = relpath(os.path.join(*false_path), sys.prefix) # Test if the distribution uses the file in question - from distutils2._backport.pkgutil import Distribution dist = Distribution(distinfo_dir) self.assertTrue(dist.uses(true_path)) self.assertFalse(dist.uses(false_path)) def test_get_distinfo_file(self): # Test the retrieval of dist-info file objects. - from distutils2._backport.pkgutil import Distribution distinfo_name = 'choxie-2.0.0.9' other_distinfo_name = 'grammar-1.0a4' distinfo_dir = os.path.join(self.fake_dists_path, @@ -295,7 +299,6 @@ # Is it the correct file? self.assertEqual(value.name, os.path.join(distinfo_dir, distfile)) - from distutils2.errors import DistutilsError # Test an absolute path that is part of another distributions dist-info other_distinfo_file = os.path.join(self.fake_dists_path, other_distinfo_name + '.dist-info', 'REQUESTED') @@ -307,7 +310,6 @@ def test_get_distinfo_files(self): # Test for the iteration of RECORD path entries. - from distutils2._backport.pkgutil import Distribution distinfo_name = 'towel_stuff-0.1' distinfo_dir = os.path.join(self.fake_dists_path, distinfo_name + '.dist-info') @@ -345,7 +347,7 @@ # Given a name and a version, we expect the distinfo_dirname function # to return a standard distribution information directory name. - items = [# (name, version, standard_dirname) + items = [ # (name, version, standard_dirname) # Test for a very simple single word name and decimal # version number ('docutils', '0.5', 'docutils-0.5.dist-info'), @@ -356,9 +358,6 @@ ('python-ldap', '2.5 a---5', 'python_ldap-2.5 a---5.dist-info'), ] - # Import the function in question - from distutils2._backport.pkgutil import distinfo_dirname - # Loop through the items to validate the results for name, version, standard_dirname in items: dirname = distinfo_dirname(name, version) @@ -371,11 +370,6 @@ ('towel-stuff', '0.1')] found_dists = [] - # Import the function in question - from distutils2._backport.pkgutil import get_distributions, \ - Distribution, \ - EggInfoDistribution - # Verify the fake dists have been found. dists = [dist for dist in get_distributions()] for dist in dists: @@ -416,12 +410,7 @@ def test_get_distribution(self): # Test for looking up a distribution by name. # Test the lookup of the towel-stuff distribution - name = 'towel-stuff' # Note: This is different from the directory name - - # Import the function in question - from distutils2._backport.pkgutil import get_distribution, \ - Distribution, \ - EggInfoDistribution + name = 'towel-stuff' # Note: This is different from the directory name # Lookup the distribution dist = get_distribution(name) @@ -461,7 +450,6 @@ def test_get_file_users(self): # Test the iteration of distributions that use a file. - from distutils2._backport.pkgutil import get_file_users, Distribution name = 'towel_stuff-0.1' path = os.path.join(self.fake_dists_path, name, 'towel_stuff', '__init__.py') @@ -471,9 +459,6 @@ def test_provides(self): # Test for looking up distributions by what they provide - from distutils2._backport.pkgutil import provides_distribution - from distutils2.errors import DistutilsError - checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) l = [dist.name for dist in provides_distribution('truffles')] @@ -522,12 +507,10 @@ use_egg_info=True)] checkLists(l, ['strawberry']) - l = [dist.name for dist in provides_distribution('strawberry', '>0.6', use_egg_info=True)] checkLists(l, []) - l = [dist.name for dist in provides_distribution('banana', '0.4', use_egg_info=True)] checkLists(l, ['banana']) @@ -536,16 +519,12 @@ use_egg_info=True)] checkLists(l, ['banana']) - l = [dist.name for dist in provides_distribution('banana', '!=0.4', use_egg_info=True)] checkLists(l, []) def test_obsoletes(self): # Test looking for distributions based on what they obsolete - from distutils2._backport.pkgutil import obsoletes_distribution - from distutils2.errors import DistutilsError - checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) l = [dist.name for dist in obsoletes_distribution('truffles', '1.0')] @@ -555,7 +534,6 @@ use_egg_info=True)] checkLists(l, ['cheese', 'bacon']) - l = [dist.name for dist in obsoletes_distribution('truffles', '0.8')] checkLists(l, ['choxie']) @@ -575,7 +553,6 @@ def test_yield_distribution(self): # tests the internal function _yield_distributions - from distutils2._backport.pkgutil import _yield_distributions checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) eggs = [('bacon', '0.1'), ('banana', '0.4'), ('strawberry', '0.6'), diff --git a/distutils2/_backport/tests/test_shutil.py b/distutils2/_backport/tests/test_shutil.py new file mode 100644 --- /dev/null +++ b/distutils2/_backport/tests/test_shutil.py @@ -0,0 +1,945 @@ +import os +import sys +import tempfile +import stat +import tarfile +from os.path import splitdrive +from StringIO import StringIO + +from distutils.spawn import find_executable, spawn +from distutils2._backport import shutil +from distutils2._backport.shutil import ( + _make_tarball, _make_zipfile, make_archive, unpack_archive, + register_archive_format, unregister_archive_format, get_archive_formats, + register_unpack_format, unregister_unpack_format, get_unpack_formats, + Error, RegistryError) + +from distutils2.tests import unittest, support, TESTFN + +try: + import bz2 + BZ2_SUPPORTED = True +except ImportError: + BZ2_SUPPORTED = False + +TESTFN2 = TESTFN + "2" + +try: + import grp + import pwd + UID_GID_SUPPORT = True +except ImportError: + UID_GID_SUPPORT = False + +try: + import zlib +except ImportError: + zlib = None + +try: + import zipfile + ZIP_SUPPORT = True +except ImportError: + ZIP_SUPPORT = find_executable('zip') + +class TestShutil(unittest.TestCase): + + def setUp(self): + super(TestShutil, self).setUp() + self.tempdirs = [] + + def tearDown(self): + super(TestShutil, self).tearDown() + while self.tempdirs: + d = self.tempdirs.pop() + shutil.rmtree(d, os.name in ('nt', 'cygwin')) + + def write_file(self, path, content='xxx'): + """Writes a file in the given path. + + + path can be a string or a sequence. + """ + if isinstance(path, (list, tuple)): + path = os.path.join(*path) + f = open(path, 'w') + try: + f.write(content) + finally: + f.close() + + def mkdtemp(self): + """Create a temporary directory that will be cleaned up. + + Returns the path of the directory. + """ + d = tempfile.mkdtemp() + self.tempdirs.append(d) + return d + + def test_rmtree_errors(self): + # filename is guaranteed not to exist + filename = tempfile.mktemp() + self.assertRaises(OSError, shutil.rmtree, filename) + + # See bug #1071513 for why we don't run this on cygwin + # and bug #1076467 for why we don't run this as root. + if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin' + and not (hasattr(os, 'geteuid') and os.geteuid() == 0)): + def test_on_error(self): + self.errorState = 0 + os.mkdir(TESTFN) + self.childpath = os.path.join(TESTFN, 'a') + f = open(self.childpath, 'w') + f.close() + old_dir_mode = os.stat(TESTFN).st_mode + old_child_mode = os.stat(self.childpath).st_mode + # Make unwritable. + os.chmod(self.childpath, stat.S_IREAD) + os.chmod(TESTFN, stat.S_IREAD) + + shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) + # Test whether onerror has actually been called. + self.assertEqual(self.errorState, 2, + "Expected call to onerror function did not happen.") + + # Make writable again. + os.chmod(TESTFN, old_dir_mode) + os.chmod(self.childpath, old_child_mode) + + # Clean up. + shutil.rmtree(TESTFN) + + def check_args_to_onerror(self, func, arg, exc): + # test_rmtree_errors deliberately runs rmtree + # on a directory that is chmod 400, which will fail. + # This function is run when shutil.rmtree fails. + # 99.9% of the time it initially fails to remove + # a file in the directory, so the first time through + # func is os.remove. + # However, some Linux machines running ZFS on + # FUSE experienced a failure earlier in the process + # at os.listdir. The first failure may legally + # be either. + if self.errorState == 0: + if func is os.remove: + self.assertEqual(arg, self.childpath) + else: + self.assertIs(func, os.listdir, + "func must be either os.remove or os.listdir") + self.assertEqual(arg, TESTFN) + self.assertTrue(issubclass(exc[0], OSError)) + self.errorState = 1 + else: + self.assertEqual(func, os.rmdir) + self.assertEqual(arg, TESTFN) + self.assertTrue(issubclass(exc[0], OSError)) + self.errorState = 2 + + def test_rmtree_dont_delete_file(self): + # When called on a file instead of a directory, don't delete it. + handle, path = tempfile.mkstemp() + os.fdopen(handle).close() + self.assertRaises(OSError, shutil.rmtree, path) + os.remove(path) + + def _write_data(self, path, data): + f = open(path, "w") + f.write(data) + f.close() + + def test_copytree_simple(self): + + def read_data(path): + f = open(path) + data = f.read() + f.close() + return data + + src_dir = tempfile.mkdtemp() + dst_dir = os.path.join(tempfile.mkdtemp(), 'destination') + self._write_data(os.path.join(src_dir, 'test.txt'), '123') + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + + try: + shutil.copytree(src_dir, dst_dir) + self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt'))) + self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir'))) + self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir', + 'test.txt'))) + actual = read_data(os.path.join(dst_dir, 'test.txt')) + self.assertEqual(actual, '123') + actual = read_data(os.path.join(dst_dir, 'test_dir', 'test.txt')) + self.assertEqual(actual, '456') + finally: + for path in ( + os.path.join(src_dir, 'test.txt'), + os.path.join(dst_dir, 'test.txt'), + os.path.join(src_dir, 'test_dir', 'test.txt'), + os.path.join(dst_dir, 'test_dir', 'test.txt'), + ): + if os.path.exists(path): + os.remove(path) + for path in (src_dir, + os.path.dirname(dst_dir) + ): + if os.path.exists(path): + shutil.rmtree(path) + + def test_copytree_with_exclude(self): + + def read_data(path): + f = open(path) + data = f.read() + f.close() + return data + + # creating data + join = os.path.join + exists = os.path.exists + src_dir = tempfile.mkdtemp() + try: + dst_dir = join(tempfile.mkdtemp(), 'destination') + self._write_data(join(src_dir, 'test.txt'), '123') + self._write_data(join(src_dir, 'test.tmp'), '123') + os.mkdir(join(src_dir, 'test_dir')) + self._write_data(join(src_dir, 'test_dir', 'test.txt'), '456') + os.mkdir(join(src_dir, 'test_dir2')) + self._write_data(join(src_dir, 'test_dir2', 'test.txt'), '456') + os.mkdir(join(src_dir, 'test_dir2', 'subdir')) + os.mkdir(join(src_dir, 'test_dir2', 'subdir2')) + self._write_data(join(src_dir, 'test_dir2', 'subdir', 'test.txt'), + '456') + self._write_data(join(src_dir, 'test_dir2', 'subdir2', 'test.py'), + '456') + + + # testing glob-like patterns + try: + patterns = shutil.ignore_patterns('*.tmp', 'test_dir2') + shutil.copytree(src_dir, dst_dir, ignore=patterns) + # checking the result: some elements should not be copied + self.assertTrue(exists(join(dst_dir, 'test.txt'))) + self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2'))) + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + try: + patterns = shutil.ignore_patterns('*.tmp', 'subdir*') + shutil.copytree(src_dir, dst_dir, ignore=patterns) + # checking the result: some elements should not be copied + self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + + # testing callable-style + try: + def _filter(src, names): + res = [] + for name in names: + path = os.path.join(src, name) + + if (os.path.isdir(path) and + path.split()[-1] == 'subdir'): + res.append(name) + elif os.path.splitext(path)[-1] in ('.py'): + res.append(name) + return res + + shutil.copytree(src_dir, dst_dir, ignore=_filter) + + # checking the result: some elements should not be copied + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2', + 'test.py'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) + + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + finally: + shutil.rmtree(src_dir) + shutil.rmtree(os.path.dirname(dst_dir)) + + @support.skip_unless_symlink + def test_dont_copy_file_onto_link_to_itself(self): + # bug 851123. + os.mkdir(TESTFN) + src = os.path.join(TESTFN, 'cheese') + dst = os.path.join(TESTFN, 'shop') + try: + f = open(src, 'w') + f.write('cheddar') + f.close() + + if hasattr(os, "link"): + os.link(src, dst) + self.assertRaises(shutil.Error, shutil.copyfile, src, dst) + f = open(src, 'r') + try: + self.assertEqual(f.read(), 'cheddar') + finally: + f.close() + os.remove(dst) + + # Using `src` here would mean we end up with a symlink pointing + # to TESTFN/TESTFN/cheese, while it should point at + # TESTFN/cheese. + os.symlink('cheese', dst) + self.assertRaises(shutil.Error, shutil.copyfile, src, dst) + f = open(src, 'r') + try: + self.assertEqual(f.read(), 'cheddar') + finally: + f.close() + os.remove(dst) + finally: + try: + shutil.rmtree(TESTFN) + except OSError: + pass + + @support.skip_unless_symlink + def test_rmtree_on_symlink(self): + # bug 1669. + os.mkdir(TESTFN) + try: + src = os.path.join(TESTFN, 'cheese') + dst = os.path.join(TESTFN, 'shop') + os.mkdir(src) + os.symlink(src, dst) + self.assertRaises(OSError, shutil.rmtree, dst) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + if hasattr(os, "mkfifo"): + # Issue #3002: copyfile and copytree block indefinitely on named pipes + def test_copyfile_named_pipe(self): + os.mkfifo(TESTFN) + try: + self.assertRaises(shutil.SpecialFileError, + shutil.copyfile, TESTFN, TESTFN2) + self.assertRaises(shutil.SpecialFileError, + shutil.copyfile, __file__, TESTFN) + finally: + os.remove(TESTFN) + + @unittest.skipUnless(hasattr(os, 'mkfifo'), 'requires os.mkfifo') + def test_copytree_named_pipe(self): + os.mkdir(TESTFN) + try: + subdir = os.path.join(TESTFN, "subdir") + os.mkdir(subdir) + pipe = os.path.join(subdir, "mypipe") + os.mkfifo(pipe) + try: + shutil.copytree(TESTFN, TESTFN2) + except shutil.Error, e: + errors = e.args[0] + self.assertEqual(len(errors), 1) + src, dst, error_msg = errors[0] + self.assertEqual("`%s` is a named pipe" % pipe, error_msg) + else: + self.fail("shutil.Error should have been raised") + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + shutil.rmtree(TESTFN2, ignore_errors=True) + + def test_copytree_special_func(self): + + src_dir = self.mkdtemp() + dst_dir = os.path.join(self.mkdtemp(), 'destination') + self._write_data(os.path.join(src_dir, 'test.txt'), '123') + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + + copied = [] + def _copy(src, dst): + copied.append((src, dst)) + + shutil.copytree(src_dir, dst_dir, copy_function=_copy) + self.assertEquals(len(copied), 2) + + @support.skip_unless_symlink + def test_copytree_dangling_symlinks(self): + + # a dangling symlink raises an error at the end + src_dir = self.mkdtemp() + dst_dir = os.path.join(self.mkdtemp(), 'destination') + os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt')) + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + self.assertRaises(Error, shutil.copytree, src_dir, dst_dir) + + # a dangling symlink is ignored with the proper flag + dst_dir = os.path.join(self.mkdtemp(), 'destination2') + shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True) + self.assertNotIn('test.txt', os.listdir(dst_dir)) + + # a dangling symlink is copied if symlinks=True + dst_dir = os.path.join(self.mkdtemp(), 'destination3') + shutil.copytree(src_dir, dst_dir, symlinks=True) + self.assertIn('test.txt', os.listdir(dst_dir)) + + @unittest.skipUnless(zlib, "requires zlib") + def test_make_tarball(self): + # creating something to tar + tmpdir = self.mkdtemp() + self.write_file([tmpdir, 'file1'], 'xxx') + self.write_file([tmpdir, 'file2'], 'xxx') + os.mkdir(os.path.join(tmpdir, 'sub')) + self.write_file([tmpdir, 'sub', 'file3'], 'xxx') + + tmpdir2 = self.mkdtemp() + unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0], + "source and target should be on same drive") + + base_name = os.path.join(tmpdir2, 'archive') + + # working with relative paths to avoid tar warnings + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(splitdrive(base_name)[1], '.') + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + tarball = base_name + '.tar.gz' + self.assertTrue(os.path.exists(tarball)) + + # trying an uncompressed one + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(splitdrive(base_name)[1], '.', compress=None) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + def _tarinfo(self, path): + tar = tarfile.open(path) + try: + names = tar.getnames() + names.sort() + return tuple(names) + finally: + tar.close() + + def _create_files(self): + # creating something to tar + tmpdir = self.mkdtemp() + dist = os.path.join(tmpdir, 'dist') + os.mkdir(dist) + self.write_file([dist, 'file1'], 'xxx') + self.write_file([dist, 'file2'], 'xxx') + os.mkdir(os.path.join(dist, 'sub')) + self.write_file([dist, 'sub', 'file3'], 'xxx') + os.mkdir(os.path.join(dist, 'sub2')) + tmpdir2 = self.mkdtemp() + base_name = os.path.join(tmpdir2, 'archive') + return tmpdir, tmpdir2, base_name + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(find_executable('tar') and find_executable('gzip'), + 'Need the tar command to run') + def test_tarfile_vs_tar(self): + tmpdir, tmpdir2, base_name = self._create_files() + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist') + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + tarball = base_name + '.tar.gz' + self.assertTrue(os.path.exists(tarball)) + + # now create another tarball using `tar` + tarball2 = os.path.join(tmpdir, 'archive2.tar.gz') + tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist'] + gzip_cmd = ['gzip', '-f9', 'archive2.tar'] + old_dir = os.getcwd() + old_stdout = sys.stdout + os.chdir(tmpdir) + sys.stdout = StringIO() + + try: + spawn(tar_cmd) + spawn(gzip_cmd) + finally: + os.chdir(old_dir) + sys.stdout = old_stdout + + self.assertTrue(os.path.exists(tarball2)) + # let's compare both tarballs + self.assertEquals(self._tarinfo(tarball), self._tarinfo(tarball2)) + + # trying an uncompressed one + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist', compress=None) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + # now for a dry_run + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist', compress=None, dry_run=True) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run') + def test_make_zipfile(self): + # creating something to tar + tmpdir = self.mkdtemp() + self.write_file([tmpdir, 'file1'], 'xxx') + self.write_file([tmpdir, 'file2'], 'xxx') + + tmpdir2 = self.mkdtemp() + base_name = os.path.join(tmpdir2, 'archive') + _make_zipfile(base_name, tmpdir) + + # check if the compressed tarball was created + tarball = base_name + '.zip' + self.assertTrue(os.path.exists(tarball)) + + + def test_make_archive(self): + tmpdir = self.mkdtemp() + base_name = os.path.join(tmpdir, 'archive') + self.assertRaises(ValueError, make_archive, base_name, 'xxx') + + @unittest.skipUnless(zlib, "Requires zlib") + def test_make_archive_owner_group(self): + # testing make_archive with owner and group, with various combinations + # this works even if there's not gid/uid support + if UID_GID_SUPPORT: + group = grp.getgrgid(0)[0] + owner = pwd.getpwuid(0)[0] + else: + group = owner = 'root' + + base_dir, root_dir, base_name = self._create_files() + base_name = os.path.join(self.mkdtemp() , 'archive') + res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner, + group=group) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'zip', root_dir, base_dir) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'tar', root_dir, base_dir, + owner=owner, group=group) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'tar', root_dir, base_dir, + owner='kjhkjhkjg', group='oihohoh') + self.assertTrue(os.path.exists(res)) + + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") + def test_tarfile_root_owner(self): + tmpdir, tmpdir2, base_name = self._create_files() + old_dir = os.getcwd() + os.chdir(tmpdir) + group = grp.getgrgid(0)[0] + owner = pwd.getpwuid(0)[0] + try: + archive_name = _make_tarball(base_name, 'dist', compress=None, + owner=owner, group=group) + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + self.assertTrue(os.path.exists(archive_name)) + + # now checks the rights + archive = tarfile.open(archive_name) + try: + for member in archive.getmembers(): + self.assertEquals(member.uid, 0) + self.assertEquals(member.gid, 0) + finally: + archive.close() + + def test_make_archive_cwd(self): + current_dir = os.getcwd() + def _breaks(*args, **kw): + raise RuntimeError() + + register_archive_format('xxx', _breaks, [], 'xxx file') + try: + try: + make_archive('xxx', 'xxx', root_dir=self.mkdtemp()) + except Exception: + pass + self.assertEquals(os.getcwd(), current_dir) + finally: + unregister_archive_format('xxx') + + def test_register_archive_format(self): + + self.assertRaises(TypeError, register_archive_format, 'xxx', 1) + self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x, + 1) + self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x, + [(1, 2), (1, 2, 3)]) + + register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file') + formats = [name for name, params in get_archive_formats()] + self.assertIn('xxx', formats) + + unregister_archive_format('xxx') + formats = [name for name, params in get_archive_formats()] + self.assertNotIn('xxx', formats) + + def _compare_dirs(self, dir1, dir2): + # check that dir1 and dir2 are equivalent, + # return the diff + diff = [] + for root, dirs, files in os.walk(dir1): + for file_ in files: + path = os.path.join(root, file_) + target_path = os.path.join(dir2, os.path.split(path)[-1]) + if not os.path.exists(target_path): + diff.append(file_) + return diff + + @unittest.skipUnless(zlib, "Requires zlib") + def test_unpack_archive(self): + formats = ['tar', 'gztar', 'zip'] + if BZ2_SUPPORTED: + formats.append('bztar') + + for format in formats: + tmpdir = self.mkdtemp() + base_dir, root_dir, base_name = self._create_files() + tmpdir2 = self.mkdtemp() + filename = make_archive(base_name, format, root_dir, base_dir) + + # let's try to unpack it now + unpack_archive(filename, tmpdir2) + diff = self._compare_dirs(tmpdir, tmpdir2) + self.assertEquals(diff, []) + + def test_unpack_registery(self): + + formats = get_unpack_formats() + + def _boo(filename, extract_dir, extra): + self.assertEquals(extra, 1) + self.assertEquals(filename, 'stuff.boo') + self.assertEquals(extract_dir, 'xx') + + register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)]) + unpack_archive('stuff.boo', 'xx') + + # trying to register a .boo unpacker again + self.assertRaises(RegistryError, register_unpack_format, 'Boo2', + ['.boo'], _boo) + + # should work now + unregister_unpack_format('Boo') + register_unpack_format('Boo2', ['.boo'], _boo) + self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats()) + self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats()) + + # let's leave a clean state + unregister_unpack_format('Boo2') + self.assertEquals(get_unpack_formats(), formats) + + +class TestMove(unittest.TestCase): + + def setUp(self): + filename = "foo" + self.src_dir = tempfile.mkdtemp() + self.dst_dir = tempfile.mkdtemp() + self.src_file = os.path.join(self.src_dir, filename) + self.dst_file = os.path.join(self.dst_dir, filename) + # Try to create a dir in the current directory, hoping that it is + # not located on the same filesystem as the system tmp dir. + try: + self.dir_other_fs = tempfile.mkdtemp( + dir=os.path.dirname(__file__)) + self.file_other_fs = os.path.join(self.dir_other_fs, + filename) + except OSError: + self.dir_other_fs = None + f = open(self.src_file, "wb") + try: + f.write("spam") + finally: + f.close() + + def tearDown(self): + for d in (self.src_dir, self.dst_dir, self.dir_other_fs): + try: + if d: + shutil.rmtree(d) + except: + pass + + def _check_move_file(self, src, dst, real_dst): + f = open(src, "rb") + try: + contents = f.read() + finally: + f.close() + + shutil.move(src, dst) + f = open(real_dst, "rb") + try: + self.assertEqual(contents, f.read()) + finally: + f.close() + + self.assertFalse(os.path.exists(src)) + + def _check_move_dir(self, src, dst, real_dst): + contents = sorted(os.listdir(src)) + shutil.move(src, dst) + self.assertEqual(contents, sorted(os.listdir(real_dst))) + self.assertFalse(os.path.exists(src)) + + def test_move_file(self): + # Move a file to another location on the same filesystem. + self._check_move_file(self.src_file, self.dst_file, self.dst_file) + + def test_move_file_to_dir(self): + # Move a file inside an existing dir on the same filesystem. + self._check_move_file(self.src_file, self.dst_dir, self.dst_file) + + def test_move_file_other_fs(self): + # Move a file to an existing dir on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_file(self.src_file, self.file_other_fs, + self.file_other_fs) + + def test_move_file_to_dir_other_fs(self): + # Move a file to another location on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_file(self.src_file, self.dir_other_fs, + self.file_other_fs) + + def test_move_dir(self): + # Move a dir to another location on the same filesystem. + dst_dir = tempfile.mktemp() + try: + self._check_move_dir(self.src_dir, dst_dir, dst_dir) + finally: + try: + shutil.rmtree(dst_dir) + except: + pass + + def test_move_dir_other_fs(self): + # Move a dir to another location on another filesystem. + if not self.dir_other_fs: + # skip + return + dst_dir = tempfile.mktemp(dir=self.dir_other_fs) + try: + self._check_move_dir(self.src_dir, dst_dir, dst_dir) + finally: + try: + shutil.rmtree(dst_dir) + except: + pass + + def test_move_dir_to_dir(self): + # Move a dir inside an existing dir on the same filesystem. + self._check_move_dir(self.src_dir, self.dst_dir, + os.path.join(self.dst_dir, os.path.basename(self.src_dir))) + + def test_move_dir_to_dir_other_fs(self): + # Move a dir inside an existing dir on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_dir(self.src_dir, self.dir_other_fs, + os.path.join(self.dir_other_fs, os.path.basename(self.src_dir))) + + def test_existing_file_inside_dest_dir(self): + # A file with the same name inside the destination dir already exists. + f = open(self.dst_file, "wb") + try: + pass + finally: + f.close() + self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir) + + def test_dont_move_dir_in_itself(self): + # Moving a dir inside itself raises an Error. + dst = os.path.join(self.src_dir, "bar") + self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst) + + def test_destinsrc_false_negative(self): + os.mkdir(TESTFN) + try: + for src, dst in [('srcdir', 'srcdir/dest')]: + src = os.path.join(TESTFN, src) + dst = os.path.join(TESTFN, dst) + self.assertTrue(shutil._destinsrc(src, dst), + msg='_destinsrc() wrongly concluded that ' + 'dst (%s) is not in src (%s)' % (dst, src)) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + def test_destinsrc_false_positive(self): + os.mkdir(TESTFN) + try: + for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]: + src = os.path.join(TESTFN, src) + dst = os.path.join(TESTFN, dst) + self.assertFalse(shutil._destinsrc(src, dst), + msg='_destinsrc() wrongly concluded that ' + 'dst (%s) is in src (%s)' % (dst, src)) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + +class TestCopyFile(unittest.TestCase): + + _delete = False + + class Faux(object): + _entered = False + _exited_with = None + _raised = False + + def __init__(self, raise_in_exit=False, suppress_at_exit=True): + self._raise_in_exit = raise_in_exit + self._suppress_at_exit = suppress_at_exit + + def read(self, *args): + return '' + + def __enter__(self): + self._entered = True + + def __exit__(self, exc_type, exc_val, exc_tb): + self._exited_with = exc_type, exc_val, exc_tb + if self._raise_in_exit: + self._raised = True + raise IOError("Cannot close") + return self._suppress_at_exit + + def tearDown(self): + if self._delete: + del shutil.open + + def _set_shutil_open(self, func): + shutil.open = func + self._delete = True + + def test_w_source_open_fails(self): + def _open(filename, mode='r'): + if filename == 'srcfile': + raise IOError('Cannot open "srcfile"') + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile') + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_dest_open_fails(self): + + srcfile = self.Faux() + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + raise IOError('Cannot open "destfile"') + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + shutil.copyfile('srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(srcfile._exited_with[0] is IOError) + self.assertEqual(srcfile._exited_with[1].args, + ('Cannot open "destfile"',)) + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_dest_close_fails(self): + + srcfile = self.Faux() + destfile = self.Faux(True) + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + return destfile + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + shutil.copyfile('srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(destfile._entered) + self.assertTrue(destfile._raised) + self.assertTrue(srcfile._exited_with[0] is IOError) + self.assertEqual(srcfile._exited_with[1].args, + ('Cannot close',)) + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_source_close_fails(self): + + srcfile = self.Faux(True) + destfile = self.Faux() + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + return destfile + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + self.assertRaises(IOError, + shutil.copyfile, 'srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(destfile._entered) + self.assertFalse(destfile._raised) + self.assertTrue(srcfile._exited_with[0] is None) + self.assertTrue(srcfile._raised) + + +def test_suite(): + suite = unittest.TestSuite() + load = unittest.defaultTestLoader.loadTestsFromTestCase + suite.addTest(load(TestCopyFile)) + suite.addTest(load(TestMove)) + suite.addTest(load(TestShutil)) + return suite + + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/distutils2/_backport/tests/test_sysconfig.py b/distutils2/_backport/tests/test_sysconfig.py --- a/distutils2/_backport/tests/test_sysconfig.py +++ b/distutils2/_backport/tests/test_sysconfig.py @@ -4,7 +4,7 @@ import sys import subprocess import shutil -from copy import copy, deepcopy +from copy import copy from ConfigParser import RawConfigParser from StringIO import StringIO @@ -15,13 +15,9 @@ get_scheme_names, _main, _SCHEMES) from distutils2.tests import unittest -from distutils2.tests.support import EnvironGuard +from distutils2.tests.support import EnvironGuard, skip_unless_symlink from test.test_support import TESTFN, unlink -try: - from test.test_support import skip_unless_symlink -except ImportError: - skip_unless_symlink = unittest.skip( - 'requires test.test_support.skip_unless_symlink') + class TestSysConfig(EnvironGuard, unittest.TestCase): diff --git a/distutils2/command/cmd.py b/distutils2/command/cmd.py --- a/distutils2/command/cmd.py +++ b/distutils2/command/cmd.py @@ -165,7 +165,10 @@ header = "command options for '%s':" % self.get_command_name() self.announce(indent + header, level=logging.INFO) indent = indent + " " + negative_opt = getattr(self, 'negative_opt', ()) for (option, _, _) in self.user_options: + if option in negative_opt: + continue option = option.replace('-', '_') if option[-1] == "=": option = option[:-1] diff --git a/distutils2/tests/support.py b/distutils2/tests/support.py --- a/distutils2/tests/support.py +++ b/distutils2/tests/support.py @@ -17,10 +17,11 @@ super(SomeTestCase, self).setUp() ... # other setup code -Read each class' docstring to see its purpose and usage. +Also provided is a DummyCommand class, useful to mock commands in the +tests of another command that needs them, a create_distribution function +and a skip_unless_symlink decorator. -Also provided is a DummyCommand class, useful to mock commands in the -tests of another command that needs them (see docstring). +Each class or function has a docstring to explain its purpose and usage. """ import os @@ -35,7 +36,8 @@ from distutils2.tests import unittest __all__ = ['LoggingCatcher', 'WarningsCatcher', 'TempdirManager', - 'EnvironGuard', 'DummyCommand', 'unittest'] + 'EnvironGuard', 'DummyCommand', 'unittest', 'create_distribution', + 'skip_unless_symlink'] class LoggingCatcher(object): @@ -135,7 +137,7 @@ finally: f.close() - def create_dist(self, pkg_name='foo', **kw): + def create_dist(self, **kw): """Create a stub distribution object and files. This function creates a Distribution instance (use keyword arguments @@ -143,17 +145,19 @@ (currently an empty directory). It returns the path to the directory and the Distribution instance. - You can use TempdirManager.write_file to write any file in that + You can use self.write_file to write any file in that directory, e.g. setup scripts or Python modules. """ # Late import so that third parties can import support without # loading a ton of distutils2 modules in memory. from distutils2.dist import Distribution + if 'name' not in kw: + kw['name'] = 'foo' tmp_dir = self.mkdtemp() - pkg_dir = os.path.join(tmp_dir, pkg_name) - os.mkdir(pkg_dir) + project_dir = os.path.join(tmp_dir, kw['name']) + os.mkdir(project_dir) dist = Distribution(attrs=kw) - return pkg_dir, dist + return project_dir, dist class EnvironGuard(object): @@ -211,3 +215,9 @@ d.parse_command_line() return d + +try: + from test.test_support import skip_unless_symlink +except ImportError: + skip_unless_symlink = unittest.skip( + 'requires test.test_support.skip_unless_symlink') diff --git a/distutils2/tests/test_command_install_dist.py b/distutils2/tests/test_command_install_dist.py --- a/distutils2/tests/test_command_install_dist.py +++ b/distutils2/tests/test_command_install_dist.py @@ -180,8 +180,8 @@ cmd.user = 'user' self.assertRaises(DistutilsOptionError, cmd.finalize_options) - def test_record(self): - + def test_old_record(self): + # test pre-PEP 376 --record option (outside dist-info dir) install_dir = self.mkdtemp() pkgdir, dist = self.create_dist() @@ -189,11 +189,11 @@ cmd = install_dist(dist) dist.command_obj['install_dist'] = cmd cmd.root = install_dir - cmd.record = os.path.join(pkgdir, 'RECORD') + cmd.record = os.path.join(pkgdir, 'filelist') cmd.ensure_finalized() cmd.run() - # let's check the RECORD file was created with four + # let's check the record file was created with four # lines, one for each .dist-info entry: METADATA, # INSTALLER, REQUSTED, RECORD f = open(cmd.record) diff --git a/docs/source/library/distutils2.tests.pypi_server.rst b/docs/source/library/distutils2.tests.pypi_server.rst --- a/docs/source/library/distutils2.tests.pypi_server.rst +++ b/docs/source/library/distutils2.tests.pypi_server.rst @@ -77,6 +77,7 @@ @use_pypi_server() def test_somthing(self, server): # your tests goes here + ... The decorator will instantiate the server for you, and run and stop it just before and after your method call. You also can pass the server initializer, @@ -85,4 +86,4 @@ class SampleTestCase(TestCase): @use_pypi_server("test_case_name") def test_something(self, server): - # something + ... diff --git a/docs/source/library/pkgutil.rst b/docs/source/library/pkgutil.rst --- a/docs/source/library/pkgutil.rst +++ b/docs/source/library/pkgutil.rst @@ -4,77 +4,204 @@ .. module:: pkgutil :synopsis: Utilities to support packages. -.. TODO Follow the reST conventions used in the stdlib +This module provides utilities to manipulate packages: support for the +Importer protocol defined in :PEP:`302` and implementation of the API +described in :PEP:`376` to work with the database of installed Python +distributions. -This module provides functions to manipulate packages, as well as -the necessary functions to provide support for the "Importer Protocol" as -described in :PEP:`302` and for working with the database of installed Python -distributions which is specified in :PEP:`376`. In addition to the functions -required in :PEP:`376`, back support for older ``.egg`` and ``.egg-info`` -distributions is provided as well. These distributions are represented by the -class :class:`~distutils2._backport.pkgutil.EggInfoDistribution` and most -functions provide an extra argument ``use_egg_info`` which indicates if -they should consider these old styled distributions. This document details -first the functions and classes available and then presents several use cases. - +Import system utilities +----------------------- .. function:: extend_path(path, name) - Extend the search path for the modules which comprise a package. Intended use is - to place the following code in a package's :file:`__init__.py`:: + Extend the search path for the modules which comprise a package. Intended + use is to place the following code in a package's :file:`__init__.py`:: from pkgutil import extend_path __path__ = extend_path(__path__, __name__) - This will add to the package's ``__path__`` all subdirectories of directories on - ``sys.path`` named after the package. This is useful if one wants to distribute - different parts of a single logical package as multiple directories. + This will add to the package's ``__path__`` all subdirectories of directories + on :data:`sys.path` named after the package. This is useful if one wants to + distribute different parts of a single logical package as multiple + directories. - It also looks for :file:`\*.pkg` files beginning where ``*`` matches the *name* - argument. This feature is similar to :file:`\*.pth` files (see the :mod:`site` - module for more information), except that it doesn't special-case lines starting - with ``import``. A :file:`\*.pkg` file is trusted at face value: apart from - checking for duplicates, all entries found in a :file:`\*.pkg` file are added to - the path, regardless of whether they exist on the filesystem. (This is a - feature.) + It also looks for :file:`\*.pkg` files beginning where ``*`` matches the + *name* argument. This feature is similar to :file:`\*.pth` files (see the + :mod:`site` module for more information), except that it doesn't special-case + lines starting with ``import``. A :file:`\*.pkg` file is trusted at face + value: apart from checking for duplicates, all entries found in a + :file:`\*.pkg` file are added to the path, regardless of whether they exist + on the filesystem. (This is a feature.) If the input path is not a list (as is the case for frozen packages) it is returned unchanged. The input path is not modified; an extended copy is returned. Items are only appended to the copy at the end. - It is assumed that ``sys.path`` is a sequence. Items of ``sys.path`` that are - not strings referring to existing directories are ignored. Unicode items on - ``sys.path`` that cause errors when used as filenames may cause this function - to raise an exception (in line with :func:`os.path.isdir` behavior). + It is assumed that :data:`sys.path` is a sequence. Items of :data:`sys.path` + that are not strings referring to existing directories are ignored. Unicode + items on :data:`sys.path` that cause errors when used as filenames may cause + this function to raise an exception (in line with :func:`os.path.isdir` + behavior). + + +.. class:: ImpImporter(dirname=None) + + :pep:`302` Importer that wraps Python's "classic" import algorithm. + + If *dirname* is a string, a :pep:`302` importer is created that searches that + directory. If *dirname* is ``None``, a :pep:`302` importer is created that + searches the current :data:`sys.path`, plus any modules that are frozen or + built-in. + + Note that :class:`ImpImporter` does not currently support being used by + placement on :data:`sys.meta_path`. + + +.. class:: ImpLoader(fullname, file, filename, etc) + + :pep:`302` Loader that wraps Python's "classic" import algorithm. + + +.. function:: find_loader(fullname) + + Find a :pep:`302` "loader" object for *fullname*. + + If *fullname* contains dots, path must be the containing package's + ``__path__``. Returns ``None`` if the module cannot be found or imported. + This function uses :func:`iter_importers`, and is thus subject to the same + limitations regarding platform-specific special import locations such as the + Windows registry. + + +.. function:: get_importer(path_item) + + Retrieve a :pep:`302` importer for the given *path_item*. + + The returned importer is cached in :data:`sys.path_importer_cache` if it was + newly created by a path hook. + + If there is no importer, a wrapper around the basic import machinery is + returned. This wrapper is never inserted into the importer cache (None is + inserted instead). + + The cache (or part of it) can be cleared manually if a rescan of + :data:`sys.path_hooks` is necessary. + + +.. function:: get_loader(module_or_name) + + Get a :pep:`302` "loader" object for *module_or_name*. + + If the module or package is accessible via the normal import mechanism, a + wrapper around the relevant part of that machinery is returned. Returns + ``None`` if the module cannot be found or imported. If the named module is + not already imported, its containing package (if any) is imported, in order + to establish the package ``__path__``. + + This function uses :func:`iter_importers`, and is thus subject to the same + limitations regarding platform-specific special import locations such as the + Windows registry. + + +.. function:: iter_importers(fullname='') + + Yield :pep:`302` importers for the given module name. + + If fullname contains a '.', the importers will be for the package containing + fullname, otherwise they will be importers for :data:`sys.meta_path`, + :data:`sys.path`, and Python's "classic" import machinery, in that order. If + the named module is in a package, that package is imported as a side effect + of invoking this function. + + Non-:pep:`302` mechanisms (e.g. the Windows registry) used by the standard + import machinery to find files in alternative locations are partially + supported, but are searched *after* :data:`sys.path`. Normally, these + locations are searched *before* :data:`sys.path`, preventing :data:`sys.path` + entries from shadowing them. + + For this to cause a visible difference in behaviour, there must be a module + or package name that is accessible via both :data:`sys.path` and one of the + non-:pep:`302` file system mechanisms. In this case, the emulation will find + the former version, while the builtin import mechanism will find the latter. + + Items of the following types can be affected by this discrepancy: + ``imp.C_EXTENSION``, ``imp.PY_SOURCE``, ``imp.PY_COMPILED``, + ``imp.PKG_DIRECTORY``. + + +.. function:: iter_modules(path=None, prefix='') + + Yields ``(module_loader, name, ispkg)`` for all submodules on *path*, or, if + path is ``None``, all top-level modules on :data:`sys.path`. + + *path* should be either ``None`` or a list of paths to look for modules in. + + *prefix* is a string to output on the front of every module name on output. + + +.. function:: walk_packages(path=None, prefix='', onerror=None) + + Yields ``(module_loader, name, ispkg)`` for all modules recursively on + *path*, or, if path is ``None``, all accessible modules. + + *path* should be either ``None`` or a list of paths to look for modules in. + + *prefix* is a string to output on the front of every module name on output. + + Note that this function must import all *packages* (*not* all modules!) on + the given *path*, in order to access the ``__path__`` attribute to find + submodules. + + *onerror* is a function which gets called with one argument (the name of the + package which was being imported) if any exception occurs while trying to + import a package. If no *onerror* function is supplied, :exc:`ImportError`\s + are caught and ignored, while all other exceptions are propagated, + terminating the search. + + Examples:: + + # list all modules python can access + walk_packages() + + # list all submodules of ctypes + walk_packages(ctypes.__path__, ctypes.__name__ + '.') + .. function:: get_data(package, resource) Get a resource from a package. - This is a wrapper for the :pep:`302` loader :func:`get_data` API. The package - argument should be the name of a package, in standard module format - (foo.bar). The resource argument should be in the form of a relative - filename, using ``/`` as the path separator. The parent directory name + This is a wrapper for the :pep:`302` loader :func:`get_data` API. The + *package* argument should be the name of a package, in standard module format + (``foo.bar``). The *resource* argument should be in the form of a relative + filename, using ``/`` as the path separator. The parent directory name ``..`` is not allowed, and nor is a rooted name (starting with a ``/``). - The function returns a binary string that is the contents of the - specified resource. + The function returns a binary string that is the contents of the specified + resource. For packages located in the filesystem, which have already been imported, this is the rough equivalent of:: - d = os.path.dirname(sys.modules[package].__file__) - data = open(os.path.join(d, resource), 'rb').read() + d = os.path.dirname(sys.modules[package].__file__) + data = open(os.path.join(d, resource), 'rb').read() If the package cannot be located or loaded, or it uses a :pep:`302` loader - which does not support :func:`get_data`, then None is returned. + which does not support :func:`get_data`, then ``None`` is returned. -API Reference -============= +Installed distributions database +-------------------------------- -.. automodule:: distutils2._backport.pkgutil - :members: +Installed Python distributions are represented by instances of +:class:`~distutils2._backport.pkgutil.Distribution`, or its subclass +:class:`~distutils2._backport.pkgutil.EggInfoDistribution` for legacy ``.egg`` +and ``.egg-info`` formats). Most functions also provide an extra argument +``use_egg_info`` to take legacy distributions into account. + +.. TODO write docs here, don't rely on automodule + classes: Distribution and descendents + functions: provides, obsoletes, replaces, etc. Caching +++++++ @@ -86,11 +213,10 @@ :func:`~distutils2._backport.pkgutil.clear_cache`. +Examples +-------- -Example Usage -============= - -Print All Information About a Distribution +Print all information about a distribution ++++++++++++++++++++++++++++++++++++++++++ Given a path to a ``.dist-info`` distribution, we shall print out all @@ -182,7 +308,7 @@ ===== * It was installed as a dependency -Find Out Obsoleted Distributions +Find out obsoleted distributions ++++++++++++++++++++++++++++++++ Now, we take tackle a different problem, we are interested in finding out -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: cache need to take care of paths Message-ID: tarek.ziade pushed 3354ef84bddb to distutils2: http://hg.python.org/distutils2/rev/3354ef84bddb changeset: 946:3354ef84bddb user: Gael Pasgrimaud date: Sat Jan 29 17:25:01 2011 +0100 summary: cache need to take care of paths files: distutils2/_backport/pkgutil.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -1031,7 +1031,7 @@ for dist in _yield_distributions(True, use_egg_info, paths): yield dist else: - _generate_cache(use_egg_info) + _generate_cache(use_egg_info, paths) for dist in _cache_path.itervalues(): yield dist @@ -1063,7 +1063,7 @@ if dist.name == name: return dist else: - _generate_cache(use_egg_info) + _generate_cache(use_egg_info, paths) if name in _cache_name: return _cache_name[name][0] -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: Branch merge Message-ID: tarek.ziade pushed 3bb80edf7d81 to distutils2: http://hg.python.org/distutils2/rev/3bb80edf7d81 changeset: 943:3bb80edf7d81 parent: 942:b8f163d9fcd7 parent: 940:b1ce3723fe28 user: ?ric Araujo date: Sat Jan 29 17:12:02 2011 +0100 summary: Branch merge files: distutils2/_backport/shutil.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -1,24 +1,19 @@ """Utilities to support packages.""" -# NOTE: This module must remain compatible with Python 2.3, as it is shared -# by setuptools for distribution with Python 2.3 and up. - import os import sys import imp -import os.path +import re +import warnings from csv import reader as csv_reader from types import ModuleType from distutils2.errors import DistutilsError from distutils2.metadata import DistributionMetadata from distutils2.version import suggest_normalized_version, VersionPredicate -import zipimport try: import cStringIO as StringIO except ImportError: import StringIO -import re -import warnings __all__ = [ @@ -28,10 +23,14 @@ 'Distribution', 'EggInfoDistribution', 'distinfo_dirname', 'get_distributions', 'get_distribution', 'get_file_users', 'provides_distribution', 'obsoletes_distribution', - 'enable_cache', 'disable_cache', 'clear_cache' + 'enable_cache', 'disable_cache', 'clear_cache', ] +########################## +# PEP 302 Implementation # +########################## + def read_code(stream): # This helper is needed in order for the :pep:`302` emulation to # correctly handle compiled files @@ -41,7 +40,7 @@ if magic != imp.get_magic(): return None - stream.read(4) # Skip timestamp + stream.read(4) # Skip timestamp return marshal.load(stream) @@ -173,7 +172,6 @@ #@simplegeneric def iter_importer_modules(importer, prefix=''): - "" if not hasattr(importer, 'iter_modules'): return [] return importer.iter_modules(prefix) @@ -331,9 +329,9 @@ def get_filename(self, fullname=None): fullname = self._fix_name(fullname) mod_type = self.etc[2] - if self.etc[2] == imp.PKG_DIRECTORY: + if mod_type == imp.PKG_DIRECTORY: return self._get_delegate().get_filename() - elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION): + elif mod_type in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION): return self.filename return None @@ -432,7 +430,8 @@ import mechanism will find the latter. Items of the following types can be affected by this discrepancy: - ``imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY`` + :data:`imp.C_EXTENSION`, :data:`imp.PY_SOURCE`, :data:`imp.PY_COMPILED`, + :data:`imp.PKG_DIRECTORY` """ if fullname.startswith('.'): raise ImportError("Relative module names not supported") @@ -534,13 +533,13 @@ # frozen package. Return the path unchanged in that case. return path - pname = os.path.join(*name.split('.')) # Reconstitute as relative path + pname = os.path.join(*name.split('.')) # Reconstitute as relative path # Just in case os.extsep != '.' sname = os.extsep.join(name.split('.')) sname_pkg = sname + os.extsep + "pkg" init_py = "__init__" + os.extsep + "py" - path = path[:] # Start with a copy of the existing path + path = path[:] # Start with a copy of the existing path for dir in sys.path: if not isinstance(dir, basestring) or not os.path.isdir(dir): @@ -565,7 +564,7 @@ line = line.rstrip('\n') if not line or line.startswith('#'): continue - path.append(line) # Don't check for existence! + path.append(line) # Don't check for existence! f.close() return path @@ -609,6 +608,7 @@ resource_name = os.path.join(*parts) return loader.get_data(resource_name) + ########################## # PEP 376 Implementation # ########################## @@ -616,12 +616,12 @@ DIST_FILES = ('INSTALLER', 'METADATA', 'RECORD', 'REQUESTED',) # Cache -_cache_name = {} # maps names to Distribution instances -_cache_name_egg = {} # maps names to EggInfoDistribution instances -_cache_path = {} # maps paths to Distribution instances -_cache_path_egg = {} # maps paths to EggInfoDistribution instances -_cache_generated = False # indicates if .dist-info distributions are cached -_cache_generated_egg = False # indicates if .dist-info and .egg are cached +_cache_name = {} # maps names to Distribution instances +_cache_name_egg = {} # maps names to EggInfoDistribution instances +_cache_path = {} # maps paths to Distribution instances +_cache_path_egg = {} # maps paths to EggInfoDistribution instances +_cache_generated = False # indicates if .dist-info distributions are cached +_cache_generated_egg = False # indicates if .dist-info and .egg are cached _cache_enabled = True @@ -636,6 +636,7 @@ _cache_enabled = True + def disable_cache(): """ Disables the internal cache. @@ -647,9 +648,10 @@ _cache_enabled = False + def clear_cache(): """ Clears the internal cache. """ - global _cache_name, _cache_name_egg, cache_path, _cache_path_egg, \ + global _cache_name, _cache_name_egg, _cache_path, _cache_path_egg, \ _cache_generated, _cache_generated_egg _cache_name = {} @@ -872,7 +874,8 @@ if isinstance(strs, basestring): for s in strs.splitlines(): s = s.strip() - if s and not s.startswith('#'): # skip blank lines/comments + # skip blank lines/comments + if s and not s.startswith('#'): yield s else: for ss in strs: @@ -890,6 +893,7 @@ except IOError: requires = None else: + # FIXME handle the case where zipfile is not available zipf = zipimport.zipimporter(path) fileobj = StringIO.StringIO(zipf.get_data('EGG-INFO/PKG-INFO')) self.metadata = DistributionMetadata(fileobj=fileobj) @@ -952,7 +956,7 @@ version = match.group('first') if match.group('rest'): version += match.group('rest') - version = version.replace(' ', '') # trim spaces + version = version.replace(' ', '') # trim spaces if version is None: reqs.append(name) else: @@ -982,12 +986,6 @@ __hash__ = object.__hash__ -def _normalize_dist_name(name): - """Returns a normalized name from the given *name*. - :rtype: string""" - return name.replace('-', '_') - - def distinfo_dirname(name, version): """ The *name* and *version* parameters are converted into their @@ -1007,7 +1005,7 @@ :returns: directory name :rtype: string""" file_extension = '.dist-info' - name = _normalize_dist_name(name) + name = name.replace('-', '_') normalized_version = suggest_normalized_version(version) # Because this is a lookup procedure, something will be returned even if # it is a version that cannot be normalized @@ -1148,7 +1146,7 @@ raise DistutilsError(('Distribution %s has invalid ' + 'provides field: %s') \ % (dist.name, p)) - p_ver = p_ver[1:-1] # trim off the parenthesis + p_ver = p_ver[1:-1] # trim off the parenthesis if p_name == name and predicate.match(p_ver): yield dist break diff --git a/distutils2/_backport/shutil.py b/distutils2/_backport/shutil.py --- a/distutils2/_backport/shutil.py +++ b/distutils2/_backport/shutil.py @@ -1,4 +1,4 @@ -"""Utility functions for copying files and directory trees. +"""Utility functions for copying and archiving files and directory trees. XXX The functions here don't copy the resource fork or other metadata on Mac. @@ -9,7 +9,13 @@ import stat from os.path import abspath import fnmatch -from warnings import warn +import errno + +try: + import bz2 + _BZ2_SUPPORTED = True +except ImportError: + _BZ2_SUPPORTED = False try: from pwd import getpwnam @@ -21,9 +27,12 @@ except ImportError: getgrnam = None -__all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2", - "copytree","move","rmtree","Error", "SpecialFileError", - "ExecError","make_archive"] +__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", + "copytree", "move", "rmtree", "Error", "SpecialFileError", + "ExecError", "make_archive", "get_archive_formats", + "register_archive_format", "unregister_archive_format", + "get_unpack_formats", "register_unpack_format", + "unregister_unpack_format", "unpack_archive"] class Error(EnvironmentError): pass @@ -35,6 +44,14 @@ class ExecError(EnvironmentError): """Raised when a command could not be executed""" +class ReadError(EnvironmentError): + """Raised when an archive cannot be read""" + +class RegistryError(Exception): + """Raised when a registery operation with the archiving + and unpacking registeries fails""" + + try: WindowsError except NameError: @@ -50,7 +67,7 @@ def _samefile(src, dst): # Macintosh, Unix. - if hasattr(os.path,'samefile'): + if hasattr(os.path, 'samefile'): try: return os.path.samefile(src, dst) except OSError: @@ -63,10 +80,8 @@ def copyfile(src, dst): """Copy data from src to dst""" if _samefile(src, dst): - raise Error, "`%s` and `%s` are the same file" % (src, dst) + raise Error("`%s` and `%s` are the same file" % (src, dst)) - fsrc = None - fdst = None for fn in [src, dst]: try: st = os.stat(fn) @@ -77,15 +92,16 @@ # XXX What about other special files? (sockets, devices...) if stat.S_ISFIFO(st.st_mode): raise SpecialFileError("`%s` is a named pipe" % fn) + + fsrc = open(src, 'rb') try: - fsrc = open(src, 'rb') fdst = open(dst, 'wb') - copyfileobj(fsrc, fdst) + try: + copyfileobj(fsrc, fdst) + finally: + fdst.close() finally: - if fdst: - fdst.close() - if fsrc: - fsrc.close() + fsrc.close() def copymode(src, dst): """Copy mode bits from src to dst""" @@ -103,8 +119,12 @@ if hasattr(os, 'chmod'): os.chmod(dst, mode) if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): - os.chflags(dst, st.st_flags) - + try: + os.chflags(dst, st.st_flags) + except OSError, why: + if (not hasattr(errno, 'EOPNOTSUPP') or + why.errno != errno.EOPNOTSUPP): + raise def copy(src, dst): """Copy data and mode bits ("cp src dst"). @@ -140,8 +160,9 @@ return set(ignored_names) return _ignore_patterns -def copytree(src, dst, symlinks=False, ignore=None): - """Recursively copy a directory tree using copy2(). +def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, + ignore_dangling_symlinks=False): + """Recursively copy a directory tree. The destination directory must not already exist. If exception(s) occur, an Error is raised with a list of reasons. @@ -149,7 +170,13 @@ If the optional symlinks flag is true, symbolic links in the source tree result in symbolic links in the destination tree; if it is false, the contents of the files pointed to by symbolic - links are copied. + links are copied. If the file pointed by the symlink doesn't + exist, an exception will be added in the list of errors raised in + an Error exception at the end of the copy process. + + You can set the optional ignore_dangling_symlinks flag to true if you + want to silence this exception. Notice that this has no effect on + platforms that don't support os.symlink. The optional ignore argument is a callable. If given, it is called with the `src` parameter, which is the directory @@ -163,7 +190,10 @@ list of names relative to the `src` directory that should not be copied. - XXX Consider this example code rather than the ultimate tool. + The optional copy_function argument is a callable that will be used + to copy each file. It will be called with the source path and the + destination path as arguments. By default, copy2() is used, but any + function that supports the same signature (like copy()) can be used. """ names = os.listdir(src) @@ -182,14 +212,21 @@ srcname = os.path.join(src, name) dstname = os.path.join(dst, name) try: - if symlinks and os.path.islink(srcname): + if os.path.islink(srcname): linkto = os.readlink(srcname) - os.symlink(linkto, dstname) + if symlinks: + os.symlink(linkto, dstname) + else: + # ignore dangling symlink if the flag is on + if not os.path.exists(linkto) and ignore_dangling_symlinks: + continue + # otherwise let the copy occurs. copy2 will raise an error + copy_function(srcname, dstname) elif os.path.isdir(srcname): - copytree(srcname, dstname, symlinks, ignore) + copytree(srcname, dstname, symlinks, ignore, copy_function) else: # Will raise a SpecialFileError for unsupported file types - copy2(srcname, dstname) + copy_function(srcname, dstname) # catch the Error from the recursive copytree so that we can # continue with other files except Error, err: @@ -205,7 +242,7 @@ else: errors.extend((src, dst, str(why))) if errors: - raise Error, errors + raise Error(errors) def rmtree(path, ignore_errors=False, onerror=None): """Recursively delete a directory tree. @@ -235,7 +272,7 @@ names = [] try: names = os.listdir(path) - except os.error, err: + except os.error: onerror(os.listdir, path, sys.exc_info()) for name in names: fullname = os.path.join(path, name) @@ -248,7 +285,7 @@ else: try: os.remove(fullname) - except os.error, err: + except os.error: onerror(os.remove, fullname, sys.exc_info()) try: os.rmdir(path) @@ -282,13 +319,13 @@ if os.path.isdir(dst): real_dst = os.path.join(dst, _basename(src)) if os.path.exists(real_dst): - raise Error, "Destination path '%s' already exists" % real_dst + raise Error("Destination path '%s' already exists" % real_dst) try: os.rename(src, real_dst) except OSError: if os.path.isdir(src): if _destinsrc(src, dst): - raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst) + raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) copytree(src, real_dst, symlinks=True) rmtree(src) else: @@ -333,40 +370,41 @@ """Create a (possibly compressed) tar file from all the files under 'base_dir'. - 'compress' must be "gzip" (the default), "compress", "bzip2", or None. - (compress will be deprecated in Python 3.2) + 'compress' must be "gzip" (the default), "bzip2", or None. 'owner' and 'group' can be used to define an owner and a group for the archive that is being built. If not provided, the current owner and group will be used. The output tar file will be named 'base_dir' + ".tar", possibly plus - the appropriate compression extension (".gz", ".bz2" or ".Z"). + the appropriate compression extension (".gz", or ".bz2"). Returns the output filename. """ - tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', None: '', 'compress': ''} - compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'compress': '.Z'} + tar_compression = {'gzip': 'gz', None: ''} + compress_ext = {'gzip': '.gz'} + + if _BZ2_SUPPORTED: + tar_compression['bzip2'] = 'bz2' + compress_ext['bzip2'] = '.bz2' # flags for compression program, each element of list will be an argument if compress is not None and compress not in compress_ext: - raise ValueError, \ - ("bad value for 'compress': must be None, 'gzip', 'bzip2' " - "or 'compress'") + raise ValueError("bad value for 'compress', or compression format not " + "supported: %s" % compress) - archive_name = base_name + '.tar' - if compress != 'compress': - archive_name += compress_ext.get(compress, '') + archive_name = base_name + '.tar' + compress_ext.get(compress, '') + archive_dir = os.path.dirname(archive_name) - archive_dir = os.path.dirname(archive_name) if not os.path.exists(archive_dir): if logger is not None: - logger.info("creating %s" % archive_dir) + logger.info("creating %s", archive_dir) if not dry_run: os.makedirs(archive_dir) - # creating the tarball + # XXX late import because of circular dependency between shutil and + # tarfile :( from distutils2._backport import tarfile if logger is not None: @@ -391,23 +429,9 @@ finally: tar.close() - # compression using `compress` - # XXX this block will be removed in Python 3.2 - if compress == 'compress': - warn("'compress' will be deprecated.", PendingDeprecationWarning) - # the option varies depending on the platform - compressed_name = archive_name + compress_ext[compress] - if sys.platform == 'win32': - cmd = [compress, archive_name, compressed_name] - else: - cmd = [compress, '-f', archive_name] - from distutils2.spawn import spawn - spawn(cmd, dry_run=dry_run) - return compressed_name - return archive_name -def _call_external_zip(directory, verbose=False): +def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False): # XXX see if we want to keep an external call here if verbose: zipoptions = "-r" @@ -420,8 +444,7 @@ except DistutilsExecError: # XXX really should distinguish between "couldn't find # external 'zip' command" and "zip failed". - raise ExecError, \ - ("unable to create zip file '%s': " + raise ExecError("unable to create zip file '%s': " "could neither import the 'zipfile' module nor " "find a standalone zip utility") % zip_filename @@ -451,7 +474,7 @@ zipfile = None if zipfile is None: - _call_external_zip(base_dir, verbose) + _call_external_zip(base_dir, zip_filename, verbose, dry_run) else: if logger is not None: logger.info("creating '%s' and adding '%s' to it", @@ -475,12 +498,14 @@ _ARCHIVE_FORMATS = { 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), 'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), - 'ztar': (_make_tarball, [('compress', 'compress')], - "compressed tar file"), 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"), - 'zip': (_make_zipfile, [],"ZIP file") + 'zip': (_make_zipfile, [], "ZIP file"), } +if _BZ2_SUPPORTED: + _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], + "bzip2'ed tar-file") + def get_archive_formats(): """Returns a list of supported formats for archiving and unarchiving. @@ -507,7 +532,7 @@ if not isinstance(extra_args, (tuple, list)): raise TypeError('extra_args needs to be a sequence') for element in extra_args: - if not isinstance(element, (tuple, list)) or len(element) !=2 : + if not isinstance(element, (tuple, list)) or len(element) !=2: raise TypeError('extra_args elements are : (arg_name, value)') _ARCHIVE_FORMATS[name] = (function, extra_args, description) @@ -520,7 +545,7 @@ """Create an archive file (eg. zip or tar). 'base_name' is the name of the file to create, minus any format-specific - extension; 'format' is the archive format: one of "zip", "tar", "ztar", + extension; 'format' is the archive format: one of "zip", "tar", "bztar" or "gztar". 'root_dir' is a directory that will be the root directory of the @@ -549,7 +574,7 @@ try: format_info = _ARCHIVE_FORMATS[format] except KeyError: - raise ValueError, "unknown archive format '%s'" % format + raise ValueError("unknown archive format '%s'" % format) func = format_info[0] for arg, val in format_info[1]: @@ -570,6 +595,61 @@ return filename +def get_unpack_formats(): + """Returns a list of supported formats for unpacking. + + Each element of the returned sequence is a tuple + (name, extensions, description) + """ + formats = [(name, info[0], info[3]) for name, info in + _UNPACK_FORMATS.iteritems()] + formats.sort() + return formats + +def _check_unpack_options(extensions, function, extra_args): + """Checks what gets registered as an unpacker.""" + # first make sure no other unpacker is registered for this extension + existing_extensions = {} + for name, info in _UNPACK_FORMATS.iteritems(): + for ext in info[0]: + existing_extensions[ext] = name + + for extension in extensions: + if extension in existing_extensions: + msg = '%s is already registered for "%s"' + raise RegistryError(msg % (extension, + existing_extensions[extension])) + + if not callable(function): + raise TypeError('The registered function must be a callable') + + +def register_unpack_format(name, extensions, function, extra_args=None, + description=''): + """Registers an unpack format. + + `name` is the name of the format. `extensions` is a list of extensions + corresponding to the format. + + `function` is the callable that will be + used to unpack archives. The callable will receive archives to unpack. + If it's unable to handle an archive, it needs to raise a ReadError + exception. + + If provided, `extra_args` is a sequence of + (name, value) tuples that will be passed as arguments to the callable. + description can be provided to describe the format, and will be returned + by the get_unpack_formats() function. + """ + if extra_args is None: + extra_args = [] + _check_unpack_options(extensions, function, extra_args) + _UNPACK_FORMATS[name] = extensions, function, extra_args, description + +def unregister_unpack_format(name): + """Removes the pack format from the registery.""" + del _UNPACK_FORMATS[name] + def _ensure_directory(path): """Ensure that the parent directory of `path` exists""" dirname = os.path.dirname(path) @@ -577,6 +657,8 @@ os.makedirs(dirname) def _unpack_zipfile(filename, extract_dir): + """Unpack zip `filename` to `extract_dir` + """ try: import zipfile except ImportError: @@ -589,6 +671,8 @@ try: for info in zip.infolist(): name = info.filename + + # don't extract absolute paths or ones with .. in them if name.startswith('/') or '..' in name: continue @@ -600,7 +684,7 @@ if not name.endswith('/'): # file data = zip.read(info.filename) - f = open(target,'wb') + f = open(target, 'wb') try: f.write(data) finally: @@ -610,6 +694,9 @@ zip.close() def _unpack_tarfile(filename, extract_dir): + """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` + """ + from distutils2._backport import tarfile try: tarobj = tarfile.open(filename) except tarfile.TarError: @@ -620,20 +707,55 @@ finally: tarobj.close() +_UNPACK_FORMATS = { + 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"), + 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"), + 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file") + } -_UNPACKERS = ( - (['.tar.gz', '.tgz', '.tar'], _unpack_tarfile), - (['.zip', '.egg'], _unpack_zipfile)) +if _BZ2_SUPPORTED: + _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], + "bzip2'ed tar-file") +def _find_unpack_format(filename): + for name, info in _UNPACK_FORMATS.iteritems(): + for extension in info[0]: + if filename.endswith(extension): + return name + return None -def unpack_archive(filename, extract_dir=None): +def unpack_archive(filename, extract_dir=None, format=None): + """Unpack an archive. + + `filename` is the name of the archive. + + `extract_dir` is the name of the target directory, where the archive + is unpacked. If not provided, the current working directory is used. + + `format` is the archive format: one of "zip", "tar", or "gztar". Or any + other registered format. If not provided, unpack_archive will use the + filename extension and see if an unpacker was registered for that + extension. + + In case none is found, a ValueError is raised. + """ if extract_dir is None: - extract_dir = os.path.dirname(filename) + extract_dir = os.getcwd() - for formats, func in _UNPACKERS: - for format in formats: - if filename.endswith(format): - func(filename, extract_dir) - return extract_dir + if format is not None: + try: + format_info = _UNPACK_FORMATS[format] + except KeyError: + raise ValueError("Unknown unpack format '{0}'".format(format)) + func = format_info[0] + func(filename, extract_dir, **dict(format_info[1])) + else: + # we need to look at the registered unpackers supported extensions + format = _find_unpack_format(filename) + if format is None: + raise ReadError("Unknown archive format '{0}'".format(filename)) + + func = _UNPACK_FORMATS[format][1] + kwargs = dict(_UNPACK_FORMATS[format][2]) raise ValueError('Unknown archive format: %s' % filename) diff --git a/distutils2/_backport/tests/test_pkgutil.py b/distutils2/_backport/tests/test_pkgutil.py --- a/distutils2/_backport/tests/test_pkgutil.py +++ b/distutils2/_backport/tests/test_pkgutil.py @@ -12,10 +12,15 @@ except ImportError: from distutils2._backport.hashlib import md5 -from test.test_support import TESTFN +from distutils2.errors import DistutilsError +from distutils2.metadata import DistributionMetadata +from distutils2.tests import unittest, run_unittest, support -from distutils2.tests import unittest, run_unittest, support from distutils2._backport import pkgutil +from distutils2._backport.pkgutil import ( + Distribution, EggInfoDistribution, get_distribution, get_distributions, + provides_distribution, obsoletes_distribution, get_file_users, + distinfo_dirname, _yield_distributions) try: from os.path import relpath @@ -108,6 +113,12 @@ self.assertEqual(res1, RESOURCE_DATA) res2 = pkgutil.get_data(pkg, 'sub/res.txt') self.assertEqual(res2, RESOURCE_DATA) + + names = [] + for loader, name, ispkg in pkgutil.iter_modules([zip_file]): + names.append(name) + self.assertEqual(names, ['test_getdata_zipfile']) + del sys.path[0] del sys.modules[pkg] @@ -205,7 +216,7 @@ record_writer.writerow(record_pieces( os.path.join(distinfo_dir, file))) record_writer.writerow([relpath(record_file, sys.prefix)]) - del record_writer # causes the RECORD file to close + del record_writer # causes the RECORD file to close record_reader = csv.reader(open(record_file, 'rb')) record_data = [] for row in record_reader: @@ -225,9 +236,6 @@ def test_instantiation(self): # Test the Distribution class's instantiation provides us with usable # attributes. - # Import the Distribution class - from distutils2._backport.pkgutil import distinfo_dirname, Distribution - here = os.path.abspath(os.path.dirname(__file__)) name = 'choxie' version = '2.0.0.9' @@ -236,7 +244,6 @@ dist = Distribution(dist_path) self.assertEqual(dist.name, name) - from distutils2.metadata import DistributionMetadata self.assertTrue(isinstance(dist.metadata, DistributionMetadata)) self.assertEqual(dist.metadata['version'], version) self.assertTrue(isinstance(dist.requested, type(bool()))) @@ -244,7 +251,6 @@ def test_installed_files(self): # Test the iteration of installed files. # Test the distribution's installed files - from distutils2._backport.pkgutil import Distribution for distinfo_dir in self.distinfo_dirs: dist = Distribution(distinfo_dir) for path, md5_, size in dist.get_installed_files(): @@ -267,14 +273,12 @@ false_path = relpath(os.path.join(*false_path), sys.prefix) # Test if the distribution uses the file in question - from distutils2._backport.pkgutil import Distribution dist = Distribution(distinfo_dir) self.assertTrue(dist.uses(true_path)) self.assertFalse(dist.uses(false_path)) def test_get_distinfo_file(self): # Test the retrieval of dist-info file objects. - from distutils2._backport.pkgutil import Distribution distinfo_name = 'choxie-2.0.0.9' other_distinfo_name = 'grammar-1.0a4' distinfo_dir = os.path.join(self.fake_dists_path, @@ -295,7 +299,6 @@ # Is it the correct file? self.assertEqual(value.name, os.path.join(distinfo_dir, distfile)) - from distutils2.errors import DistutilsError # Test an absolute path that is part of another distributions dist-info other_distinfo_file = os.path.join(self.fake_dists_path, other_distinfo_name + '.dist-info', 'REQUESTED') @@ -307,7 +310,6 @@ def test_get_distinfo_files(self): # Test for the iteration of RECORD path entries. - from distutils2._backport.pkgutil import Distribution distinfo_name = 'towel_stuff-0.1' distinfo_dir = os.path.join(self.fake_dists_path, distinfo_name + '.dist-info') @@ -345,7 +347,7 @@ # Given a name and a version, we expect the distinfo_dirname function # to return a standard distribution information directory name. - items = [# (name, version, standard_dirname) + items = [ # (name, version, standard_dirname) # Test for a very simple single word name and decimal # version number ('docutils', '0.5', 'docutils-0.5.dist-info'), @@ -356,9 +358,6 @@ ('python-ldap', '2.5 a---5', 'python_ldap-2.5 a---5.dist-info'), ] - # Import the function in question - from distutils2._backport.pkgutil import distinfo_dirname - # Loop through the items to validate the results for name, version, standard_dirname in items: dirname = distinfo_dirname(name, version) @@ -371,11 +370,6 @@ ('towel-stuff', '0.1')] found_dists = [] - # Import the function in question - from distutils2._backport.pkgutil import get_distributions, \ - Distribution, \ - EggInfoDistribution - # Verify the fake dists have been found. dists = [dist for dist in get_distributions()] for dist in dists: @@ -416,12 +410,7 @@ def test_get_distribution(self): # Test for looking up a distribution by name. # Test the lookup of the towel-stuff distribution - name = 'towel-stuff' # Note: This is different from the directory name - - # Import the function in question - from distutils2._backport.pkgutil import get_distribution, \ - Distribution, \ - EggInfoDistribution + name = 'towel-stuff' # Note: This is different from the directory name # Lookup the distribution dist = get_distribution(name) @@ -461,7 +450,6 @@ def test_get_file_users(self): # Test the iteration of distributions that use a file. - from distutils2._backport.pkgutil import get_file_users, Distribution name = 'towel_stuff-0.1' path = os.path.join(self.fake_dists_path, name, 'towel_stuff', '__init__.py') @@ -471,9 +459,6 @@ def test_provides(self): # Test for looking up distributions by what they provide - from distutils2._backport.pkgutil import provides_distribution - from distutils2.errors import DistutilsError - checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) l = [dist.name for dist in provides_distribution('truffles')] @@ -522,12 +507,10 @@ use_egg_info=True)] checkLists(l, ['strawberry']) - l = [dist.name for dist in provides_distribution('strawberry', '>0.6', use_egg_info=True)] checkLists(l, []) - l = [dist.name for dist in provides_distribution('banana', '0.4', use_egg_info=True)] checkLists(l, ['banana']) @@ -536,16 +519,12 @@ use_egg_info=True)] checkLists(l, ['banana']) - l = [dist.name for dist in provides_distribution('banana', '!=0.4', use_egg_info=True)] checkLists(l, []) def test_obsoletes(self): # Test looking for distributions based on what they obsolete - from distutils2._backport.pkgutil import obsoletes_distribution - from distutils2.errors import DistutilsError - checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) l = [dist.name for dist in obsoletes_distribution('truffles', '1.0')] @@ -555,7 +534,6 @@ use_egg_info=True)] checkLists(l, ['cheese', 'bacon']) - l = [dist.name for dist in obsoletes_distribution('truffles', '0.8')] checkLists(l, ['choxie']) @@ -575,7 +553,6 @@ def test_yield_distribution(self): # tests the internal function _yield_distributions - from distutils2._backport.pkgutil import _yield_distributions checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) eggs = [('bacon', '0.1'), ('banana', '0.4'), ('strawberry', '0.6'), diff --git a/distutils2/_backport/tests/test_shutil.py b/distutils2/_backport/tests/test_shutil.py new file mode 100644 --- /dev/null +++ b/distutils2/_backport/tests/test_shutil.py @@ -0,0 +1,945 @@ +import os +import sys +import tempfile +import stat +import tarfile +from os.path import splitdrive +from StringIO import StringIO + +from distutils.spawn import find_executable, spawn +from distutils2._backport import shutil +from distutils2._backport.shutil import ( + _make_tarball, _make_zipfile, make_archive, unpack_archive, + register_archive_format, unregister_archive_format, get_archive_formats, + register_unpack_format, unregister_unpack_format, get_unpack_formats, + Error, RegistryError) + +from distutils2.tests import unittest, support, TESTFN + +try: + import bz2 + BZ2_SUPPORTED = True +except ImportError: + BZ2_SUPPORTED = False + +TESTFN2 = TESTFN + "2" + +try: + import grp + import pwd + UID_GID_SUPPORT = True +except ImportError: + UID_GID_SUPPORT = False + +try: + import zlib +except ImportError: + zlib = None + +try: + import zipfile + ZIP_SUPPORT = True +except ImportError: + ZIP_SUPPORT = find_executable('zip') + +class TestShutil(unittest.TestCase): + + def setUp(self): + super(TestShutil, self).setUp() + self.tempdirs = [] + + def tearDown(self): + super(TestShutil, self).tearDown() + while self.tempdirs: + d = self.tempdirs.pop() + shutil.rmtree(d, os.name in ('nt', 'cygwin')) + + def write_file(self, path, content='xxx'): + """Writes a file in the given path. + + + path can be a string or a sequence. + """ + if isinstance(path, (list, tuple)): + path = os.path.join(*path) + f = open(path, 'w') + try: + f.write(content) + finally: + f.close() + + def mkdtemp(self): + """Create a temporary directory that will be cleaned up. + + Returns the path of the directory. + """ + d = tempfile.mkdtemp() + self.tempdirs.append(d) + return d + + def test_rmtree_errors(self): + # filename is guaranteed not to exist + filename = tempfile.mktemp() + self.assertRaises(OSError, shutil.rmtree, filename) + + # See bug #1071513 for why we don't run this on cygwin + # and bug #1076467 for why we don't run this as root. + if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin' + and not (hasattr(os, 'geteuid') and os.geteuid() == 0)): + def test_on_error(self): + self.errorState = 0 + os.mkdir(TESTFN) + self.childpath = os.path.join(TESTFN, 'a') + f = open(self.childpath, 'w') + f.close() + old_dir_mode = os.stat(TESTFN).st_mode + old_child_mode = os.stat(self.childpath).st_mode + # Make unwritable. + os.chmod(self.childpath, stat.S_IREAD) + os.chmod(TESTFN, stat.S_IREAD) + + shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) + # Test whether onerror has actually been called. + self.assertEqual(self.errorState, 2, + "Expected call to onerror function did not happen.") + + # Make writable again. + os.chmod(TESTFN, old_dir_mode) + os.chmod(self.childpath, old_child_mode) + + # Clean up. + shutil.rmtree(TESTFN) + + def check_args_to_onerror(self, func, arg, exc): + # test_rmtree_errors deliberately runs rmtree + # on a directory that is chmod 400, which will fail. + # This function is run when shutil.rmtree fails. + # 99.9% of the time it initially fails to remove + # a file in the directory, so the first time through + # func is os.remove. + # However, some Linux machines running ZFS on + # FUSE experienced a failure earlier in the process + # at os.listdir. The first failure may legally + # be either. + if self.errorState == 0: + if func is os.remove: + self.assertEqual(arg, self.childpath) + else: + self.assertIs(func, os.listdir, + "func must be either os.remove or os.listdir") + self.assertEqual(arg, TESTFN) + self.assertTrue(issubclass(exc[0], OSError)) + self.errorState = 1 + else: + self.assertEqual(func, os.rmdir) + self.assertEqual(arg, TESTFN) + self.assertTrue(issubclass(exc[0], OSError)) + self.errorState = 2 + + def test_rmtree_dont_delete_file(self): + # When called on a file instead of a directory, don't delete it. + handle, path = tempfile.mkstemp() + os.fdopen(handle).close() + self.assertRaises(OSError, shutil.rmtree, path) + os.remove(path) + + def _write_data(self, path, data): + f = open(path, "w") + f.write(data) + f.close() + + def test_copytree_simple(self): + + def read_data(path): + f = open(path) + data = f.read() + f.close() + return data + + src_dir = tempfile.mkdtemp() + dst_dir = os.path.join(tempfile.mkdtemp(), 'destination') + self._write_data(os.path.join(src_dir, 'test.txt'), '123') + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + + try: + shutil.copytree(src_dir, dst_dir) + self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt'))) + self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir'))) + self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir', + 'test.txt'))) + actual = read_data(os.path.join(dst_dir, 'test.txt')) + self.assertEqual(actual, '123') + actual = read_data(os.path.join(dst_dir, 'test_dir', 'test.txt')) + self.assertEqual(actual, '456') + finally: + for path in ( + os.path.join(src_dir, 'test.txt'), + os.path.join(dst_dir, 'test.txt'), + os.path.join(src_dir, 'test_dir', 'test.txt'), + os.path.join(dst_dir, 'test_dir', 'test.txt'), + ): + if os.path.exists(path): + os.remove(path) + for path in (src_dir, + os.path.dirname(dst_dir) + ): + if os.path.exists(path): + shutil.rmtree(path) + + def test_copytree_with_exclude(self): + + def read_data(path): + f = open(path) + data = f.read() + f.close() + return data + + # creating data + join = os.path.join + exists = os.path.exists + src_dir = tempfile.mkdtemp() + try: + dst_dir = join(tempfile.mkdtemp(), 'destination') + self._write_data(join(src_dir, 'test.txt'), '123') + self._write_data(join(src_dir, 'test.tmp'), '123') + os.mkdir(join(src_dir, 'test_dir')) + self._write_data(join(src_dir, 'test_dir', 'test.txt'), '456') + os.mkdir(join(src_dir, 'test_dir2')) + self._write_data(join(src_dir, 'test_dir2', 'test.txt'), '456') + os.mkdir(join(src_dir, 'test_dir2', 'subdir')) + os.mkdir(join(src_dir, 'test_dir2', 'subdir2')) + self._write_data(join(src_dir, 'test_dir2', 'subdir', 'test.txt'), + '456') + self._write_data(join(src_dir, 'test_dir2', 'subdir2', 'test.py'), + '456') + + + # testing glob-like patterns + try: + patterns = shutil.ignore_patterns('*.tmp', 'test_dir2') + shutil.copytree(src_dir, dst_dir, ignore=patterns) + # checking the result: some elements should not be copied + self.assertTrue(exists(join(dst_dir, 'test.txt'))) + self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2'))) + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + try: + patterns = shutil.ignore_patterns('*.tmp', 'subdir*') + shutil.copytree(src_dir, dst_dir, ignore=patterns) + # checking the result: some elements should not be copied + self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + + # testing callable-style + try: + def _filter(src, names): + res = [] + for name in names: + path = os.path.join(src, name) + + if (os.path.isdir(path) and + path.split()[-1] == 'subdir'): + res.append(name) + elif os.path.splitext(path)[-1] in ('.py'): + res.append(name) + return res + + shutil.copytree(src_dir, dst_dir, ignore=_filter) + + # checking the result: some elements should not be copied + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2', + 'test.py'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) + + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + finally: + shutil.rmtree(src_dir) + shutil.rmtree(os.path.dirname(dst_dir)) + + @support.skip_unless_symlink + def test_dont_copy_file_onto_link_to_itself(self): + # bug 851123. + os.mkdir(TESTFN) + src = os.path.join(TESTFN, 'cheese') + dst = os.path.join(TESTFN, 'shop') + try: + f = open(src, 'w') + f.write('cheddar') + f.close() + + if hasattr(os, "link"): + os.link(src, dst) + self.assertRaises(shutil.Error, shutil.copyfile, src, dst) + f = open(src, 'r') + try: + self.assertEqual(f.read(), 'cheddar') + finally: + f.close() + os.remove(dst) + + # Using `src` here would mean we end up with a symlink pointing + # to TESTFN/TESTFN/cheese, while it should point at + # TESTFN/cheese. + os.symlink('cheese', dst) + self.assertRaises(shutil.Error, shutil.copyfile, src, dst) + f = open(src, 'r') + try: + self.assertEqual(f.read(), 'cheddar') + finally: + f.close() + os.remove(dst) + finally: + try: + shutil.rmtree(TESTFN) + except OSError: + pass + + @support.skip_unless_symlink + def test_rmtree_on_symlink(self): + # bug 1669. + os.mkdir(TESTFN) + try: + src = os.path.join(TESTFN, 'cheese') + dst = os.path.join(TESTFN, 'shop') + os.mkdir(src) + os.symlink(src, dst) + self.assertRaises(OSError, shutil.rmtree, dst) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + if hasattr(os, "mkfifo"): + # Issue #3002: copyfile and copytree block indefinitely on named pipes + def test_copyfile_named_pipe(self): + os.mkfifo(TESTFN) + try: + self.assertRaises(shutil.SpecialFileError, + shutil.copyfile, TESTFN, TESTFN2) + self.assertRaises(shutil.SpecialFileError, + shutil.copyfile, __file__, TESTFN) + finally: + os.remove(TESTFN) + + @unittest.skipUnless(hasattr(os, 'mkfifo'), 'requires os.mkfifo') + def test_copytree_named_pipe(self): + os.mkdir(TESTFN) + try: + subdir = os.path.join(TESTFN, "subdir") + os.mkdir(subdir) + pipe = os.path.join(subdir, "mypipe") + os.mkfifo(pipe) + try: + shutil.copytree(TESTFN, TESTFN2) + except shutil.Error, e: + errors = e.args[0] + self.assertEqual(len(errors), 1) + src, dst, error_msg = errors[0] + self.assertEqual("`%s` is a named pipe" % pipe, error_msg) + else: + self.fail("shutil.Error should have been raised") + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + shutil.rmtree(TESTFN2, ignore_errors=True) + + def test_copytree_special_func(self): + + src_dir = self.mkdtemp() + dst_dir = os.path.join(self.mkdtemp(), 'destination') + self._write_data(os.path.join(src_dir, 'test.txt'), '123') + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + + copied = [] + def _copy(src, dst): + copied.append((src, dst)) + + shutil.copytree(src_dir, dst_dir, copy_function=_copy) + self.assertEquals(len(copied), 2) + + @support.skip_unless_symlink + def test_copytree_dangling_symlinks(self): + + # a dangling symlink raises an error at the end + src_dir = self.mkdtemp() + dst_dir = os.path.join(self.mkdtemp(), 'destination') + os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt')) + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + self.assertRaises(Error, shutil.copytree, src_dir, dst_dir) + + # a dangling symlink is ignored with the proper flag + dst_dir = os.path.join(self.mkdtemp(), 'destination2') + shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True) + self.assertNotIn('test.txt', os.listdir(dst_dir)) + + # a dangling symlink is copied if symlinks=True + dst_dir = os.path.join(self.mkdtemp(), 'destination3') + shutil.copytree(src_dir, dst_dir, symlinks=True) + self.assertIn('test.txt', os.listdir(dst_dir)) + + @unittest.skipUnless(zlib, "requires zlib") + def test_make_tarball(self): + # creating something to tar + tmpdir = self.mkdtemp() + self.write_file([tmpdir, 'file1'], 'xxx') + self.write_file([tmpdir, 'file2'], 'xxx') + os.mkdir(os.path.join(tmpdir, 'sub')) + self.write_file([tmpdir, 'sub', 'file3'], 'xxx') + + tmpdir2 = self.mkdtemp() + unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0], + "source and target should be on same drive") + + base_name = os.path.join(tmpdir2, 'archive') + + # working with relative paths to avoid tar warnings + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(splitdrive(base_name)[1], '.') + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + tarball = base_name + '.tar.gz' + self.assertTrue(os.path.exists(tarball)) + + # trying an uncompressed one + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(splitdrive(base_name)[1], '.', compress=None) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + def _tarinfo(self, path): + tar = tarfile.open(path) + try: + names = tar.getnames() + names.sort() + return tuple(names) + finally: + tar.close() + + def _create_files(self): + # creating something to tar + tmpdir = self.mkdtemp() + dist = os.path.join(tmpdir, 'dist') + os.mkdir(dist) + self.write_file([dist, 'file1'], 'xxx') + self.write_file([dist, 'file2'], 'xxx') + os.mkdir(os.path.join(dist, 'sub')) + self.write_file([dist, 'sub', 'file3'], 'xxx') + os.mkdir(os.path.join(dist, 'sub2')) + tmpdir2 = self.mkdtemp() + base_name = os.path.join(tmpdir2, 'archive') + return tmpdir, tmpdir2, base_name + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(find_executable('tar') and find_executable('gzip'), + 'Need the tar command to run') + def test_tarfile_vs_tar(self): + tmpdir, tmpdir2, base_name = self._create_files() + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist') + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + tarball = base_name + '.tar.gz' + self.assertTrue(os.path.exists(tarball)) + + # now create another tarball using `tar` + tarball2 = os.path.join(tmpdir, 'archive2.tar.gz') + tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist'] + gzip_cmd = ['gzip', '-f9', 'archive2.tar'] + old_dir = os.getcwd() + old_stdout = sys.stdout + os.chdir(tmpdir) + sys.stdout = StringIO() + + try: + spawn(tar_cmd) + spawn(gzip_cmd) + finally: + os.chdir(old_dir) + sys.stdout = old_stdout + + self.assertTrue(os.path.exists(tarball2)) + # let's compare both tarballs + self.assertEquals(self._tarinfo(tarball), self._tarinfo(tarball2)) + + # trying an uncompressed one + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist', compress=None) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + # now for a dry_run + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist', compress=None, dry_run=True) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run') + def test_make_zipfile(self): + # creating something to tar + tmpdir = self.mkdtemp() + self.write_file([tmpdir, 'file1'], 'xxx') + self.write_file([tmpdir, 'file2'], 'xxx') + + tmpdir2 = self.mkdtemp() + base_name = os.path.join(tmpdir2, 'archive') + _make_zipfile(base_name, tmpdir) + + # check if the compressed tarball was created + tarball = base_name + '.zip' + self.assertTrue(os.path.exists(tarball)) + + + def test_make_archive(self): + tmpdir = self.mkdtemp() + base_name = os.path.join(tmpdir, 'archive') + self.assertRaises(ValueError, make_archive, base_name, 'xxx') + + @unittest.skipUnless(zlib, "Requires zlib") + def test_make_archive_owner_group(self): + # testing make_archive with owner and group, with various combinations + # this works even if there's not gid/uid support + if UID_GID_SUPPORT: + group = grp.getgrgid(0)[0] + owner = pwd.getpwuid(0)[0] + else: + group = owner = 'root' + + base_dir, root_dir, base_name = self._create_files() + base_name = os.path.join(self.mkdtemp() , 'archive') + res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner, + group=group) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'zip', root_dir, base_dir) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'tar', root_dir, base_dir, + owner=owner, group=group) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'tar', root_dir, base_dir, + owner='kjhkjhkjg', group='oihohoh') + self.assertTrue(os.path.exists(res)) + + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") + def test_tarfile_root_owner(self): + tmpdir, tmpdir2, base_name = self._create_files() + old_dir = os.getcwd() + os.chdir(tmpdir) + group = grp.getgrgid(0)[0] + owner = pwd.getpwuid(0)[0] + try: + archive_name = _make_tarball(base_name, 'dist', compress=None, + owner=owner, group=group) + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + self.assertTrue(os.path.exists(archive_name)) + + # now checks the rights + archive = tarfile.open(archive_name) + try: + for member in archive.getmembers(): + self.assertEquals(member.uid, 0) + self.assertEquals(member.gid, 0) + finally: + archive.close() + + def test_make_archive_cwd(self): + current_dir = os.getcwd() + def _breaks(*args, **kw): + raise RuntimeError() + + register_archive_format('xxx', _breaks, [], 'xxx file') + try: + try: + make_archive('xxx', 'xxx', root_dir=self.mkdtemp()) + except Exception: + pass + self.assertEquals(os.getcwd(), current_dir) + finally: + unregister_archive_format('xxx') + + def test_register_archive_format(self): + + self.assertRaises(TypeError, register_archive_format, 'xxx', 1) + self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x, + 1) + self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x, + [(1, 2), (1, 2, 3)]) + + register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file') + formats = [name for name, params in get_archive_formats()] + self.assertIn('xxx', formats) + + unregister_archive_format('xxx') + formats = [name for name, params in get_archive_formats()] + self.assertNotIn('xxx', formats) + + def _compare_dirs(self, dir1, dir2): + # check that dir1 and dir2 are equivalent, + # return the diff + diff = [] + for root, dirs, files in os.walk(dir1): + for file_ in files: + path = os.path.join(root, file_) + target_path = os.path.join(dir2, os.path.split(path)[-1]) + if not os.path.exists(target_path): + diff.append(file_) + return diff + + @unittest.skipUnless(zlib, "Requires zlib") + def test_unpack_archive(self): + formats = ['tar', 'gztar', 'zip'] + if BZ2_SUPPORTED: + formats.append('bztar') + + for format in formats: + tmpdir = self.mkdtemp() + base_dir, root_dir, base_name = self._create_files() + tmpdir2 = self.mkdtemp() + filename = make_archive(base_name, format, root_dir, base_dir) + + # let's try to unpack it now + unpack_archive(filename, tmpdir2) + diff = self._compare_dirs(tmpdir, tmpdir2) + self.assertEquals(diff, []) + + def test_unpack_registery(self): + + formats = get_unpack_formats() + + def _boo(filename, extract_dir, extra): + self.assertEquals(extra, 1) + self.assertEquals(filename, 'stuff.boo') + self.assertEquals(extract_dir, 'xx') + + register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)]) + unpack_archive('stuff.boo', 'xx') + + # trying to register a .boo unpacker again + self.assertRaises(RegistryError, register_unpack_format, 'Boo2', + ['.boo'], _boo) + + # should work now + unregister_unpack_format('Boo') + register_unpack_format('Boo2', ['.boo'], _boo) + self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats()) + self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats()) + + # let's leave a clean state + unregister_unpack_format('Boo2') + self.assertEquals(get_unpack_formats(), formats) + + +class TestMove(unittest.TestCase): + + def setUp(self): + filename = "foo" + self.src_dir = tempfile.mkdtemp() + self.dst_dir = tempfile.mkdtemp() + self.src_file = os.path.join(self.src_dir, filename) + self.dst_file = os.path.join(self.dst_dir, filename) + # Try to create a dir in the current directory, hoping that it is + # not located on the same filesystem as the system tmp dir. + try: + self.dir_other_fs = tempfile.mkdtemp( + dir=os.path.dirname(__file__)) + self.file_other_fs = os.path.join(self.dir_other_fs, + filename) + except OSError: + self.dir_other_fs = None + f = open(self.src_file, "wb") + try: + f.write("spam") + finally: + f.close() + + def tearDown(self): + for d in (self.src_dir, self.dst_dir, self.dir_other_fs): + try: + if d: + shutil.rmtree(d) + except: + pass + + def _check_move_file(self, src, dst, real_dst): + f = open(src, "rb") + try: + contents = f.read() + finally: + f.close() + + shutil.move(src, dst) + f = open(real_dst, "rb") + try: + self.assertEqual(contents, f.read()) + finally: + f.close() + + self.assertFalse(os.path.exists(src)) + + def _check_move_dir(self, src, dst, real_dst): + contents = sorted(os.listdir(src)) + shutil.move(src, dst) + self.assertEqual(contents, sorted(os.listdir(real_dst))) + self.assertFalse(os.path.exists(src)) + + def test_move_file(self): + # Move a file to another location on the same filesystem. + self._check_move_file(self.src_file, self.dst_file, self.dst_file) + + def test_move_file_to_dir(self): + # Move a file inside an existing dir on the same filesystem. + self._check_move_file(self.src_file, self.dst_dir, self.dst_file) + + def test_move_file_other_fs(self): + # Move a file to an existing dir on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_file(self.src_file, self.file_other_fs, + self.file_other_fs) + + def test_move_file_to_dir_other_fs(self): + # Move a file to another location on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_file(self.src_file, self.dir_other_fs, + self.file_other_fs) + + def test_move_dir(self): + # Move a dir to another location on the same filesystem. + dst_dir = tempfile.mktemp() + try: + self._check_move_dir(self.src_dir, dst_dir, dst_dir) + finally: + try: + shutil.rmtree(dst_dir) + except: + pass + + def test_move_dir_other_fs(self): + # Move a dir to another location on another filesystem. + if not self.dir_other_fs: + # skip + return + dst_dir = tempfile.mktemp(dir=self.dir_other_fs) + try: + self._check_move_dir(self.src_dir, dst_dir, dst_dir) + finally: + try: + shutil.rmtree(dst_dir) + except: + pass + + def test_move_dir_to_dir(self): + # Move a dir inside an existing dir on the same filesystem. + self._check_move_dir(self.src_dir, self.dst_dir, + os.path.join(self.dst_dir, os.path.basename(self.src_dir))) + + def test_move_dir_to_dir_other_fs(self): + # Move a dir inside an existing dir on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_dir(self.src_dir, self.dir_other_fs, + os.path.join(self.dir_other_fs, os.path.basename(self.src_dir))) + + def test_existing_file_inside_dest_dir(self): + # A file with the same name inside the destination dir already exists. + f = open(self.dst_file, "wb") + try: + pass + finally: + f.close() + self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir) + + def test_dont_move_dir_in_itself(self): + # Moving a dir inside itself raises an Error. + dst = os.path.join(self.src_dir, "bar") + self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst) + + def test_destinsrc_false_negative(self): + os.mkdir(TESTFN) + try: + for src, dst in [('srcdir', 'srcdir/dest')]: + src = os.path.join(TESTFN, src) + dst = os.path.join(TESTFN, dst) + self.assertTrue(shutil._destinsrc(src, dst), + msg='_destinsrc() wrongly concluded that ' + 'dst (%s) is not in src (%s)' % (dst, src)) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + def test_destinsrc_false_positive(self): + os.mkdir(TESTFN) + try: + for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]: + src = os.path.join(TESTFN, src) + dst = os.path.join(TESTFN, dst) + self.assertFalse(shutil._destinsrc(src, dst), + msg='_destinsrc() wrongly concluded that ' + 'dst (%s) is in src (%s)' % (dst, src)) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + +class TestCopyFile(unittest.TestCase): + + _delete = False + + class Faux(object): + _entered = False + _exited_with = None + _raised = False + + def __init__(self, raise_in_exit=False, suppress_at_exit=True): + self._raise_in_exit = raise_in_exit + self._suppress_at_exit = suppress_at_exit + + def read(self, *args): + return '' + + def __enter__(self): + self._entered = True + + def __exit__(self, exc_type, exc_val, exc_tb): + self._exited_with = exc_type, exc_val, exc_tb + if self._raise_in_exit: + self._raised = True + raise IOError("Cannot close") + return self._suppress_at_exit + + def tearDown(self): + if self._delete: + del shutil.open + + def _set_shutil_open(self, func): + shutil.open = func + self._delete = True + + def test_w_source_open_fails(self): + def _open(filename, mode='r'): + if filename == 'srcfile': + raise IOError('Cannot open "srcfile"') + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile') + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_dest_open_fails(self): + + srcfile = self.Faux() + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + raise IOError('Cannot open "destfile"') + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + shutil.copyfile('srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(srcfile._exited_with[0] is IOError) + self.assertEqual(srcfile._exited_with[1].args, + ('Cannot open "destfile"',)) + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_dest_close_fails(self): + + srcfile = self.Faux() + destfile = self.Faux(True) + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + return destfile + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + shutil.copyfile('srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(destfile._entered) + self.assertTrue(destfile._raised) + self.assertTrue(srcfile._exited_with[0] is IOError) + self.assertEqual(srcfile._exited_with[1].args, + ('Cannot close',)) + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_source_close_fails(self): + + srcfile = self.Faux(True) + destfile = self.Faux() + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + return destfile + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + self.assertRaises(IOError, + shutil.copyfile, 'srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(destfile._entered) + self.assertFalse(destfile._raised) + self.assertTrue(srcfile._exited_with[0] is None) + self.assertTrue(srcfile._raised) + + +def test_suite(): + suite = unittest.TestSuite() + load = unittest.defaultTestLoader.loadTestsFromTestCase + suite.addTest(load(TestCopyFile)) + suite.addTest(load(TestMove)) + suite.addTest(load(TestShutil)) + return suite + + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/distutils2/_backport/tests/test_sysconfig.py b/distutils2/_backport/tests/test_sysconfig.py --- a/distutils2/_backport/tests/test_sysconfig.py +++ b/distutils2/_backport/tests/test_sysconfig.py @@ -4,7 +4,7 @@ import sys import subprocess import shutil -from copy import copy, deepcopy +from copy import copy from ConfigParser import RawConfigParser from StringIO import StringIO @@ -15,13 +15,9 @@ get_scheme_names, _main, _SCHEMES) from distutils2.tests import unittest -from distutils2.tests.support import EnvironGuard +from distutils2.tests.support import EnvironGuard, skip_unless_symlink from test.test_support import TESTFN, unlink -try: - from test.test_support import skip_unless_symlink -except ImportError: - skip_unless_symlink = unittest.skip( - 'requires test.test_support.skip_unless_symlink') + class TestSysConfig(EnvironGuard, unittest.TestCase): diff --git a/distutils2/command/cmd.py b/distutils2/command/cmd.py --- a/distutils2/command/cmd.py +++ b/distutils2/command/cmd.py @@ -165,7 +165,10 @@ header = "command options for '%s':" % self.get_command_name() self.announce(indent + header, level=logging.INFO) indent = indent + " " + negative_opt = getattr(self, 'negative_opt', ()) for (option, _, _) in self.user_options: + if option in negative_opt: + continue option = option.replace('-', '_') if option[-1] == "=": option = option[:-1] diff --git a/distutils2/tests/support.py b/distutils2/tests/support.py --- a/distutils2/tests/support.py +++ b/distutils2/tests/support.py @@ -17,10 +17,11 @@ super(SomeTestCase, self).setUp() ... # other setup code -Read each class' docstring to see its purpose and usage. +Also provided is a DummyCommand class, useful to mock commands in the +tests of another command that needs them, a create_distribution function +and a skip_unless_symlink decorator. -Also provided is a DummyCommand class, useful to mock commands in the -tests of another command that needs them (see docstring). +Each class or function has a docstring to explain its purpose and usage. """ import os @@ -35,7 +36,8 @@ from distutils2.tests import unittest __all__ = ['LoggingCatcher', 'WarningsCatcher', 'TempdirManager', - 'EnvironGuard', 'DummyCommand', 'unittest'] + 'EnvironGuard', 'DummyCommand', 'unittest', 'create_distribution', + 'skip_unless_symlink'] class LoggingCatcher(object): @@ -135,7 +137,7 @@ finally: f.close() - def create_dist(self, pkg_name='foo', **kw): + def create_dist(self, **kw): """Create a stub distribution object and files. This function creates a Distribution instance (use keyword arguments @@ -143,17 +145,19 @@ (currently an empty directory). It returns the path to the directory and the Distribution instance. - You can use TempdirManager.write_file to write any file in that + You can use self.write_file to write any file in that directory, e.g. setup scripts or Python modules. """ # Late import so that third parties can import support without # loading a ton of distutils2 modules in memory. from distutils2.dist import Distribution + if 'name' not in kw: + kw['name'] = 'foo' tmp_dir = self.mkdtemp() - pkg_dir = os.path.join(tmp_dir, pkg_name) - os.mkdir(pkg_dir) + project_dir = os.path.join(tmp_dir, kw['name']) + os.mkdir(project_dir) dist = Distribution(attrs=kw) - return pkg_dir, dist + return project_dir, dist class EnvironGuard(object): @@ -211,3 +215,9 @@ d.parse_command_line() return d + +try: + from test.test_support import skip_unless_symlink +except ImportError: + skip_unless_symlink = unittest.skip( + 'requires test.test_support.skip_unless_symlink') diff --git a/distutils2/tests/test_command_install_dist.py b/distutils2/tests/test_command_install_dist.py --- a/distutils2/tests/test_command_install_dist.py +++ b/distutils2/tests/test_command_install_dist.py @@ -180,8 +180,8 @@ cmd.user = 'user' self.assertRaises(DistutilsOptionError, cmd.finalize_options) - def test_record(self): - + def test_old_record(self): + # test pre-PEP 376 --record option (outside dist-info dir) install_dir = self.mkdtemp() pkgdir, dist = self.create_dist() @@ -189,11 +189,11 @@ cmd = install_dist(dist) dist.command_obj['install_dist'] = cmd cmd.root = install_dir - cmd.record = os.path.join(pkgdir, 'RECORD') + cmd.record = os.path.join(pkgdir, 'filelist') cmd.ensure_finalized() cmd.run() - # let's check the RECORD file was created with four + # let's check the record file was created with four # lines, one for each .dist-info entry: METADATA, # INSTALLER, REQUSTED, RECORD f = open(cmd.record) diff --git a/docs/source/library/distutils2.tests.pypi_server.rst b/docs/source/library/distutils2.tests.pypi_server.rst --- a/docs/source/library/distutils2.tests.pypi_server.rst +++ b/docs/source/library/distutils2.tests.pypi_server.rst @@ -77,6 +77,7 @@ @use_pypi_server() def test_somthing(self, server): # your tests goes here + ... The decorator will instantiate the server for you, and run and stop it just before and after your method call. You also can pass the server initializer, @@ -85,4 +86,4 @@ class SampleTestCase(TestCase): @use_pypi_server("test_case_name") def test_something(self, server): - # something + ... diff --git a/docs/source/library/pkgutil.rst b/docs/source/library/pkgutil.rst --- a/docs/source/library/pkgutil.rst +++ b/docs/source/library/pkgutil.rst @@ -4,77 +4,204 @@ .. module:: pkgutil :synopsis: Utilities to support packages. -.. TODO Follow the reST conventions used in the stdlib +This module provides utilities to manipulate packages: support for the +Importer protocol defined in :PEP:`302` and implementation of the API +described in :PEP:`376` to work with the database of installed Python +distributions. -This module provides functions to manipulate packages, as well as -the necessary functions to provide support for the "Importer Protocol" as -described in :PEP:`302` and for working with the database of installed Python -distributions which is specified in :PEP:`376`. In addition to the functions -required in :PEP:`376`, back support for older ``.egg`` and ``.egg-info`` -distributions is provided as well. These distributions are represented by the -class :class:`~distutils2._backport.pkgutil.EggInfoDistribution` and most -functions provide an extra argument ``use_egg_info`` which indicates if -they should consider these old styled distributions. This document details -first the functions and classes available and then presents several use cases. - +Import system utilities +----------------------- .. function:: extend_path(path, name) - Extend the search path for the modules which comprise a package. Intended use is - to place the following code in a package's :file:`__init__.py`:: + Extend the search path for the modules which comprise a package. Intended + use is to place the following code in a package's :file:`__init__.py`:: from pkgutil import extend_path __path__ = extend_path(__path__, __name__) - This will add to the package's ``__path__`` all subdirectories of directories on - ``sys.path`` named after the package. This is useful if one wants to distribute - different parts of a single logical package as multiple directories. + This will add to the package's ``__path__`` all subdirectories of directories + on :data:`sys.path` named after the package. This is useful if one wants to + distribute different parts of a single logical package as multiple + directories. - It also looks for :file:`\*.pkg` files beginning where ``*`` matches the *name* - argument. This feature is similar to :file:`\*.pth` files (see the :mod:`site` - module for more information), except that it doesn't special-case lines starting - with ``import``. A :file:`\*.pkg` file is trusted at face value: apart from - checking for duplicates, all entries found in a :file:`\*.pkg` file are added to - the path, regardless of whether they exist on the filesystem. (This is a - feature.) + It also looks for :file:`\*.pkg` files beginning where ``*`` matches the + *name* argument. This feature is similar to :file:`\*.pth` files (see the + :mod:`site` module for more information), except that it doesn't special-case + lines starting with ``import``. A :file:`\*.pkg` file is trusted at face + value: apart from checking for duplicates, all entries found in a + :file:`\*.pkg` file are added to the path, regardless of whether they exist + on the filesystem. (This is a feature.) If the input path is not a list (as is the case for frozen packages) it is returned unchanged. The input path is not modified; an extended copy is returned. Items are only appended to the copy at the end. - It is assumed that ``sys.path`` is a sequence. Items of ``sys.path`` that are - not strings referring to existing directories are ignored. Unicode items on - ``sys.path`` that cause errors when used as filenames may cause this function - to raise an exception (in line with :func:`os.path.isdir` behavior). + It is assumed that :data:`sys.path` is a sequence. Items of :data:`sys.path` + that are not strings referring to existing directories are ignored. Unicode + items on :data:`sys.path` that cause errors when used as filenames may cause + this function to raise an exception (in line with :func:`os.path.isdir` + behavior). + + +.. class:: ImpImporter(dirname=None) + + :pep:`302` Importer that wraps Python's "classic" import algorithm. + + If *dirname* is a string, a :pep:`302` importer is created that searches that + directory. If *dirname* is ``None``, a :pep:`302` importer is created that + searches the current :data:`sys.path`, plus any modules that are frozen or + built-in. + + Note that :class:`ImpImporter` does not currently support being used by + placement on :data:`sys.meta_path`. + + +.. class:: ImpLoader(fullname, file, filename, etc) + + :pep:`302` Loader that wraps Python's "classic" import algorithm. + + +.. function:: find_loader(fullname) + + Find a :pep:`302` "loader" object for *fullname*. + + If *fullname* contains dots, path must be the containing package's + ``__path__``. Returns ``None`` if the module cannot be found or imported. + This function uses :func:`iter_importers`, and is thus subject to the same + limitations regarding platform-specific special import locations such as the + Windows registry. + + +.. function:: get_importer(path_item) + + Retrieve a :pep:`302` importer for the given *path_item*. + + The returned importer is cached in :data:`sys.path_importer_cache` if it was + newly created by a path hook. + + If there is no importer, a wrapper around the basic import machinery is + returned. This wrapper is never inserted into the importer cache (None is + inserted instead). + + The cache (or part of it) can be cleared manually if a rescan of + :data:`sys.path_hooks` is necessary. + + +.. function:: get_loader(module_or_name) + + Get a :pep:`302` "loader" object for *module_or_name*. + + If the module or package is accessible via the normal import mechanism, a + wrapper around the relevant part of that machinery is returned. Returns + ``None`` if the module cannot be found or imported. If the named module is + not already imported, its containing package (if any) is imported, in order + to establish the package ``__path__``. + + This function uses :func:`iter_importers`, and is thus subject to the same + limitations regarding platform-specific special import locations such as the + Windows registry. + + +.. function:: iter_importers(fullname='') + + Yield :pep:`302` importers for the given module name. + + If fullname contains a '.', the importers will be for the package containing + fullname, otherwise they will be importers for :data:`sys.meta_path`, + :data:`sys.path`, and Python's "classic" import machinery, in that order. If + the named module is in a package, that package is imported as a side effect + of invoking this function. + + Non-:pep:`302` mechanisms (e.g. the Windows registry) used by the standard + import machinery to find files in alternative locations are partially + supported, but are searched *after* :data:`sys.path`. Normally, these + locations are searched *before* :data:`sys.path`, preventing :data:`sys.path` + entries from shadowing them. + + For this to cause a visible difference in behaviour, there must be a module + or package name that is accessible via both :data:`sys.path` and one of the + non-:pep:`302` file system mechanisms. In this case, the emulation will find + the former version, while the builtin import mechanism will find the latter. + + Items of the following types can be affected by this discrepancy: + ``imp.C_EXTENSION``, ``imp.PY_SOURCE``, ``imp.PY_COMPILED``, + ``imp.PKG_DIRECTORY``. + + +.. function:: iter_modules(path=None, prefix='') + + Yields ``(module_loader, name, ispkg)`` for all submodules on *path*, or, if + path is ``None``, all top-level modules on :data:`sys.path`. + + *path* should be either ``None`` or a list of paths to look for modules in. + + *prefix* is a string to output on the front of every module name on output. + + +.. function:: walk_packages(path=None, prefix='', onerror=None) + + Yields ``(module_loader, name, ispkg)`` for all modules recursively on + *path*, or, if path is ``None``, all accessible modules. + + *path* should be either ``None`` or a list of paths to look for modules in. + + *prefix* is a string to output on the front of every module name on output. + + Note that this function must import all *packages* (*not* all modules!) on + the given *path*, in order to access the ``__path__`` attribute to find + submodules. + + *onerror* is a function which gets called with one argument (the name of the + package which was being imported) if any exception occurs while trying to + import a package. If no *onerror* function is supplied, :exc:`ImportError`\s + are caught and ignored, while all other exceptions are propagated, + terminating the search. + + Examples:: + + # list all modules python can access + walk_packages() + + # list all submodules of ctypes + walk_packages(ctypes.__path__, ctypes.__name__ + '.') + .. function:: get_data(package, resource) Get a resource from a package. - This is a wrapper for the :pep:`302` loader :func:`get_data` API. The package - argument should be the name of a package, in standard module format - (foo.bar). The resource argument should be in the form of a relative - filename, using ``/`` as the path separator. The parent directory name + This is a wrapper for the :pep:`302` loader :func:`get_data` API. The + *package* argument should be the name of a package, in standard module format + (``foo.bar``). The *resource* argument should be in the form of a relative + filename, using ``/`` as the path separator. The parent directory name ``..`` is not allowed, and nor is a rooted name (starting with a ``/``). - The function returns a binary string that is the contents of the - specified resource. + The function returns a binary string that is the contents of the specified + resource. For packages located in the filesystem, which have already been imported, this is the rough equivalent of:: - d = os.path.dirname(sys.modules[package].__file__) - data = open(os.path.join(d, resource), 'rb').read() + d = os.path.dirname(sys.modules[package].__file__) + data = open(os.path.join(d, resource), 'rb').read() If the package cannot be located or loaded, or it uses a :pep:`302` loader - which does not support :func:`get_data`, then None is returned. + which does not support :func:`get_data`, then ``None`` is returned. -API Reference -============= +Installed distributions database +-------------------------------- -.. automodule:: distutils2._backport.pkgutil - :members: +Installed Python distributions are represented by instances of +:class:`~distutils2._backport.pkgutil.Distribution`, or its subclass +:class:`~distutils2._backport.pkgutil.EggInfoDistribution` for legacy ``.egg`` +and ``.egg-info`` formats). Most functions also provide an extra argument +``use_egg_info`` to take legacy distributions into account. + +.. TODO write docs here, don't rely on automodule + classes: Distribution and descendents + functions: provides, obsoletes, replaces, etc. Caching +++++++ @@ -86,11 +213,10 @@ :func:`~distutils2._backport.pkgutil.clear_cache`. +Examples +-------- -Example Usage -============= - -Print All Information About a Distribution +Print all information about a distribution ++++++++++++++++++++++++++++++++++++++++++ Given a path to a ``.dist-info`` distribution, we shall print out all @@ -182,7 +308,7 @@ ===== * It was installed as a dependency -Find Out Obsoleted Distributions +Find out obsoleted distributions ++++++++++++++++++++++++++++++++ Now, we take tackle a different problem, we are interested in finding out -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: merge latest Message-ID: tarek.ziade pushed cf4e49ee4904 to distutils2: http://hg.python.org/distutils2/rev/cf4e49ee4904 changeset: 945:cf4e49ee4904 parent: 944:c7deaaa88de8 parent: 920:860a4bcab873 user: Gael Pasgrimaud date: Sat Jan 29 16:27:49 2011 +0100 summary: merge latest files: patch diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -660,14 +660,14 @@ _cache_generated_egg = False -def _yield_distributions(include_dist, include_egg): +def _yield_distributions(include_dist, include_egg, paths=sys.path): """ Yield .dist-info and .egg(-info) distributions, based on the arguments :parameter include_dist: yield .dist-info distributions :parameter include_egg: yield .egg(-info) distributions """ - for path in sys.path: + for path in paths: realpath = os.path.realpath(path) if not os.path.isdir(realpath): continue @@ -679,7 +679,7 @@ dir.endswith('.egg')): yield EggInfoDistribution(dist_path) -def _generate_cache(use_egg_info=False): +def _generate_cache(use_egg_info=False, paths=sys.path): global _cache_generated, _cache_generated_egg if _cache_generated_egg or (_cache_generated and not use_egg_info): @@ -688,7 +688,7 @@ gen_dist = not _cache_generated gen_egg = use_egg_info - for dist in _yield_distributions(gen_dist, gen_egg): + for dist in _yield_distributions(gen_dist, gen_egg, paths): if isinstance(dist, Distribution): _cache_path[dist.path] = dist if not dist.name in _cache_name: @@ -1017,7 +1017,7 @@ return '-'.join([name, normalized_version]) + file_extension -def get_distributions(use_egg_info=False): +def get_distributions(use_egg_info=False, paths=sys.path): """ Provides an iterator that looks for ``.dist-info`` directories in ``sys.path`` and returns :class:`Distribution` instances for each one of @@ -1028,7 +1028,7 @@ instances """ if not _cache_enabled: - for dist in _yield_distributions(True, use_egg_info): + for dist in _yield_distributions(True, use_egg_info, paths): yield dist else: _generate_cache(use_egg_info) @@ -1041,7 +1041,7 @@ yield dist -def get_distribution(name, use_egg_info=False): +def get_distribution(name, use_egg_info=False, paths=sys.path): """ Scans all elements in ``sys.path`` and looks for all directories ending with ``.dist-info``. Returns a :class:`Distribution` @@ -1059,7 +1059,7 @@ :rtype: :class:`Distribution` or :class:`EggInfoDistribution` or None """ if not _cache_enabled: - for dist in _yield_distributions(True, use_egg_info): + for dist in _yield_distributions(True, use_egg_info, paths): if dist.name == name: return dist else: diff --git a/distutils2/command/sdist.py b/distutils2/command/sdist.py --- a/distutils2/command/sdist.py +++ b/distutils2/command/sdist.py @@ -215,8 +215,6 @@ def add_defaults(self): """Add all the default files to self.filelist: - - README or README.txt - - test/test*.py - all pure Python modules mentioned in setup script - all files pointed by package_data (build_py) - all files defined in data_files. @@ -226,32 +224,6 @@ Warns if (README or README.txt) or setup.py are missing; everything else is optional. """ - standards = [('README', 'README.txt')] - for fn in standards: - if isinstance(fn, tuple): - alts = fn - got_it = 0 - for fn in alts: - if os.path.exists(fn): - got_it = 1 - self.filelist.append(fn) - break - - if not got_it: - self.warn("standard file not found: should have one of " + - string.join(alts, ', ')) - else: - if os.path.exists(fn): - self.filelist.append(fn) - else: - self.warn("standard file '%s' not found" % fn) - - optional = ['test/test*.py', 'setup.cfg'] - for pattern in optional: - files = filter(os.path.isfile, glob(pattern)) - if files: - self.filelist.extend(files) - for cmd_name in get_command_names(): try: cmd_obj = self.get_finalized_command(cmd_name) @@ -323,7 +295,7 @@ for file in self.distribution.metadata.requires_files: if file not in files: - msg = "'%s' must be included explicitly extra-files metadata" % file + msg = "'%s' must be included explicitly in 'extra_files'" % file raise DistutilsFileError(msg) for file in files: @@ -383,4 +355,3 @@ # Now create them for dir in need_dirs: self.mkpath(dir, mode, verbose=verbose, dry_run=dry_run) - diff --git a/distutils2/markers.py b/distutils2/markers.py new file mode 100644 --- /dev/null +++ b/distutils2/markers.py @@ -0,0 +1,194 @@ +""" Micro-language for PEP 345 environment markers +""" +import sys +import platform +import os +from tokenize import tokenize, NAME, OP, STRING, ENDMARKER +from StringIO import StringIO + +__all__ = ['interpret'] + + +# allowed operators +_OPERATORS = {'==': lambda x, y: x == y, + '!=': lambda x, y: x != y, + '>': lambda x, y: x > y, + '>=': lambda x, y: x >= y, + '<': lambda x, y: x < y, + '<=': lambda x, y: x <= y, + 'in': lambda x, y: x in y, + 'not in': lambda x, y: x not in y} + + +def _operate(operation, x, y): + return _OPERATORS[operation](x, y) + + +# restricted set of variables +_VARS = {'sys.platform': sys.platform, + 'python_version': sys.version[:3], + 'python_full_version': sys.version.split(' ', 1)[0], + 'os.name': os.name, + 'platform.version': platform.version(), + 'platform.machine': platform.machine()} + + +class _Operation(object): + + def __init__(self, execution_context=None): + self.left = None + self.op = None + self.right = None + if execution_context is None: + execution_context = {} + self.execution_context = execution_context + + def _get_var(self, name): + if name in self.execution_context: + return self.execution_context[name] + return _VARS[name] + + def __repr__(self): + return '%s %s %s' % (self.left, self.op, self.right) + + def _is_string(self, value): + if value is None or len(value) < 2: + return False + for delimiter in '"\'': + if value[0] == value[-1] == delimiter: + return True + return False + + def _is_name(self, value): + return value in _VARS + + def _convert(self, value): + if value in _VARS: + return self._get_var(value) + return value.strip('"\'') + + def _check_name(self, value): + if value not in _VARS: + raise NameError(value) + + def _nonsense_op(self): + msg = 'This operation is not supported : "%s"' % self + raise SyntaxError(msg) + + def __call__(self): + # make sure we do something useful + if self._is_string(self.left): + if self._is_string(self.right): + self._nonsense_op() + self._check_name(self.right) + else: + if not self._is_string(self.right): + self._nonsense_op() + self._check_name(self.left) + + if self.op not in _OPERATORS: + raise TypeError('Operator not supported "%s"' % self.op) + + left = self._convert(self.left) + right = self._convert(self.right) + return _operate(self.op, left, right) + + +class _OR(object): + def __init__(self, left, right=None): + self.left = left + self.right = right + + def filled(self): + return self.right is not None + + def __repr__(self): + return 'OR(%r, %r)' % (self.left, self.right) + + def __call__(self): + return self.left() or self.right() + + +class _AND(object): + def __init__(self, left, right=None): + self.left = left + self.right = right + + def filled(self): + return self.right is not None + + def __repr__(self): + return 'AND(%r, %r)' % (self.left, self.right) + + def __call__(self): + return self.left() and self.right() + + +class _CHAIN(object): + + def __init__(self, execution_context=None): + self.ops = [] + self.op_starting = True + self.execution_context = execution_context + + def eat(self, toktype, tokval, rowcol, line, logical_line): + if toktype not in (NAME, OP, STRING, ENDMARKER): + raise SyntaxError('Type not supported "%s"' % tokval) + + if self.op_starting: + op = _Operation(self.execution_context) + if len(self.ops) > 0: + last = self.ops[-1] + if isinstance(last, (_OR, _AND)) and not last.filled(): + last.right = op + else: + self.ops.append(op) + else: + self.ops.append(op) + self.op_starting = False + else: + op = self.ops[-1] + + if (toktype == ENDMARKER or + (toktype == NAME and tokval in ('and', 'or'))): + if toktype == NAME and tokval == 'and': + self.ops.append(_AND(self.ops.pop())) + elif toktype == NAME and tokval == 'or': + self.ops.append(_OR(self.ops.pop())) + self.op_starting = True + return + + if isinstance(op, (_OR, _AND)) and op.right is not None: + op = op.right + + if ((toktype in (NAME, STRING) and tokval not in ('in', 'not')) + or (toktype == OP and tokval == '.')): + if op.op is None: + if op.left is None: + op.left = tokval + else: + op.left += tokval + else: + if op.right is None: + op.right = tokval + else: + op.right += tokval + elif toktype == OP or tokval in ('in', 'not'): + if tokval == 'in' and op.op == 'not': + op.op = 'not in' + else: + op.op = tokval + + def result(self): + for op in self.ops: + if not op(): + return False + return True + + +def interpret(marker, execution_context=None): + """Interpret a marker and return a result depending on environment.""" + marker = marker.strip() + operations = _CHAIN(execution_context) + tokenize(StringIO(marker).readline, operations.eat) + return operations.result() diff --git a/distutils2/metadata.py b/distutils2/metadata.py --- a/distutils2/metadata.py +++ b/distutils2/metadata.py @@ -5,13 +5,12 @@ import os import sys -import platform import re from StringIO import StringIO from email import message_from_file -from tokenize import tokenize, NAME, OP, STRING, ENDMARKER from distutils2 import logger +from distutils2.markers import interpret from distutils2.version import (is_valid_predicate, is_valid_version, is_valid_versions) from distutils2.errors import (MetadataMissingError, @@ -291,7 +290,7 @@ if not self.platform_dependent or ';' not in value: return True, value value, marker = value.split(';') - return _interpret(marker, self.execution_context), value + return interpret(marker, self.execution_context), value def _remove_line_prefix(self, value): return _LINE_PREFIX.sub('\n', value) @@ -518,191 +517,3 @@ def items(self): """Dict like api""" return [(key, self[key]) for key in self.keys()] - - -# -# micro-language for PEP 345 environment markers -# - -# allowed operators -_OPERATORS = {'==': lambda x, y: x == y, - '!=': lambda x, y: x != y, - '>': lambda x, y: x > y, - '>=': lambda x, y: x >= y, - '<': lambda x, y: x < y, - '<=': lambda x, y: x <= y, - 'in': lambda x, y: x in y, - 'not in': lambda x, y: x not in y} - - -def _operate(operation, x, y): - return _OPERATORS[operation](x, y) - -# restricted set of variables -_VARS = {'sys.platform': sys.platform, - 'python_version': sys.version[:3], - 'python_full_version': sys.version.split(' ', 1)[0], - 'os.name': os.name, - 'platform.version': platform.version(), - 'platform.machine': platform.machine()} - - -class _Operation(object): - - def __init__(self, execution_context=None): - self.left = None - self.op = None - self.right = None - if execution_context is None: - execution_context = {} - self.execution_context = execution_context - - def _get_var(self, name): - if name in self.execution_context: - return self.execution_context[name] - return _VARS[name] - - def __repr__(self): - return '%s %s %s' % (self.left, self.op, self.right) - - def _is_string(self, value): - if value is None or len(value) < 2: - return False - for delimiter in '"\'': - if value[0] == value[-1] == delimiter: - return True - return False - - def _is_name(self, value): - return value in _VARS - - def _convert(self, value): - if value in _VARS: - return self._get_var(value) - return value.strip('"\'') - - def _check_name(self, value): - if value not in _VARS: - raise NameError(value) - - def _nonsense_op(self): - msg = 'This operation is not supported : "%s"' % self - raise SyntaxError(msg) - - def __call__(self): - # make sure we do something useful - if self._is_string(self.left): - if self._is_string(self.right): - self._nonsense_op() - self._check_name(self.right) - else: - if not self._is_string(self.right): - self._nonsense_op() - self._check_name(self.left) - - if self.op not in _OPERATORS: - raise TypeError('Operator not supported "%s"' % self.op) - - left = self._convert(self.left) - right = self._convert(self.right) - return _operate(self.op, left, right) - - -class _OR(object): - def __init__(self, left, right=None): - self.left = left - self.right = right - - def filled(self): - return self.right is not None - - def __repr__(self): - return 'OR(%r, %r)' % (self.left, self.right) - - def __call__(self): - return self.left() or self.right() - - -class _AND(object): - def __init__(self, left, right=None): - self.left = left - self.right = right - - def filled(self): - return self.right is not None - - def __repr__(self): - return 'AND(%r, %r)' % (self.left, self.right) - - def __call__(self): - return self.left() and self.right() - - -class _CHAIN(object): - - def __init__(self, execution_context=None): - self.ops = [] - self.op_starting = True - self.execution_context = execution_context - - def eat(self, toktype, tokval, rowcol, line, logical_line): - if toktype not in (NAME, OP, STRING, ENDMARKER): - raise SyntaxError('Type not supported "%s"' % tokval) - - if self.op_starting: - op = _Operation(self.execution_context) - if len(self.ops) > 0: - last = self.ops[-1] - if isinstance(last, (_OR, _AND)) and not last.filled(): - last.right = op - else: - self.ops.append(op) - else: - self.ops.append(op) - self.op_starting = False - else: - op = self.ops[-1] - - if (toktype == ENDMARKER or - (toktype == NAME and tokval in ('and', 'or'))): - if toktype == NAME and tokval == 'and': - self.ops.append(_AND(self.ops.pop())) - elif toktype == NAME and tokval == 'or': - self.ops.append(_OR(self.ops.pop())) - self.op_starting = True - return - - if isinstance(op, (_OR, _AND)) and op.right is not None: - op = op.right - - if ((toktype in (NAME, STRING) and tokval not in ('in', 'not')) - or (toktype == OP and tokval == '.')): - if op.op is None: - if op.left is None: - op.left = tokval - else: - op.left += tokval - else: - if op.right is None: - op.right = tokval - else: - op.right += tokval - elif toktype == OP or tokval in ('in', 'not'): - if tokval == 'in' and op.op == 'not': - op.op = 'not in' - else: - op.op = tokval - - def result(self): - for op in self.ops: - if not op(): - return False - return True - - -def _interpret(marker, execution_context=None): - """Interpret a marker and return a result depending on environment.""" - marker = marker.strip() - operations = _CHAIN(execution_context) - tokenize(StringIO(marker).readline, operations.eat) - return operations.result() diff --git a/distutils2/tests/test_command_sdist.py b/distutils2/tests/test_command_sdist.py --- a/distutils2/tests/test_command_sdist.py +++ b/distutils2/tests/test_command_sdist.py @@ -45,7 +45,6 @@ MANIFEST = """\ # file GENERATED by distutils, do NOT edit -README inroot.txt data%(sep)sdata.dt scripts%(sep)sscript.py @@ -141,7 +140,7 @@ zip_file.close() # making sure everything has been pruned correctly - self.assertEqual(len(content), 3) + self.assertEqual(len(content), 2) @unittest.skipUnless(zlib, "requires zlib") def test_make_distribution(self): @@ -236,7 +235,7 @@ zip_file.close() # making sure everything was added - self.assertEqual(len(content), 10) + self.assertEqual(len(content), 9) # checking the MANIFEST manifest = open(join(self.tmp_dir, 'MANIFEST')).read() @@ -362,8 +361,7 @@ if line.strip() != ''] finally: f.close() - - self.assertEqual(len(manifest), 4) + self.assertEqual(len(manifest), 3) # adding a file self.write_file((self.tmp_dir, 'somecode', 'doc2.txt'), '#') @@ -383,7 +381,7 @@ f.close() # do we have the new file in MANIFEST ? - self.assertEqual(len(manifest2), 5) + self.assertEqual(len(manifest2), 4) self.assertIn('doc2.txt', manifest2[-1]) def test_manifest_marker(self): diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -280,7 +280,8 @@ def test_metadata_requires_description_files(self): tempdir = self.mkdtemp() os.chdir(tempdir) - self.write_setup({'description-file': 'README\n README2', 'extra-files':'\n README2'}) + self.write_setup({'description-file': 'README\n README2', + 'extra-files':'\n README2'}) self.write_file('README', 'yeah') self.write_file('README2', 'yeah') self.write_file('haven.py', '#') @@ -302,10 +303,17 @@ cmd = sdist(dist) cmd.finalize_options() cmd.get_file_list() + self.assertRaises(DistutilsFileError, cmd.make_distribution) + + self.write_setup({'description-file': 'README\n README2', + 'extra-files': '\n README2\n README'}) + dist = self.run_setup('--description') + cmd = sdist(dist) + cmd.finalize_options() + cmd.get_file_list() cmd.make_distribution() self.assertIn('README\nREADME2\n', open('MANIFEST').read()) - def test_sub_commands(self): tempdir = self.mkdtemp() os.chdir(tempdir) diff --git a/distutils2/tests/test_markers.py b/distutils2/tests/test_markers.py new file mode 100644 --- /dev/null +++ b/distutils2/tests/test_markers.py @@ -0,0 +1,69 @@ +"""Tests for distutils.metadata.""" +import os +import sys +import platform +from StringIO import StringIO + +from distutils2.markers import interpret +from distutils2.tests import run_unittest, unittest +from distutils2.tests.support import LoggingCatcher, WarningsCatcher + + +class MarkersTestCase(LoggingCatcher, WarningsCatcher, + unittest.TestCase): + + def test_interpret(self): + sys_platform = sys.platform + version = sys.version.split()[0] + os_name = os.name + platform_version = platform.version() + platform_machine = platform.machine() + + self.assertTrue(interpret("sys.platform == '%s'" % sys_platform)) + self.assertTrue(interpret( + "sys.platform == '%s' or python_version == '2.4'" % sys_platform)) + self.assertTrue(interpret( + "sys.platform == '%s' and python_full_version == '%s'" % + (sys_platform, version))) + self.assertTrue(interpret("'%s' == sys.platform" % sys_platform)) + self.assertTrue(interpret('os.name == "%s"' % os_name)) + self.assertTrue(interpret( + 'platform.version == "%s" and platform.machine == "%s"' % + (platform_version, platform_machine))) + + # stuff that need to raise a syntax error + ops = ('os.name == os.name', 'os.name == 2', "'2' == '2'", + 'okpjonon', '', 'os.name ==', 'python_version == 2.4') + for op in ops: + self.assertRaises(SyntaxError, interpret, op) + + # combined operations + OP = 'os.name == "%s"' % os_name + AND = ' and ' + OR = ' or ' + self.assertTrue(interpret(OP + AND + OP)) + self.assertTrue(interpret(OP + AND + OP + AND + OP)) + self.assertTrue(interpret(OP + OR + OP)) + self.assertTrue(interpret(OP + OR + OP + OR + OP)) + + # other operators + self.assertTrue(interpret("os.name != 'buuuu'")) + self.assertTrue(interpret("python_version > '1.0'")) + self.assertTrue(interpret("python_version < '5.0'")) + self.assertTrue(interpret("python_version <= '5.0'")) + self.assertTrue(interpret("python_version >= '1.0'")) + self.assertTrue(interpret("'%s' in os.name" % os_name)) + self.assertTrue(interpret("'buuuu' not in os.name")) + self.assertTrue(interpret( + "'buuuu' not in os.name and '%s' in os.name" % os_name)) + + # execution context + self.assertTrue(interpret('python_version == "0.1"', + {'python_version': '0.1'})) + + +def test_suite(): + return unittest.makeSuite(MarkersTestCase) + +if __name__ == '__main__': + run_unittest(test_suite()) diff --git a/distutils2/tests/test_metadata.py b/distutils2/tests/test_metadata.py --- a/distutils2/tests/test_metadata.py +++ b/distutils2/tests/test_metadata.py @@ -1,10 +1,10 @@ -"""Tests for distutils.command.bdist.""" +"""Tests for distutils.metadata.""" import os import sys import platform from StringIO import StringIO -from distutils2.metadata import (DistributionMetadata, _interpret, +from distutils2.metadata import (DistributionMetadata, PKG_INFO_PREFERRED_VERSION) from distutils2.tests import run_unittest, unittest from distutils2.tests.support import LoggingCatcher, WarningsCatcher @@ -46,55 +46,6 @@ self.assertRaises(TypeError, DistributionMetadata, PKG_INFO, mapping=m, fileobj=fp) - def test_interpret(self): - sys_platform = sys.platform - version = sys.version.split()[0] - os_name = os.name - platform_version = platform.version() - platform_machine = platform.machine() - - self.assertTrue(_interpret("sys.platform == '%s'" % sys_platform)) - self.assertTrue(_interpret( - "sys.platform == '%s' or python_version == '2.4'" % sys_platform)) - self.assertTrue(_interpret( - "sys.platform == '%s' and python_full_version == '%s'" % - (sys_platform, version))) - self.assertTrue(_interpret("'%s' == sys.platform" % sys_platform)) - self.assertTrue(_interpret('os.name == "%s"' % os_name)) - self.assertTrue(_interpret( - 'platform.version == "%s" and platform.machine == "%s"' % - (platform_version, platform_machine))) - - # stuff that need to raise a syntax error - ops = ('os.name == os.name', 'os.name == 2', "'2' == '2'", - 'okpjonon', '', 'os.name ==', 'python_version == 2.4') - for op in ops: - self.assertRaises(SyntaxError, _interpret, op) - - # combined operations - OP = 'os.name == "%s"' % os_name - AND = ' and ' - OR = ' or ' - self.assertTrue(_interpret(OP + AND + OP)) - self.assertTrue(_interpret(OP + AND + OP + AND + OP)) - self.assertTrue(_interpret(OP + OR + OP)) - self.assertTrue(_interpret(OP + OR + OP + OR + OP)) - - # other operators - self.assertTrue(_interpret("os.name != 'buuuu'")) - self.assertTrue(_interpret("python_version > '1.0'")) - self.assertTrue(_interpret("python_version < '5.0'")) - self.assertTrue(_interpret("python_version <= '5.0'")) - self.assertTrue(_interpret("python_version >= '1.0'")) - self.assertTrue(_interpret("'%s' in os.name" % os_name)) - self.assertTrue(_interpret("'buuuu' not in os.name")) - self.assertTrue(_interpret( - "'buuuu' not in os.name and '%s' in os.name" % os_name)) - - # execution context - self.assertTrue(_interpret('python_version == "0.1"', - {'python_version': '0.1'})) - def test_metadata_read_write(self): PKG_INFO = os.path.join(os.path.dirname(__file__), 'PKG-INFO') metadata = DistributionMetadata(PKG_INFO) diff --git a/docs/source/setupcfg.rst b/docs/source/setupcfg.rst --- a/docs/source/setupcfg.rst +++ b/docs/source/setupcfg.rst @@ -128,6 +128,8 @@ This section describes the files included in the project. +- **packages_root**: the root directory containing all packages. If not provided + Distutils2 will use the current directory. *\*optional* - **packages**: a list of packages the project includes *\*optional* *\*multi* - **modules**: a list of packages the project includes *\*optional* *\*multi* - **scripts**: a list of scripts the project includes *\*optional* *\*multi* @@ -136,6 +138,7 @@ Example:: [files] + packages_root = src packages = pypi2rpm pypi2rpm.command diff --git a/patch b/patch deleted file mode 100644 --- a/patch +++ /dev/null @@ -1,23 +0,0 @@ -diff -r 5603e1bc5442 distutils2/util.py ---- a/distutils2/util.py Fri Jan 28 18:42:44 2011 +0100 -+++ b/distutils2/util.py Sat Jan 29 02:39:55 2011 +0100 -@@ -1203,12 +1203,13 @@ - in_cfg_value = has_get_option(config, section, option) - if not in_cfg_value: - # There is no such option in the setup.cfg -- continue -- -- if arg == "long_description": -- filename = has_get_option("description_file") -- if filename: -- in_cfg_value = open(filename).read() -+ if arg == "long_description": -+ filename = has_get_option(config, section, "description_file") -+ print "We have a filename", filename -+ if filename: -+ in_cfg_value = open(filename).read() -+ else: -+ continue - - if arg in MULTI_FIELDS: - # Special behaviour when we have a multi line option -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: first implementation of the remove() method Message-ID: tarek.ziade pushed b119d089a91b to distutils2: http://hg.python.org/distutils2/rev/b119d089a91b changeset: 947:b119d089a91b user: Gael Pasgrimaud date: Sat Jan 29 17:25:43 2011 +0100 summary: first implementation of the remove() method files: distutils2/install.py distutils2/tests/support.py distutils2/tests/test_uninstall.py diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -2,10 +2,14 @@ import logging import shutil import os +import sys +import stat import errno import itertools +import tempfile from distutils2._backport.pkgutil import get_distributions +from distutils2._backport.pkgutil import get_distribution from distutils2.depgraph import generate_graph from distutils2.index import wrapper from distutils2.index.errors import ProjectNotFound, ReleaseNotFound @@ -208,10 +212,38 @@ infos[key].extend(new_infos[key]) -def remove(project_name): +def remove(project_name, paths=sys.path): """Removes a single project from the installation""" - pass + tmp = tempfile.mkdtemp(prefix=project_name+'-uninstall') + dist = get_distribution(project_name, paths=paths) + files = dist.get_installed_files(local=True) + rmdirs = [] + rmfiles = [] + try: + for file, md5, size in files: + if os.path.isfile(file): + dirname, filename = os.path.split(file) + tmpfile = os.path.join(tmp, filename) + try: + os.rename(file, tmpfile) + finally: + if not os.path.isfile(file): + os.rename(tmpfile, file) + if file not in rmfiles: + rmfiles.append(file) + if dirname not in rmdirs: + rmdirs.append(dirname) + except OSError: + os.rmdir(tmp) + + for file in rmfiles: + os.remove(file) + + for dirname in rmdirs: + if not os.listdir(dirname): + if bool(os.stat(dirname).st_mode & stat.S_IWUSR): + os.rmdir(dirname) diff --git a/distutils2/tests/support.py b/distutils2/tests/support.py --- a/distutils2/tests/support.py +++ b/distutils2/tests/support.py @@ -167,6 +167,9 @@ raise AssertionError( '%s not found. %s does not exist' % (file, dirname)) + def assertIsNotFile(self, *args): + path = os.path.join(*args) + assert not os.path.isfile(path), "%s exist" % path class EnvironGuard(object): """TestCase-compatible mixin to save and restore the environment.""" diff --git a/distutils2/tests/test_uninstall.py b/distutils2/tests/test_uninstall.py new file mode 100644 --- /dev/null +++ b/distutils2/tests/test_uninstall.py @@ -0,0 +1,86 @@ +"""Tests for the uninstall command.""" +import os +import sys +from StringIO import StringIO +from distutils2.tests import unittest, support, run_unittest +from distutils2.install import remove + +SETUP_CFG = """ +[metadata] +name = %(name)s +version = %(version)s + +[files] +packages = + %(name)s + %(name)s.sub +""" + +class UninstallTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def setUp(self): + super(UninstallTestCase, self).setUp() + self.addCleanup(setattr, sys, 'stdout', sys.stdout) + self.addCleanup(setattr, sys, 'stderr', sys.stderr) + self.addCleanup(os.chdir, os.getcwd()) + self.root_dir = self.mkdtemp() + + def run_setup(self, *args): + # run setup with args + #sys.stdout = StringIO() + sys.argv[:] = [''] + list(args) + old_sys = sys.argv[:] + try: + from distutils2.run import commands_main + dist = commands_main() + finally: + sys.argv[:] = old_sys + return dist + + def get_path(self, dist, name): + from distutils2.command.install_dist import install_dist + cmd = install_dist(dist) + cmd.prefix = self.root_dir + cmd.finalize_options() + return getattr(cmd, 'install_'+name) + + def make_dist(self, pkg_name='foo', **kw): + dirname = self.mkdtemp() + kw['name'] = pkg_name + if 'version' not in kw: + kw['version'] = '0.1' + self.write_file((dirname, 'setup.cfg'), SETUP_CFG % kw) + os.mkdir(os.path.join(dirname, pkg_name)) + self.write_file((dirname, '__init__.py'), '#') + self.write_file((dirname, pkg_name+'_utils.py'), '#') + os.mkdir(os.path.join(dirname, pkg_name, 'sub')) + self.write_file((dirname, pkg_name, 'sub', '__init__.py'), '#') + self.write_file((dirname, pkg_name, 'sub', pkg_name+'_utils.py'), '#') + return dirname + + def install_dist(self, pkg_name='foo', dirname=None, **kw): + if not dirname: + dirname = self.make_dist(pkg_name, **kw) + os.chdir(dirname) + dist = self.run_setup('install_dist', '--prefix='+self.root_dir) + install_lib = self.get_path(dist, 'purelib') + return dist, install_lib + + def test_uninstall(self): + dist, install_lib = self.install_dist() + self.assertIsFile(install_lib, 'foo', 'sub', '__init__.py') + self.assertIsFile(install_lib, 'foo-0.1.dist-info', 'RECORD') + remove('foo', paths=[install_lib]) + self.assertIsNotFile(install_lib, 'foo', 'sub', '__init__.py') + self.assertIsNotFile(install_lib, 'foo-0.1.dist-info', 'RECORD') + + + + +def test_suite(): + return unittest.makeSuite(UninstallTestCase) + +if __name__ == '__main__': + run_unittest(test_suite()) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: raise if the distribution is not found. also disable cache for testing Message-ID: tarek.ziade pushed f31564d7ed76 to distutils2: http://hg.python.org/distutils2/rev/f31564d7ed76 changeset: 949:f31564d7ed76 user: Gael Pasgrimaud date: Sat Jan 29 18:02:19 2011 +0100 summary: raise if the distribution is not found. also disable cache for testing files: distutils2/install.py distutils2/tests/test_uninstall.py diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -9,12 +9,12 @@ from distutils2 import logger from distutils2._backport.pkgutil import get_distributions -<<<<<<< local from distutils2._backport.pkgutil import get_distribution from distutils2._backport.sysconfig import get_config_var from distutils2.depgraph import generate_graph from distutils2.index import wrapper from distutils2.index.errors import ProjectNotFound, ReleaseNotFound +from distutils2.errors import DistutilsError from distutils2.version import get_version_predicate """Provides installations scripts. @@ -319,6 +319,8 @@ """Removes a single project from the installation""" tmp = tempfile.mkdtemp(prefix=project_name+'-uninstall') dist = get_distribution(project_name, paths=paths) + if dist is None: + raise DistutilsError('Distribution %s not found' % project_name) files = dist.get_installed_files(local=True) rmdirs = [] rmfiles = [] diff --git a/distutils2/tests/test_uninstall.py b/distutils2/tests/test_uninstall.py --- a/distutils2/tests/test_uninstall.py +++ b/distutils2/tests/test_uninstall.py @@ -2,7 +2,9 @@ import os import sys from StringIO import StringIO +from distutils2._backport.pkgutil import disable_cache, enable_cache from distutils2.tests import unittest, support, run_unittest +from distutils2.errors import DistutilsError from distutils2.install import remove SETUP_CFG = """ @@ -25,7 +27,9 @@ self.addCleanup(setattr, sys, 'stdout', sys.stdout) self.addCleanup(setattr, sys, 'stderr', sys.stderr) self.addCleanup(os.chdir, os.getcwd()) + self.addCleanup(enable_cache) self.root_dir = self.mkdtemp() + disable_cache() def run_setup(self, *args): # run setup with args @@ -68,6 +72,9 @@ install_lib = self.get_path(dist, 'purelib') return dist, install_lib + def test_uninstall_unknow_distribution(self): + self.assertRaises(DistutilsError, remove, 'foo', paths=[self.root_dir]) + def test_uninstall(self): dist, install_lib = self.install_dist() self.assertIsFile(install_lib, 'foo', 'sub', '__init__.py') -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: merge with Alain Message-ID: tarek.ziade pushed 20b7b525914c to distutils2: http://hg.python.org/distutils2/rev/20b7b525914c changeset: 951:20b7b525914c parent: 943:3bb80edf7d81 parent: 950:8f043681485c user: Alexis Metaireau date: Sat Jan 29 18:07:02 2011 +0100 summary: merge with Alain files: diff --git a/distutils2/mkcfg.py b/distutils2/mkcfg.py --- a/distutils2/mkcfg.py +++ b/distutils2/mkcfg.py @@ -20,17 +20,27 @@ # Ask for the dependencies. # Ask for the Requires-Dist # Ask for the Provides-Dist +# Ask for a description # Detect scripts (not sure how. #! outside of package?) import os import sys import re import shutil +import glob +import re from ConfigParser import RawConfigParser from textwrap import dedent +if sys.version_info[:2] < (2, 6): + from sets import Set as set +try: + from hashlib import md5 +except ImportError: + from md5 import md5 # importing this with an underscore as it should be replaced by the # dict form or another structures for all purposes from distutils2._trove import all_classifiers as _CLASSIFIERS_LIST +from distutils2._backport import sysconfig _FILENAME = 'setup.cfg' @@ -82,6 +92,10 @@ Optionally, you can set other trove identifiers for things such as the human language, programming language, user interface, etc... ''', + 'setup.py found':''' +The setup.py script will be executed to retrieve the metadata. +A wizard will be run if you answer "n", +''' } # XXX everything needs docstrings and tests (both low-level tests of various @@ -158,16 +172,18 @@ LICENCES = _build_licences(_CLASSIFIERS_LIST) - class MainProgram(object): def __init__(self): self.configparser = None - self.classifiers = {} + self.classifiers = set([]) self.data = {} self.data['classifier'] = self.classifiers self.data['packages'] = [] self.data['modules'] = [] + self.data['platform'] = [] + self.data['resources'] = [] self.data['extra_files'] = [] + self.data['scripts'] = [] self.load_config_file() def lookup_option(self, key): @@ -178,6 +194,7 @@ def load_config_file(self): self.configparser = RawConfigParser() # TODO replace with section in distutils config file + #XXX freedesktop self.configparser.read(os.path.expanduser('~/.mkcfg')) self.data['author'] = self.lookup_option('author') self.data['author_email'] = self.lookup_option('author_email') @@ -194,6 +211,7 @@ if not valuesDifferent: return + #XXX freedesktop fp = open(os.path.expanduser('~/.mkcfgpy'), 'w') try: self.configparser.write(fp) @@ -201,19 +219,118 @@ fp.close() def load_existing_setup_script(self): - raise NotImplementedError - # Ideas: - # - define a mock module to assign to sys.modules['distutils'] before - # importing the setup script as a module (or executing it); it would - # provide setup (a function that just returns its args as a dict), - # Extension (ditto), find_packages (the real function) - # - we could even mock Distribution and commands to handle more setup - # scripts - # - we could use a sandbox (http://bugs.python.org/issue8680) - # - the cleanest way is to parse the file, not import it, but there is - # no way to do that across versions (the compiler package is - # deprecated or removed in recent Pythons, the ast module is not - # present before 2.6) + """ Generate a setup.cfg from an existing setup.py. + + It only exports the distutils metadata (setuptools specific metadata + is not actually supported). + """ + setuppath = 'setup.py' + if not os.path.exists(setuppath): + return + else: + ans = ask_yn(('A legacy setup.py has been found.\n' + 'Would you like to convert it to a setup.cfg ?'), + 'y', + _helptext['setup.py found']) + if ans != 'y': + return + + #_______mock setup start + data = self.data + def setup(**attrs): + """Mock the setup(**attrs) in order to retrive metadata.""" + # use the distutils v1 processings to correctly parse metadata. + #XXX we could also use the setuptools distibution ??? + from distutils.dist import Distribution + dist = Distribution(attrs) + dist.parse_config_files() + # 1. retrieves metadata that are quite similar PEP314<->PEP345 + labels = (('name',) * 2, + ('version',) * 2, + ('author',) * 2, + ('author_email',) * 2, + ('maintainer',) * 2, + ('maintainer_email',) * 2, + ('description', 'summary'), + ('long_description', 'description'), + ('url', 'home_page'), + ('platforms', 'platform'), + ('provides', 'provides-dist'), + ('obsoletes', 'obsoletes-dist'), + ('requires', 'requires-dist'),) + get = lambda lab: getattr(dist.metadata, lab.replace('-', '_')) + data.update((new, get(old)) for (old, new) in labels if get(old)) + # 2. retrieves data that requires special processings. + data['classifier'].update(dist.get_classifiers() or []) + data['scripts'].extend(dist.scripts or []) + data['packages'].extend(dist.packages or []) + data['modules'].extend(dist.py_modules or []) + # 2.1 data_files -> resources. + if len(dist.data_files) < 2 or isinstance(dist.data_files[1], str): + dist.data_files = [('', dist.data_files)] + #add tokens in the destination paths + vars = {'distribution.name':data['name']} + path_tokens = sysconfig.get_paths(vars=vars).items() + #sort tokens to use the longest one first + path_tokens.sort(cmp=lambda x,y: cmp(len(y), len(x)), + key=lambda x: x[1]) + for dest, srcs in (dist.data_files or []): + dest = os.path.join(sys.prefix, dest) + for tok, path in path_tokens: + if dest.startswith(path): + dest = ('{%s}' % tok) + dest[len(path):] + files = [('/ '.join(src.rsplit('/', 1)), dest) + for src in srcs] + data['resources'].extend(files) + continue + # 2.2 package_data -> extra_files + package_dirs = dist.package_dir or {} + for package, extras in dist.package_data.iteritems() or []: + package_dir = package_dirs.get(package, package) + fils = [os.path.join(package_dir, fil) for fil in extras] + data['extra_files'].extend(fils) + + # Use README file if its content is the desciption + if "description" in data: + ref = md5(re.sub('\s', '', self.data['description']).lower()) + ref = ref.digest() + for readme in glob.glob('README*'): + fob = open(readme) + val = md5(re.sub('\s', '', fob.read()).lower()).digest() + fob.close() + if val == ref: + del data['description'] + data['description-file'] = readme + break + #_________ mock setup end + + # apply monkey patch to distutils (v1) and setuptools (if needed) + # (abord the feature if distutils v1 has been killed) + try: + import distutils.core as DC + getattr(DC, 'setup') # ensure distutils v1 + except ImportError, AttributeError: + return + saved_setups = [(DC, DC.setup)] + DC.setup = setup + try: + import setuptools + saved_setups.append((setuptools, setuptools.setup)) + setuptools.setup = setup + except ImportError, AttributeError: + pass + # get metadata by executing the setup.py with the patched setup(...) + success = False # for python < 2.4 + try: + pyenv = globals().copy() + execfile(setuppath, pyenv) + success = True + finally: #revert monkey patches + for patched_module, original_setup in saved_setups: + patched_module.setup = original_setup + if not self.data: + raise ValueError('Unable to load metadata from setup.py') + return success def inspect_file(self, path): fp = open(path, 'r') @@ -222,9 +339,11 @@ m = re.match(r'^#!.*python((?P\d)(\.\d+)?)?$', line) if m: if m.group('major') == '3': - self.classifiers['Programming Language :: Python :: 3'] = 1 + self.classifiers.add( + 'Programming Language :: Python :: 3') else: - self.classifiers['Programming Language :: Python :: 2'] = 1 + self.classifiers.add( + 'Programming Language :: Python :: 2') finally: fp.close() @@ -370,7 +489,7 @@ for key in sorted(trove): if len(trove[key]) == 0: if ask_yn('Add "%s"' % desc[4:] + ' :: ' + key, 'n') == 'y': - classifiers[desc[4:] + ' :: ' + key] = 1 + classifiers.add(desc[4:] + ' :: ' + key) continue if ask_yn('Do you want to set items under\n "%s" (%d sub-items)' @@ -421,7 +540,7 @@ print ("ERROR: Invalid selection, type a number from the list " "above.") - classifiers[_CLASSIFIERS_LIST[index]] = 1 + classifiers.add(_CLASSIFIERS_LIST[index]) return def set_devel_status(self, classifiers): @@ -448,7 +567,7 @@ 'Development Status :: 5 - Production/Stable', 'Development Status :: 6 - Mature', 'Development Status :: 7 - Inactive'][choice] - classifiers[key] = 1 + classifiers.add(key) return except (IndexError, ValueError): print ("ERROR: Invalid selection, type a single digit " @@ -475,28 +594,39 @@ fp = open(_FILENAME, 'w') try: fp.write('[metadata]\n') - fp.write('name = %s\n' % self.data['name']) - fp.write('version = %s\n' % self.data['version']) - fp.write('author = %s\n' % self.data['author']) - fp.write('author_email = %s\n' % self.data['author_email']) - fp.write('summary = %s\n' % self.data['summary']) - fp.write('home_page = %s\n' % self.data['home_page']) - fp.write('\n') - if len(self.data['classifier']) > 0: - classifiers = '\n'.join([' %s' % clas for clas in - self.data['classifier']]) - fp.write('classifier = %s\n' % classifiers.strip()) - fp.write('\n') - - fp.write('[files]\n') - for element in ('packages', 'modules', 'extra_files'): - if len(self.data[element]) == 0: + # simple string entries + for name in ('name', 'version', 'summary', 'download_url'): + fp.write('%s = %s\n' % (name, self.data.get(name, 'UNKNOWN'))) + # optional string entries + if 'keywords' in self.data and self.data['keywords']: + fp.write('keywords = %s\n' % ' '.join(self.data['keywords'])) + for name in ('home_page', 'author', 'author_email', + 'maintainer', 'maintainer_email', 'description-file'): + if name in self.data and self.data[name]: + fp.write('%s = %s\n' % (name, self.data[name])) + if 'description' in self.data: + fp.write( + 'description = %s\n' + % '\n |'.join(self.data['description'].split('\n'))) + # multiple use string entries + for name in ('platform', 'supported-platform', 'classifier', + 'requires-dist', 'provides-dist', 'obsoletes-dist', + 'requires-external'): + if not(name in self.data and self.data[name]): continue - items = '\n'.join([' %s' % item for item in - self.data[element]]) - fp.write('%s = %s\n' % (element, items.strip())) - - fp.write('\n') + fp.write('%s = ' % name) + fp.write(''.join(' %s\n' % val + for val in self.data[name]).lstrip()) + fp.write('\n[files]\n') + for name in ('packages', 'modules', 'scripts', + 'package_data', 'extra_files'): + if not(name in self.data and self.data[name]): + continue + fp.write('%s = %s\n' + % (name, '\n '.join(self.data[name]).strip())) + fp.write('\n[resources]\n') + for src, dest in self.data['resources']: + fp.write('%s = %s\n' % (src, dest)) finally: fp.close() @@ -508,11 +638,12 @@ """Main entry point.""" program = MainProgram() # uncomment when implemented - #program.load_existing_setup_script() - program.inspect_directory() - program.query_user() - program.update_config_file() + if not program.load_existing_setup_script(): + program.inspect_directory() + program.query_user() + program.update_config_file() program.write_setup_script() + # istutils2.util.generate_distutils_setup_py() if __name__ == '__main__': diff --git a/distutils2/tests/test_mkcfg.py b/distutils2/tests/test_mkcfg.py --- a/distutils2/tests/test_mkcfg.py +++ b/distutils2/tests/test_mkcfg.py @@ -1,10 +1,17 @@ +# -*- coding: utf-8 -*- """Tests for distutils.mkcfg.""" import os +import os.path as osp import sys import StringIO +if sys.version_info[:2] < (2, 6): + from sets import Set as set +from textwrap import dedent + from distutils2.tests import run_unittest, support, unittest from distutils2.mkcfg import MainProgram -from distutils2.mkcfg import ask_yn, ask +from distutils2.mkcfg import ask_yn, ask, main + class MkcfgTestCase(support.TempdirManager, unittest.TestCase): @@ -12,16 +19,20 @@ def setUp(self): super(MkcfgTestCase, self).setUp() self._stdin = sys.stdin - self._stdout = sys.stdout + self._stdout = sys.stdout sys.stdin = StringIO.StringIO() sys.stdout = StringIO.StringIO() - + self._cwd = os.getcwd() + self.wdir = self.mkdtemp() + os.chdir(self.wdir) + def tearDown(self): super(MkcfgTestCase, self).tearDown() sys.stdin = self._stdin sys.stdout = self._stdout - - def test_ask_yn(self): + os.chdir(self._cwd) + + def test_ask_yn(self): sys.stdin.write('y\n') sys.stdin.seek(0) self.assertEqual('y', ask_yn('is this a test')) @@ -40,13 +51,13 @@ main.data['author'] = [] main._set_multi('_set_multi test', 'author') self.assertEqual(['aaaaa'], main.data['author']) - + def test_find_files(self): # making sure we scan a project dir correctly main = MainProgram() # building the structure - tempdir = self.mkdtemp() + tempdir = self.wdir dirs = ['pkg1', 'data', 'pkg2', 'pkg2/sub'] files = ['README', 'setup.cfg', 'foo.py', 'pkg1/__init__.py', 'pkg1/bar.py', @@ -60,12 +71,7 @@ path = os.path.join(tempdir, file_) self.write_file(path, 'xxx') - old_dir = os.getcwd() - os.chdir(tempdir) - try: - main._find_files() - finally: - os.chdir(old_dir) + main._find_files() # do we have what we want ? self.assertEqual(main.data['packages'], ['pkg1', 'pkg2', 'pkg2.sub']) @@ -73,6 +79,131 @@ self.assertEqual(set(main.data['extra_files']), set(['setup.cfg', 'README', 'data/data1'])) + def test_convert_setup_py_to_cfg(self): + self.write_file((self.wdir, 'setup.py'), + dedent(""" + # -*- coding: utf-8 -*- + from distutils.core import setup + lg_dsc = '''My super Death-scription + barbar is now on the public domain, + ho, baby !''' + setup(name='pyxfoil', + version='0.2', + description='Python bindings for the Xfoil engine', + long_description = lg_dsc, + maintainer='Andr?? Espaze', + maintainer_email='andre.espaze at logilab.fr', + url='http://www.python-science.org/project/pyxfoil', + license='GPLv2', + packages=['pyxfoil', 'babar', 'me'], + data_files=[('share/doc/pyxfoil', ['README.rst']), + ('share/man', ['pyxfoil.1']), + ], + py_modules = ['my_lib', 'mymodule'], + package_dir = {'babar' : '', + 'me' : 'Martinique/Lamentin', + }, + package_data = {'babar': ['Pom', 'Flora', 'Alexander'], + 'me': ['dady', 'mumy', 'sys', 'bro'], + '': ['setup.py', 'README'], + 'pyxfoil' : ['fengine.so'], + }, + scripts = ['my_script', 'bin/run'], + ) + """)) + sys.stdin.write('y\n') + sys.stdin.seek(0) + main() + fid = open(osp.join(self.wdir, 'setup.cfg')) + lines = set([line.rstrip() for line in fid]) + fid.close() + self.assertEqual(lines, set(['', + '[metadata]', + 'version = 0.2', + 'name = pyxfoil', + 'maintainer = Andr?? Espaze', + 'description = My super Death-scription', + ' |barbar is now on the public domain,', + ' |ho, baby !', + 'maintainer_email = andre.espaze at logilab.fr', + 'home_page = http://www.python-science.org/project/pyxfoil', + 'download_url = UNKNOWN', + 'summary = Python bindings for the Xfoil engine', + '[files]', + 'modules = my_lib', + ' mymodule', + 'packages = pyxfoil', + ' babar', + ' me', + 'extra_files = Martinique/Lamentin/dady', + ' Martinique/Lamentin/mumy', + ' Martinique/Lamentin/sys', + ' Martinique/Lamentin/bro', + ' Pom', + ' Flora', + ' Alexander', + ' setup.py', + ' README', + ' pyxfoil/fengine.so', + 'scripts = my_script', + ' bin/run', + '[resources]', + 'README.rst = {doc}', + 'pyxfoil.1 = {man}', + ])) + + def test_convert_setup_py_to_cfg_with_description_in_readme(self): + self.write_file((self.wdir, 'setup.py'), + dedent(""" + # -*- coding: utf-8 -*- + from distutils.core import setup + lg_dsc = open('README.txt').read() + setup(name='pyxfoil', + version='0.2', + description='Python bindings for the Xfoil engine', + long_description=lg_dsc, + maintainer='Andr?? Espaze', + maintainer_email='andre.espaze at logilab.fr', + url='http://www.python-science.org/project/pyxfoil', + license='GPLv2', + packages=['pyxfoil'], + package_data={'pyxfoil' : ['fengine.so']}, + data_files=[ + ('share/doc/pyxfoil', ['README.rst']), + ('share/man', ['pyxfoil.1']), + ], + ) + """)) + self.write_file((self.wdir, 'README.txt'), + dedent(''' +My super Death-scription +barbar is now on the public domain, +ho, baby ! + ''')) + sys.stdin.write('y\n') + sys.stdin.seek(0) + main() + fid = open(osp.join(self.wdir, 'setup.cfg')) + lines = set([line.strip() for line in fid]) + fid.close() + self.assertEqual(lines, set(['', + '[metadata]', + 'version = 0.2', + 'name = pyxfoil', + 'maintainer = Andr?? Espaze', + 'maintainer_email = andre.espaze at logilab.fr', + 'home_page = http://www.python-science.org/project/pyxfoil', + 'download_url = UNKNOWN', + 'summary = Python bindings for the Xfoil engine', + 'description-file = README.txt', + '[files]', + 'packages = pyxfoil', + 'extra_files = pyxfoil/fengine.so', + '[resources]', + 'README.rst = {doc}', + 'pyxfoil.1 = {man}', + ])) + def test_suite(): return unittest.makeSuite(MkcfgTestCase) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: Improve mkcfg script to recycle deprecated setup.py Message-ID: tarek.ziade pushed 8f043681485c to distutils2: http://hg.python.org/distutils2/rev/8f043681485c changeset: 950:8f043681485c parent: 896:272155a17d56 user: Alain Leufroy PEP345 - complete PEP345 support when writing the new setup.cfg Note: The wizard has not been improved. files: distutils2/mkcfg.py distutils2/tests/test_mkcfg.py diff --git a/distutils2/mkcfg.py b/distutils2/mkcfg.py --- a/distutils2/mkcfg.py +++ b/distutils2/mkcfg.py @@ -20,17 +20,27 @@ # Ask for the dependencies. # Ask for the Requires-Dist # Ask for the Provides-Dist +# Ask for a description # Detect scripts (not sure how. #! outside of package?) import os import sys import re import shutil +import glob +import re from ConfigParser import RawConfigParser from textwrap import dedent +if sys.version_info[:2] < (2, 6): + from sets import Set as set +try: + from hashlib import md5 +except ImportError: + from md5 import md5 # importing this with an underscore as it should be replaced by the # dict form or another structures for all purposes from distutils2._trove import all_classifiers as _CLASSIFIERS_LIST +from distutils2._backport import sysconfig _FILENAME = 'setup.cfg' @@ -82,6 +92,10 @@ Optionally, you can set other trove identifiers for things such as the human language, programming language, user interface, etc... ''', + 'setup.py found':''' +The setup.py script will be executed to retrieve the metadata. +A wizard will be run if you answer "n", +''' } # XXX everything needs docstrings and tests (both low-level tests of various @@ -158,16 +172,18 @@ LICENCES = _build_licences(_CLASSIFIERS_LIST) - class MainProgram(object): def __init__(self): self.configparser = None - self.classifiers = {} + self.classifiers = set([]) self.data = {} self.data['classifier'] = self.classifiers self.data['packages'] = [] self.data['modules'] = [] + self.data['platform'] = [] + self.data['resources'] = [] self.data['extra_files'] = [] + self.data['scripts'] = [] self.load_config_file() def lookup_option(self, key): @@ -178,6 +194,7 @@ def load_config_file(self): self.configparser = RawConfigParser() # TODO replace with section in distutils config file + #XXX freedesktop self.configparser.read(os.path.expanduser('~/.mkcfg')) self.data['author'] = self.lookup_option('author') self.data['author_email'] = self.lookup_option('author_email') @@ -194,6 +211,7 @@ if not valuesDifferent: return + #XXX freedesktop fp = open(os.path.expanduser('~/.mkcfgpy'), 'w') try: self.configparser.write(fp) @@ -201,19 +219,118 @@ fp.close() def load_existing_setup_script(self): - raise NotImplementedError - # Ideas: - # - define a mock module to assign to sys.modules['distutils'] before - # importing the setup script as a module (or executing it); it would - # provide setup (a function that just returns its args as a dict), - # Extension (ditto), find_packages (the real function) - # - we could even mock Distribution and commands to handle more setup - # scripts - # - we could use a sandbox (http://bugs.python.org/issue8680) - # - the cleanest way is to parse the file, not import it, but there is - # no way to do that across versions (the compiler package is - # deprecated or removed in recent Pythons, the ast module is not - # present before 2.6) + """ Generate a setup.cfg from an existing setup.py. + + It only exports the distutils metadata (setuptools specific metadata + is not actually supported). + """ + setuppath = 'setup.py' + if not os.path.exists(setuppath): + return + else: + ans = ask_yn(('A legacy setup.py has been found.\n' + 'Would you like to convert it to a setup.cfg ?'), + 'y', + _helptext['setup.py found']) + if ans != 'y': + return + + #_______mock setup start + data = self.data + def setup(**attrs): + """Mock the setup(**attrs) in order to retrive metadata.""" + # use the distutils v1 processings to correctly parse metadata. + #XXX we could also use the setuptools distibution ??? + from distutils.dist import Distribution + dist = Distribution(attrs) + dist.parse_config_files() + # 1. retrieves metadata that are quite similar PEP314<->PEP345 + labels = (('name',) * 2, + ('version',) * 2, + ('author',) * 2, + ('author_email',) * 2, + ('maintainer',) * 2, + ('maintainer_email',) * 2, + ('description', 'summary'), + ('long_description', 'description'), + ('url', 'home_page'), + ('platforms', 'platform'), + ('provides', 'provides-dist'), + ('obsoletes', 'obsoletes-dist'), + ('requires', 'requires-dist'),) + get = lambda lab: getattr(dist.metadata, lab.replace('-', '_')) + data.update((new, get(old)) for (old, new) in labels if get(old)) + # 2. retrieves data that requires special processings. + data['classifier'].update(dist.get_classifiers() or []) + data['scripts'].extend(dist.scripts or []) + data['packages'].extend(dist.packages or []) + data['modules'].extend(dist.py_modules or []) + # 2.1 data_files -> resources. + if len(dist.data_files) < 2 or isinstance(dist.data_files[1], str): + dist.data_files = [('', dist.data_files)] + #add tokens in the destination paths + vars = {'distribution.name':data['name']} + path_tokens = sysconfig.get_paths(vars=vars).items() + #sort tokens to use the longest one first + path_tokens.sort(cmp=lambda x,y: cmp(len(y), len(x)), + key=lambda x: x[1]) + for dest, srcs in (dist.data_files or []): + dest = os.path.join(sys.prefix, dest) + for tok, path in path_tokens: + if dest.startswith(path): + dest = ('{%s}' % tok) + dest[len(path):] + files = [('/ '.join(src.rsplit('/', 1)), dest) + for src in srcs] + data['resources'].extend(files) + continue + # 2.2 package_data -> extra_files + package_dirs = dist.package_dir or {} + for package, extras in dist.package_data.iteritems() or []: + package_dir = package_dirs.get(package, package) + fils = [os.path.join(package_dir, fil) for fil in extras] + data['extra_files'].extend(fils) + + # Use README file if its content is the desciption + if "description" in data: + ref = md5(re.sub('\s', '', self.data['description']).lower()) + ref = ref.digest() + for readme in glob.glob('README*'): + fob = open(readme) + val = md5(re.sub('\s', '', fob.read()).lower()).digest() + fob.close() + if val == ref: + del data['description'] + data['description-file'] = readme + break + #_________ mock setup end + + # apply monkey patch to distutils (v1) and setuptools (if needed) + # (abord the feature if distutils v1 has been killed) + try: + import distutils.core as DC + getattr(DC, 'setup') # ensure distutils v1 + except ImportError, AttributeError: + return + saved_setups = [(DC, DC.setup)] + DC.setup = setup + try: + import setuptools + saved_setups.append((setuptools, setuptools.setup)) + setuptools.setup = setup + except ImportError, AttributeError: + pass + # get metadata by executing the setup.py with the patched setup(...) + success = False # for python < 2.4 + try: + pyenv = globals().copy() + execfile(setuppath, pyenv) + success = True + finally: #revert monkey patches + for patched_module, original_setup in saved_setups: + patched_module.setup = original_setup + if not self.data: + raise ValueError('Unable to load metadata from setup.py') + return success def inspect_file(self, path): fp = open(path, 'r') @@ -222,9 +339,11 @@ m = re.match(r'^#!.*python((?P\d)(\.\d+)?)?$', line) if m: if m.group('major') == '3': - self.classifiers['Programming Language :: Python :: 3'] = 1 + self.classifiers.add( + 'Programming Language :: Python :: 3') else: - self.classifiers['Programming Language :: Python :: 2'] = 1 + self.classifiers.add( + 'Programming Language :: Python :: 2') finally: fp.close() @@ -370,7 +489,7 @@ for key in sorted(trove): if len(trove[key]) == 0: if ask_yn('Add "%s"' % desc[4:] + ' :: ' + key, 'n') == 'y': - classifiers[desc[4:] + ' :: ' + key] = 1 + classifiers.add(desc[4:] + ' :: ' + key) continue if ask_yn('Do you want to set items under\n "%s" (%d sub-items)' @@ -421,7 +540,7 @@ print ("ERROR: Invalid selection, type a number from the list " "above.") - classifiers[_CLASSIFIERS_LIST[index]] = 1 + classifiers.add(_CLASSIFIERS_LIST[index]) return def set_devel_status(self, classifiers): @@ -448,7 +567,7 @@ 'Development Status :: 5 - Production/Stable', 'Development Status :: 6 - Mature', 'Development Status :: 7 - Inactive'][choice] - classifiers[key] = 1 + classifiers.add(key) return except (IndexError, ValueError): print ("ERROR: Invalid selection, type a single digit " @@ -475,28 +594,39 @@ fp = open(_FILENAME, 'w') try: fp.write('[metadata]\n') - fp.write('name = %s\n' % self.data['name']) - fp.write('version = %s\n' % self.data['version']) - fp.write('author = %s\n' % self.data['author']) - fp.write('author_email = %s\n' % self.data['author_email']) - fp.write('summary = %s\n' % self.data['summary']) - fp.write('home_page = %s\n' % self.data['home_page']) - fp.write('\n') - if len(self.data['classifier']) > 0: - classifiers = '\n'.join([' %s' % clas for clas in - self.data['classifier']]) - fp.write('classifier = %s\n' % classifiers.strip()) - fp.write('\n') - - fp.write('[files]\n') - for element in ('packages', 'modules', 'extra_files'): - if len(self.data[element]) == 0: + # simple string entries + for name in ('name', 'version', 'summary', 'download_url'): + fp.write('%s = %s\n' % (name, self.data.get(name, 'UNKNOWN'))) + # optional string entries + if 'keywords' in self.data and self.data['keywords']: + fp.write('keywords = %s\n' % ' '.join(self.data['keywords'])) + for name in ('home_page', 'author', 'author_email', + 'maintainer', 'maintainer_email', 'description-file'): + if name in self.data and self.data[name]: + fp.write('%s = %s\n' % (name, self.data[name])) + if 'description' in self.data: + fp.write( + 'description = %s\n' + % '\n |'.join(self.data['description'].split('\n'))) + # multiple use string entries + for name in ('platform', 'supported-platform', 'classifier', + 'requires-dist', 'provides-dist', 'obsoletes-dist', + 'requires-external'): + if not(name in self.data and self.data[name]): continue - items = '\n'.join([' %s' % item for item in - self.data[element]]) - fp.write('%s = %s\n' % (element, items.strip())) - - fp.write('\n') + fp.write('%s = ' % name) + fp.write(''.join(' %s\n' % val + for val in self.data[name]).lstrip()) + fp.write('\n[files]\n') + for name in ('packages', 'modules', 'scripts', + 'package_data', 'extra_files'): + if not(name in self.data and self.data[name]): + continue + fp.write('%s = %s\n' + % (name, '\n '.join(self.data[name]).strip())) + fp.write('\n[resources]\n') + for src, dest in self.data['resources']: + fp.write('%s = %s\n' % (src, dest)) finally: fp.close() @@ -508,11 +638,12 @@ """Main entry point.""" program = MainProgram() # uncomment when implemented - #program.load_existing_setup_script() - program.inspect_directory() - program.query_user() - program.update_config_file() + if not program.load_existing_setup_script(): + program.inspect_directory() + program.query_user() + program.update_config_file() program.write_setup_script() + # istutils2.util.generate_distutils_setup_py() if __name__ == '__main__': diff --git a/distutils2/tests/test_mkcfg.py b/distutils2/tests/test_mkcfg.py --- a/distutils2/tests/test_mkcfg.py +++ b/distutils2/tests/test_mkcfg.py @@ -1,10 +1,17 @@ +# -*- coding: utf-8 -*- """Tests for distutils.mkcfg.""" import os +import os.path as osp import sys import StringIO +if sys.version_info[:2] < (2, 6): + from sets import Set as set +from textwrap import dedent + from distutils2.tests import run_unittest, support, unittest from distutils2.mkcfg import MainProgram -from distutils2.mkcfg import ask_yn, ask +from distutils2.mkcfg import ask_yn, ask, main + class MkcfgTestCase(support.TempdirManager, unittest.TestCase): @@ -12,16 +19,20 @@ def setUp(self): super(MkcfgTestCase, self).setUp() self._stdin = sys.stdin - self._stdout = sys.stdout + self._stdout = sys.stdout sys.stdin = StringIO.StringIO() sys.stdout = StringIO.StringIO() - + self._cwd = os.getcwd() + self.wdir = self.mkdtemp() + os.chdir(self.wdir) + def tearDown(self): super(MkcfgTestCase, self).tearDown() sys.stdin = self._stdin sys.stdout = self._stdout - - def test_ask_yn(self): + os.chdir(self._cwd) + + def test_ask_yn(self): sys.stdin.write('y\n') sys.stdin.seek(0) self.assertEqual('y', ask_yn('is this a test')) @@ -40,13 +51,13 @@ main.data['author'] = [] main._set_multi('_set_multi test', 'author') self.assertEqual(['aaaaa'], main.data['author']) - + def test_find_files(self): # making sure we scan a project dir correctly main = MainProgram() # building the structure - tempdir = self.mkdtemp() + tempdir = self.wdir dirs = ['pkg1', 'data', 'pkg2', 'pkg2/sub'] files = ['README', 'setup.cfg', 'foo.py', 'pkg1/__init__.py', 'pkg1/bar.py', @@ -60,12 +71,7 @@ path = os.path.join(tempdir, file_) self.write_file(path, 'xxx') - old_dir = os.getcwd() - os.chdir(tempdir) - try: - main._find_files() - finally: - os.chdir(old_dir) + main._find_files() # do we have what we want ? self.assertEqual(main.data['packages'], ['pkg1', 'pkg2', 'pkg2.sub']) @@ -73,6 +79,131 @@ self.assertEqual(set(main.data['extra_files']), set(['setup.cfg', 'README', 'data/data1'])) + def test_convert_setup_py_to_cfg(self): + self.write_file((self.wdir, 'setup.py'), + dedent(""" + # -*- coding: utf-8 -*- + from distutils.core import setup + lg_dsc = '''My super Death-scription + barbar is now on the public domain, + ho, baby !''' + setup(name='pyxfoil', + version='0.2', + description='Python bindings for the Xfoil engine', + long_description = lg_dsc, + maintainer='Andr?? Espaze', + maintainer_email='andre.espaze at logilab.fr', + url='http://www.python-science.org/project/pyxfoil', + license='GPLv2', + packages=['pyxfoil', 'babar', 'me'], + data_files=[('share/doc/pyxfoil', ['README.rst']), + ('share/man', ['pyxfoil.1']), + ], + py_modules = ['my_lib', 'mymodule'], + package_dir = {'babar' : '', + 'me' : 'Martinique/Lamentin', + }, + package_data = {'babar': ['Pom', 'Flora', 'Alexander'], + 'me': ['dady', 'mumy', 'sys', 'bro'], + '': ['setup.py', 'README'], + 'pyxfoil' : ['fengine.so'], + }, + scripts = ['my_script', 'bin/run'], + ) + """)) + sys.stdin.write('y\n') + sys.stdin.seek(0) + main() + fid = open(osp.join(self.wdir, 'setup.cfg')) + lines = set([line.rstrip() for line in fid]) + fid.close() + self.assertEqual(lines, set(['', + '[metadata]', + 'version = 0.2', + 'name = pyxfoil', + 'maintainer = Andr?? Espaze', + 'description = My super Death-scription', + ' |barbar is now on the public domain,', + ' |ho, baby !', + 'maintainer_email = andre.espaze at logilab.fr', + 'home_page = http://www.python-science.org/project/pyxfoil', + 'download_url = UNKNOWN', + 'summary = Python bindings for the Xfoil engine', + '[files]', + 'modules = my_lib', + ' mymodule', + 'packages = pyxfoil', + ' babar', + ' me', + 'extra_files = Martinique/Lamentin/dady', + ' Martinique/Lamentin/mumy', + ' Martinique/Lamentin/sys', + ' Martinique/Lamentin/bro', + ' Pom', + ' Flora', + ' Alexander', + ' setup.py', + ' README', + ' pyxfoil/fengine.so', + 'scripts = my_script', + ' bin/run', + '[resources]', + 'README.rst = {doc}', + 'pyxfoil.1 = {man}', + ])) + + def test_convert_setup_py_to_cfg_with_description_in_readme(self): + self.write_file((self.wdir, 'setup.py'), + dedent(""" + # -*- coding: utf-8 -*- + from distutils.core import setup + lg_dsc = open('README.txt').read() + setup(name='pyxfoil', + version='0.2', + description='Python bindings for the Xfoil engine', + long_description=lg_dsc, + maintainer='Andr?? Espaze', + maintainer_email='andre.espaze at logilab.fr', + url='http://www.python-science.org/project/pyxfoil', + license='GPLv2', + packages=['pyxfoil'], + package_data={'pyxfoil' : ['fengine.so']}, + data_files=[ + ('share/doc/pyxfoil', ['README.rst']), + ('share/man', ['pyxfoil.1']), + ], + ) + """)) + self.write_file((self.wdir, 'README.txt'), + dedent(''' +My super Death-scription +barbar is now on the public domain, +ho, baby ! + ''')) + sys.stdin.write('y\n') + sys.stdin.seek(0) + main() + fid = open(osp.join(self.wdir, 'setup.cfg')) + lines = set([line.strip() for line in fid]) + fid.close() + self.assertEqual(lines, set(['', + '[metadata]', + 'version = 0.2', + 'name = pyxfoil', + 'maintainer = Andr?? Espaze', + 'maintainer_email = andre.espaze at logilab.fr', + 'home_page = http://www.python-science.org/project/pyxfoil', + 'download_url = UNKNOWN', + 'summary = Python bindings for the Xfoil engine', + 'description-file = README.txt', + '[files]', + 'packages = pyxfoil', + 'extra_files = pyxfoil/fengine.so', + '[resources]', + 'README.rst = {doc}', + 'pyxfoil.1 = {man}', + ])) + def test_suite(): return unittest.makeSuite(MkcfgTestCase) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: merge Message-ID: tarek.ziade pushed 1e23203b0675 to distutils2: http://hg.python.org/distutils2/rev/1e23203b0675 changeset: 952:1e23203b0675 parent: 951:20b7b525914c parent: 949:f31564d7ed76 user: Alexis Metaireau date: Sat Jan 29 18:07:41 2011 +0100 summary: merge files: diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -1029,7 +1029,7 @@ for dist in _yield_distributions(True, use_egg_info, paths): yield dist else: - _generate_cache(use_egg_info) + _generate_cache(use_egg_info, paths) for dist in _cache_path.itervalues(): yield dist @@ -1061,7 +1061,7 @@ if dist.name == name: return dist else: - _generate_cache(use_egg_info) + _generate_cache(use_egg_info, paths) if name in _cache_name: return _cache_name[name][0] diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -1,15 +1,20 @@ from tempfile import mkdtemp import shutil import os +import sys +import stat import errno import itertools +import tempfile from distutils2 import logger from distutils2._backport.pkgutil import get_distributions +from distutils2._backport.pkgutil import get_distribution from distutils2._backport.sysconfig import get_config_var from distutils2.depgraph import generate_graph from distutils2.index import wrapper from distutils2.index.errors import ProjectNotFound, ReleaseNotFound +from distutils2.errors import DistutilsError from distutils2.version import get_version_predicate """Provides installations scripts. @@ -310,10 +315,40 @@ infos[key].extend(new_infos[key]) -def remove(project_name): +def remove(project_name, paths=sys.path): """Removes a single project from the installation""" - pass + tmp = tempfile.mkdtemp(prefix=project_name+'-uninstall') + dist = get_distribution(project_name, paths=paths) + if dist is None: + raise DistutilsError('Distribution %s not found' % project_name) + files = dist.get_installed_files(local=True) + rmdirs = [] + rmfiles = [] + try: + for file, md5, size in files: + if os.path.isfile(file): + dirname, filename = os.path.split(file) + tmpfile = os.path.join(tmp, filename) + try: + os.rename(file, tmpfile) + finally: + if not os.path.isfile(file): + os.rename(tmpfile, file) + if file not in rmfiles: + rmfiles.append(file) + if dirname not in rmdirs: + rmdirs.append(dirname) + except OSError: + os.rmdir(tmp) + + for file in rmfiles: + os.remove(file) + + for dirname in rmdirs: + if not os.listdir(dirname): + if bool(os.stat(dirname).st_mode & stat.S_IWUSR): + os.rmdir(dirname) diff --git a/distutils2/tests/support.py b/distutils2/tests/support.py --- a/distutils2/tests/support.py +++ b/distutils2/tests/support.py @@ -159,6 +159,21 @@ dist = Distribution(attrs=kw) return project_dir, dist + def assertIsFile(self, *args): + path = os.path.join(*args) + dirname = os.path.dirname(path) + file = os.path.basename(path) + if os.path.isdir(dirname): + files = os.listdir(dirname) + msg = "%s not found in %s: %s" % (file, dirname, files) + assert os.path.isfile(path), msg + else: + raise AssertionError( + '%s not found. %s does not exist' % (file, dirname)) + + def assertIsNotFile(self, *args): + path = os.path.join(*args) + assert not os.path.isfile(path), "%s exist" % path class EnvironGuard(object): """TestCase-compatible mixin to save and restore the environment.""" diff --git a/distutils2/tests/test_uninstall.py b/distutils2/tests/test_uninstall.py new file mode 100644 --- /dev/null +++ b/distutils2/tests/test_uninstall.py @@ -0,0 +1,93 @@ +"""Tests for the uninstall command.""" +import os +import sys +from StringIO import StringIO +from distutils2._backport.pkgutil import disable_cache, enable_cache +from distutils2.tests import unittest, support, run_unittest +from distutils2.errors import DistutilsError +from distutils2.install import remove + +SETUP_CFG = """ +[metadata] +name = %(name)s +version = %(version)s + +[files] +packages = + %(name)s + %(name)s.sub +""" + +class UninstallTestCase(support.TempdirManager, + support.LoggingCatcher, + unittest.TestCase): + + def setUp(self): + super(UninstallTestCase, self).setUp() + self.addCleanup(setattr, sys, 'stdout', sys.stdout) + self.addCleanup(setattr, sys, 'stderr', sys.stderr) + self.addCleanup(os.chdir, os.getcwd()) + self.addCleanup(enable_cache) + self.root_dir = self.mkdtemp() + disable_cache() + + def run_setup(self, *args): + # run setup with args + #sys.stdout = StringIO() + sys.argv[:] = [''] + list(args) + old_sys = sys.argv[:] + try: + from distutils2.run import commands_main + dist = commands_main() + finally: + sys.argv[:] = old_sys + return dist + + def get_path(self, dist, name): + from distutils2.command.install_dist import install_dist + cmd = install_dist(dist) + cmd.prefix = self.root_dir + cmd.finalize_options() + return getattr(cmd, 'install_'+name) + + def make_dist(self, pkg_name='foo', **kw): + dirname = self.mkdtemp() + kw['name'] = pkg_name + if 'version' not in kw: + kw['version'] = '0.1' + self.write_file((dirname, 'setup.cfg'), SETUP_CFG % kw) + os.mkdir(os.path.join(dirname, pkg_name)) + self.write_file((dirname, '__init__.py'), '#') + self.write_file((dirname, pkg_name+'_utils.py'), '#') + os.mkdir(os.path.join(dirname, pkg_name, 'sub')) + self.write_file((dirname, pkg_name, 'sub', '__init__.py'), '#') + self.write_file((dirname, pkg_name, 'sub', pkg_name+'_utils.py'), '#') + return dirname + + def install_dist(self, pkg_name='foo', dirname=None, **kw): + if not dirname: + dirname = self.make_dist(pkg_name, **kw) + os.chdir(dirname) + dist = self.run_setup('install_dist', '--prefix='+self.root_dir) + install_lib = self.get_path(dist, 'purelib') + return dist, install_lib + + def test_uninstall_unknow_distribution(self): + self.assertRaises(DistutilsError, remove, 'foo', paths=[self.root_dir]) + + def test_uninstall(self): + dist, install_lib = self.install_dist() + self.assertIsFile(install_lib, 'foo', 'sub', '__init__.py') + self.assertIsFile(install_lib, 'foo-0.1.dist-info', 'RECORD') + remove('foo', paths=[install_lib]) + self.assertIsNotFile(install_lib, 'foo', 'sub', '__init__.py') + self.assertIsNotFile(install_lib, 'foo-0.1.dist-info', 'RECORD') + + + + +def test_suite(): + return unittest.makeSuite(UninstallTestCase) + +if __name__ == '__main__': + run_unittest(test_suite()) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: merge to latest Message-ID: tarek.ziade pushed c565ac60b197 to distutils2: http://hg.python.org/distutils2/rev/c565ac60b197 changeset: 948:c565ac60b197 parent: 947:b119d089a91b parent: 943:3bb80edf7d81 user: Gael Pasgrimaud date: Sat Jan 29 17:32:39 2011 +0100 summary: merge to latest files: distutils2/_backport/pkgutil.py distutils2/install.py distutils2/tests/support.py diff --git a/distutils2/_backport/__init__.py b/distutils2/_backport/__init__.py --- a/distutils2/_backport/__init__.py +++ b/distutils2/_backport/__init__.py @@ -1,8 +1,2 @@ """Things that will land in the Python 3.3 std lib but which we must drag along with us for now to support 2.x.""" - -def any(seq): - for elem in seq: - if elem: - return True - return False diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -1,24 +1,19 @@ """Utilities to support packages.""" -# NOTE: This module must remain compatible with Python 2.3, as it is shared -# by setuptools for distribution with Python 2.3 and up. - import os import sys import imp -import os.path +import re +import warnings from csv import reader as csv_reader from types import ModuleType from distutils2.errors import DistutilsError from distutils2.metadata import DistributionMetadata from distutils2.version import suggest_normalized_version, VersionPredicate -import zipimport try: import cStringIO as StringIO except ImportError: import StringIO -import re -import warnings __all__ = [ @@ -28,10 +23,14 @@ 'Distribution', 'EggInfoDistribution', 'distinfo_dirname', 'get_distributions', 'get_distribution', 'get_file_users', 'provides_distribution', 'obsoletes_distribution', - 'enable_cache', 'disable_cache', 'clear_cache' + 'enable_cache', 'disable_cache', 'clear_cache', ] +########################## +# PEP 302 Implementation # +########################## + def read_code(stream): # This helper is needed in order for the :pep:`302` emulation to # correctly handle compiled files @@ -41,7 +40,7 @@ if magic != imp.get_magic(): return None - stream.read(4) # Skip timestamp + stream.read(4) # Skip timestamp return marshal.load(stream) @@ -173,7 +172,6 @@ #@simplegeneric def iter_importer_modules(importer, prefix=''): - "" if not hasattr(importer, 'iter_modules'): return [] return importer.iter_modules(prefix) @@ -331,9 +329,9 @@ def get_filename(self, fullname=None): fullname = self._fix_name(fullname) mod_type = self.etc[2] - if self.etc[2] == imp.PKG_DIRECTORY: + if mod_type == imp.PKG_DIRECTORY: return self._get_delegate().get_filename() - elif self.etc[2] in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION): + elif mod_type in (imp.PY_SOURCE, imp.PY_COMPILED, imp.C_EXTENSION): return self.filename return None @@ -432,7 +430,8 @@ import mechanism will find the latter. Items of the following types can be affected by this discrepancy: - ``imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY`` + :data:`imp.C_EXTENSION`, :data:`imp.PY_SOURCE`, :data:`imp.PY_COMPILED`, + :data:`imp.PKG_DIRECTORY` """ if fullname.startswith('.'): raise ImportError("Relative module names not supported") @@ -534,13 +533,13 @@ # frozen package. Return the path unchanged in that case. return path - pname = os.path.join(*name.split('.')) # Reconstitute as relative path + pname = os.path.join(*name.split('.')) # Reconstitute as relative path # Just in case os.extsep != '.' sname = os.extsep.join(name.split('.')) sname_pkg = sname + os.extsep + "pkg" init_py = "__init__" + os.extsep + "py" - path = path[:] # Start with a copy of the existing path + path = path[:] # Start with a copy of the existing path for dir in sys.path: if not isinstance(dir, basestring) or not os.path.isdir(dir): @@ -565,7 +564,7 @@ line = line.rstrip('\n') if not line or line.startswith('#'): continue - path.append(line) # Don't check for existence! + path.append(line) # Don't check for existence! f.close() return path @@ -609,6 +608,7 @@ resource_name = os.path.join(*parts) return loader.get_data(resource_name) + ########################## # PEP 376 Implementation # ########################## @@ -616,12 +616,12 @@ DIST_FILES = ('INSTALLER', 'METADATA', 'RECORD', 'REQUESTED',) # Cache -_cache_name = {} # maps names to Distribution instances -_cache_name_egg = {} # maps names to EggInfoDistribution instances -_cache_path = {} # maps paths to Distribution instances -_cache_path_egg = {} # maps paths to EggInfoDistribution instances -_cache_generated = False # indicates if .dist-info distributions are cached -_cache_generated_egg = False # indicates if .dist-info and .egg are cached +_cache_name = {} # maps names to Distribution instances +_cache_name_egg = {} # maps names to EggInfoDistribution instances +_cache_path = {} # maps paths to Distribution instances +_cache_path_egg = {} # maps paths to EggInfoDistribution instances +_cache_generated = False # indicates if .dist-info distributions are cached +_cache_generated_egg = False # indicates if .dist-info and .egg are cached _cache_enabled = True @@ -636,6 +636,7 @@ _cache_enabled = True + def disable_cache(): """ Disables the internal cache. @@ -647,9 +648,10 @@ _cache_enabled = False + def clear_cache(): """ Clears the internal cache. """ - global _cache_name, _cache_name_egg, cache_path, _cache_path_egg, \ + global _cache_name, _cache_name_egg, _cache_path, _cache_path_egg, \ _cache_generated, _cache_generated_egg _cache_name = {} @@ -872,7 +874,8 @@ if isinstance(strs, basestring): for s in strs.splitlines(): s = s.strip() - if s and not s.startswith('#'): # skip blank lines/comments + # skip blank lines/comments + if s and not s.startswith('#'): yield s else: for ss in strs: @@ -890,6 +893,7 @@ except IOError: requires = None else: + # FIXME handle the case where zipfile is not available zipf = zipimport.zipimporter(path) fileobj = StringIO.StringIO(zipf.get_data('EGG-INFO/PKG-INFO')) self.metadata = DistributionMetadata(fileobj=fileobj) @@ -952,7 +956,7 @@ version = match.group('first') if match.group('rest'): version += match.group('rest') - version = version.replace(' ', '') # trim spaces + version = version.replace(' ', '') # trim spaces if version is None: reqs.append(name) else: @@ -982,12 +986,6 @@ __hash__ = object.__hash__ -def _normalize_dist_name(name): - """Returns a normalized name from the given *name*. - :rtype: string""" - return name.replace('-', '_') - - def distinfo_dirname(name, version): """ The *name* and *version* parameters are converted into their @@ -1007,7 +1005,7 @@ :returns: directory name :rtype: string""" file_extension = '.dist-info' - name = _normalize_dist_name(name) + name = name.replace('-', '_') normalized_version = suggest_normalized_version(version) # Because this is a lookup procedure, something will be returned even if # it is a version that cannot be normalized @@ -1148,7 +1146,7 @@ raise DistutilsError(('Distribution %s has invalid ' + 'provides field: %s') \ % (dist.name, p)) - p_ver = p_ver[1:-1] # trim off the parenthesis + p_ver = p_ver[1:-1] # trim off the parenthesis if p_name == name and predicate.match(p_ver): yield dist break diff --git a/distutils2/_backport/shutil.py b/distutils2/_backport/shutil.py --- a/distutils2/_backport/shutil.py +++ b/distutils2/_backport/shutil.py @@ -1,4 +1,4 @@ -"""Utility functions for copying files and directory trees. +"""Utility functions for copying and archiving files and directory trees. XXX The functions here don't copy the resource fork or other metadata on Mac. @@ -9,7 +9,13 @@ import stat from os.path import abspath import fnmatch -from warnings import warn +import errno + +try: + import bz2 + _BZ2_SUPPORTED = True +except ImportError: + _BZ2_SUPPORTED = False try: from pwd import getpwnam @@ -21,9 +27,12 @@ except ImportError: getgrnam = None -__all__ = ["copyfileobj","copyfile","copymode","copystat","copy","copy2", - "copytree","move","rmtree","Error", "SpecialFileError", - "ExecError","make_archive"] +__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", + "copytree", "move", "rmtree", "Error", "SpecialFileError", + "ExecError", "make_archive", "get_archive_formats", + "register_archive_format", "unregister_archive_format", + "get_unpack_formats", "register_unpack_format", + "unregister_unpack_format", "unpack_archive"] class Error(EnvironmentError): pass @@ -35,6 +44,14 @@ class ExecError(EnvironmentError): """Raised when a command could not be executed""" +class ReadError(EnvironmentError): + """Raised when an archive cannot be read""" + +class RegistryError(Exception): + """Raised when a registery operation with the archiving + and unpacking registeries fails""" + + try: WindowsError except NameError: @@ -50,7 +67,7 @@ def _samefile(src, dst): # Macintosh, Unix. - if hasattr(os.path,'samefile'): + if hasattr(os.path, 'samefile'): try: return os.path.samefile(src, dst) except OSError: @@ -63,10 +80,8 @@ def copyfile(src, dst): """Copy data from src to dst""" if _samefile(src, dst): - raise Error, "`%s` and `%s` are the same file" % (src, dst) + raise Error("`%s` and `%s` are the same file" % (src, dst)) - fsrc = None - fdst = None for fn in [src, dst]: try: st = os.stat(fn) @@ -77,15 +92,16 @@ # XXX What about other special files? (sockets, devices...) if stat.S_ISFIFO(st.st_mode): raise SpecialFileError("`%s` is a named pipe" % fn) + + fsrc = open(src, 'rb') try: - fsrc = open(src, 'rb') fdst = open(dst, 'wb') - copyfileobj(fsrc, fdst) + try: + copyfileobj(fsrc, fdst) + finally: + fdst.close() finally: - if fdst: - fdst.close() - if fsrc: - fsrc.close() + fsrc.close() def copymode(src, dst): """Copy mode bits from src to dst""" @@ -103,8 +119,12 @@ if hasattr(os, 'chmod'): os.chmod(dst, mode) if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): - os.chflags(dst, st.st_flags) - + try: + os.chflags(dst, st.st_flags) + except OSError, why: + if (not hasattr(errno, 'EOPNOTSUPP') or + why.errno != errno.EOPNOTSUPP): + raise def copy(src, dst): """Copy data and mode bits ("cp src dst"). @@ -140,8 +160,9 @@ return set(ignored_names) return _ignore_patterns -def copytree(src, dst, symlinks=False, ignore=None): - """Recursively copy a directory tree using copy2(). +def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, + ignore_dangling_symlinks=False): + """Recursively copy a directory tree. The destination directory must not already exist. If exception(s) occur, an Error is raised with a list of reasons. @@ -149,7 +170,13 @@ If the optional symlinks flag is true, symbolic links in the source tree result in symbolic links in the destination tree; if it is false, the contents of the files pointed to by symbolic - links are copied. + links are copied. If the file pointed by the symlink doesn't + exist, an exception will be added in the list of errors raised in + an Error exception at the end of the copy process. + + You can set the optional ignore_dangling_symlinks flag to true if you + want to silence this exception. Notice that this has no effect on + platforms that don't support os.symlink. The optional ignore argument is a callable. If given, it is called with the `src` parameter, which is the directory @@ -163,7 +190,10 @@ list of names relative to the `src` directory that should not be copied. - XXX Consider this example code rather than the ultimate tool. + The optional copy_function argument is a callable that will be used + to copy each file. It will be called with the source path and the + destination path as arguments. By default, copy2() is used, but any + function that supports the same signature (like copy()) can be used. """ names = os.listdir(src) @@ -182,14 +212,21 @@ srcname = os.path.join(src, name) dstname = os.path.join(dst, name) try: - if symlinks and os.path.islink(srcname): + if os.path.islink(srcname): linkto = os.readlink(srcname) - os.symlink(linkto, dstname) + if symlinks: + os.symlink(linkto, dstname) + else: + # ignore dangling symlink if the flag is on + if not os.path.exists(linkto) and ignore_dangling_symlinks: + continue + # otherwise let the copy occurs. copy2 will raise an error + copy_function(srcname, dstname) elif os.path.isdir(srcname): - copytree(srcname, dstname, symlinks, ignore) + copytree(srcname, dstname, symlinks, ignore, copy_function) else: # Will raise a SpecialFileError for unsupported file types - copy2(srcname, dstname) + copy_function(srcname, dstname) # catch the Error from the recursive copytree so that we can # continue with other files except Error, err: @@ -205,7 +242,7 @@ else: errors.extend((src, dst, str(why))) if errors: - raise Error, errors + raise Error(errors) def rmtree(path, ignore_errors=False, onerror=None): """Recursively delete a directory tree. @@ -235,7 +272,7 @@ names = [] try: names = os.listdir(path) - except os.error, err: + except os.error: onerror(os.listdir, path, sys.exc_info()) for name in names: fullname = os.path.join(path, name) @@ -248,7 +285,7 @@ else: try: os.remove(fullname) - except os.error, err: + except os.error: onerror(os.remove, fullname, sys.exc_info()) try: os.rmdir(path) @@ -282,13 +319,13 @@ if os.path.isdir(dst): real_dst = os.path.join(dst, _basename(src)) if os.path.exists(real_dst): - raise Error, "Destination path '%s' already exists" % real_dst + raise Error("Destination path '%s' already exists" % real_dst) try: os.rename(src, real_dst) except OSError: if os.path.isdir(src): if _destinsrc(src, dst): - raise Error, "Cannot move a directory '%s' into itself '%s'." % (src, dst) + raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) copytree(src, real_dst, symlinks=True) rmtree(src) else: @@ -333,40 +370,41 @@ """Create a (possibly compressed) tar file from all the files under 'base_dir'. - 'compress' must be "gzip" (the default), "compress", "bzip2", or None. - (compress will be deprecated in Python 3.2) + 'compress' must be "gzip" (the default), "bzip2", or None. 'owner' and 'group' can be used to define an owner and a group for the archive that is being built. If not provided, the current owner and group will be used. The output tar file will be named 'base_dir' + ".tar", possibly plus - the appropriate compression extension (".gz", ".bz2" or ".Z"). + the appropriate compression extension (".gz", or ".bz2"). Returns the output filename. """ - tar_compression = {'gzip': 'gz', 'bzip2': 'bz2', None: '', 'compress': ''} - compress_ext = {'gzip': '.gz', 'bzip2': '.bz2', 'compress': '.Z'} + tar_compression = {'gzip': 'gz', None: ''} + compress_ext = {'gzip': '.gz'} + + if _BZ2_SUPPORTED: + tar_compression['bzip2'] = 'bz2' + compress_ext['bzip2'] = '.bz2' # flags for compression program, each element of list will be an argument if compress is not None and compress not in compress_ext: - raise ValueError, \ - ("bad value for 'compress': must be None, 'gzip', 'bzip2' " - "or 'compress'") + raise ValueError("bad value for 'compress', or compression format not " + "supported: %s" % compress) - archive_name = base_name + '.tar' - if compress != 'compress': - archive_name += compress_ext.get(compress, '') + archive_name = base_name + '.tar' + compress_ext.get(compress, '') + archive_dir = os.path.dirname(archive_name) - archive_dir = os.path.dirname(archive_name) if not os.path.exists(archive_dir): if logger is not None: - logger.info("creating %s" % archive_dir) + logger.info("creating %s", archive_dir) if not dry_run: os.makedirs(archive_dir) - # creating the tarball + # XXX late import because of circular dependency between shutil and + # tarfile :( from distutils2._backport import tarfile if logger is not None: @@ -391,23 +429,9 @@ finally: tar.close() - # compression using `compress` - # XXX this block will be removed in Python 3.2 - if compress == 'compress': - warn("'compress' will be deprecated.", PendingDeprecationWarning) - # the option varies depending on the platform - compressed_name = archive_name + compress_ext[compress] - if sys.platform == 'win32': - cmd = [compress, archive_name, compressed_name] - else: - cmd = [compress, '-f', archive_name] - from distutils2.spawn import spawn - spawn(cmd, dry_run=dry_run) - return compressed_name - return archive_name -def _call_external_zip(directory, verbose=False): +def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False): # XXX see if we want to keep an external call here if verbose: zipoptions = "-r" @@ -420,8 +444,7 @@ except DistutilsExecError: # XXX really should distinguish between "couldn't find # external 'zip' command" and "zip failed". - raise ExecError, \ - ("unable to create zip file '%s': " + raise ExecError("unable to create zip file '%s': " "could neither import the 'zipfile' module nor " "find a standalone zip utility") % zip_filename @@ -451,7 +474,7 @@ zipfile = None if zipfile is None: - _call_external_zip(base_dir, verbose) + _call_external_zip(base_dir, zip_filename, verbose, dry_run) else: if logger is not None: logger.info("creating '%s' and adding '%s' to it", @@ -475,12 +498,14 @@ _ARCHIVE_FORMATS = { 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), 'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), - 'ztar': (_make_tarball, [('compress', 'compress')], - "compressed tar file"), 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"), - 'zip': (_make_zipfile, [],"ZIP file") + 'zip': (_make_zipfile, [], "ZIP file"), } +if _BZ2_SUPPORTED: + _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], + "bzip2'ed tar-file") + def get_archive_formats(): """Returns a list of supported formats for archiving and unarchiving. @@ -507,7 +532,7 @@ if not isinstance(extra_args, (tuple, list)): raise TypeError('extra_args needs to be a sequence') for element in extra_args: - if not isinstance(element, (tuple, list)) or len(element) !=2 : + if not isinstance(element, (tuple, list)) or len(element) !=2: raise TypeError('extra_args elements are : (arg_name, value)') _ARCHIVE_FORMATS[name] = (function, extra_args, description) @@ -520,7 +545,7 @@ """Create an archive file (eg. zip or tar). 'base_name' is the name of the file to create, minus any format-specific - extension; 'format' is the archive format: one of "zip", "tar", "ztar", + extension; 'format' is the archive format: one of "zip", "tar", "bztar" or "gztar". 'root_dir' is a directory that will be the root directory of the @@ -549,7 +574,7 @@ try: format_info = _ARCHIVE_FORMATS[format] except KeyError: - raise ValueError, "unknown archive format '%s'" % format + raise ValueError("unknown archive format '%s'" % format) func = format_info[0] for arg, val in format_info[1]: @@ -568,3 +593,169 @@ os.chdir(save_cwd) return filename + + +def get_unpack_formats(): + """Returns a list of supported formats for unpacking. + + Each element of the returned sequence is a tuple + (name, extensions, description) + """ + formats = [(name, info[0], info[3]) for name, info in + _UNPACK_FORMATS.iteritems()] + formats.sort() + return formats + +def _check_unpack_options(extensions, function, extra_args): + """Checks what gets registered as an unpacker.""" + # first make sure no other unpacker is registered for this extension + existing_extensions = {} + for name, info in _UNPACK_FORMATS.iteritems(): + for ext in info[0]: + existing_extensions[ext] = name + + for extension in extensions: + if extension in existing_extensions: + msg = '%s is already registered for "%s"' + raise RegistryError(msg % (extension, + existing_extensions[extension])) + + if not callable(function): + raise TypeError('The registered function must be a callable') + + +def register_unpack_format(name, extensions, function, extra_args=None, + description=''): + """Registers an unpack format. + + `name` is the name of the format. `extensions` is a list of extensions + corresponding to the format. + + `function` is the callable that will be + used to unpack archives. The callable will receive archives to unpack. + If it's unable to handle an archive, it needs to raise a ReadError + exception. + + If provided, `extra_args` is a sequence of + (name, value) tuples that will be passed as arguments to the callable. + description can be provided to describe the format, and will be returned + by the get_unpack_formats() function. + """ + if extra_args is None: + extra_args = [] + _check_unpack_options(extensions, function, extra_args) + _UNPACK_FORMATS[name] = extensions, function, extra_args, description + +def unregister_unpack_format(name): + """Removes the pack format from the registery.""" + del _UNPACK_FORMATS[name] + +def _ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + if not os.path.isdir(dirname): + os.makedirs(dirname) + +def _unpack_zipfile(filename, extract_dir): + """Unpack zip `filename` to `extract_dir` + """ + try: + import zipfile + except ImportError: + raise ReadError('zlib not supported, cannot unpack this archive.') + + if not zipfile.is_zipfile(filename): + raise ReadError("%s is not a zip file" % filename) + + zip = zipfile.ZipFile(filename) + try: + for info in zip.infolist(): + name = info.filename + + # don't extract absolute paths or ones with .. in them + if name.startswith('/') or '..' in name: + continue + + target = os.path.join(extract_dir, *name.split('/')) + if not target: + continue + + _ensure_directory(target) + if not name.endswith('/'): + # file + data = zip.read(info.filename) + f = open(target, 'wb') + try: + f.write(data) + finally: + f.close() + del data + finally: + zip.close() + +def _unpack_tarfile(filename, extract_dir): + """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` + """ + from distutils2._backport import tarfile + try: + tarobj = tarfile.open(filename) + except tarfile.TarError: + raise ReadError( + "%s is not a compressed or uncompressed tar file" % filename) + try: + tarobj.extractall(extract_dir) + finally: + tarobj.close() + +_UNPACK_FORMATS = { + 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"), + 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"), + 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file") + } + +if _BZ2_SUPPORTED: + _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], + "bzip2'ed tar-file") + +def _find_unpack_format(filename): + for name, info in _UNPACK_FORMATS.iteritems(): + for extension in info[0]: + if filename.endswith(extension): + return name + return None + +def unpack_archive(filename, extract_dir=None, format=None): + """Unpack an archive. + + `filename` is the name of the archive. + + `extract_dir` is the name of the target directory, where the archive + is unpacked. If not provided, the current working directory is used. + + `format` is the archive format: one of "zip", "tar", or "gztar". Or any + other registered format. If not provided, unpack_archive will use the + filename extension and see if an unpacker was registered for that + extension. + + In case none is found, a ValueError is raised. + """ + if extract_dir is None: + extract_dir = os.getcwd() + + if format is not None: + try: + format_info = _UNPACK_FORMATS[format] + except KeyError: + raise ValueError("Unknown unpack format '{0}'".format(format)) + + func = format_info[0] + func(filename, extract_dir, **dict(format_info[1])) + else: + # we need to look at the registered unpackers supported extensions + format = _find_unpack_format(filename) + if format is None: + raise ReadError("Unknown archive format '{0}'".format(filename)) + + func = _UNPACK_FORMATS[format][1] + kwargs = dict(_UNPACK_FORMATS[format][2]) + raise ValueError('Unknown archive format: %s' % filename) diff --git a/distutils2/_backport/tests/test_pkgutil.py b/distutils2/_backport/tests/test_pkgutil.py --- a/distutils2/_backport/tests/test_pkgutil.py +++ b/distutils2/_backport/tests/test_pkgutil.py @@ -12,10 +12,15 @@ except ImportError: from distutils2._backport.hashlib import md5 -from test.test_support import TESTFN +from distutils2.errors import DistutilsError +from distutils2.metadata import DistributionMetadata +from distutils2.tests import unittest, run_unittest, support -from distutils2.tests import unittest, run_unittest, support from distutils2._backport import pkgutil +from distutils2._backport.pkgutil import ( + Distribution, EggInfoDistribution, get_distribution, get_distributions, + provides_distribution, obsoletes_distribution, get_file_users, + distinfo_dirname, _yield_distributions) try: from os.path import relpath @@ -108,6 +113,12 @@ self.assertEqual(res1, RESOURCE_DATA) res2 = pkgutil.get_data(pkg, 'sub/res.txt') self.assertEqual(res2, RESOURCE_DATA) + + names = [] + for loader, name, ispkg in pkgutil.iter_modules([zip_file]): + names.append(name) + self.assertEqual(names, ['test_getdata_zipfile']) + del sys.path[0] del sys.modules[pkg] @@ -205,7 +216,7 @@ record_writer.writerow(record_pieces( os.path.join(distinfo_dir, file))) record_writer.writerow([relpath(record_file, sys.prefix)]) - del record_writer # causes the RECORD file to close + del record_writer # causes the RECORD file to close record_reader = csv.reader(open(record_file, 'rb')) record_data = [] for row in record_reader: @@ -225,9 +236,6 @@ def test_instantiation(self): # Test the Distribution class's instantiation provides us with usable # attributes. - # Import the Distribution class - from distutils2._backport.pkgutil import distinfo_dirname, Distribution - here = os.path.abspath(os.path.dirname(__file__)) name = 'choxie' version = '2.0.0.9' @@ -236,7 +244,6 @@ dist = Distribution(dist_path) self.assertEqual(dist.name, name) - from distutils2.metadata import DistributionMetadata self.assertTrue(isinstance(dist.metadata, DistributionMetadata)) self.assertEqual(dist.metadata['version'], version) self.assertTrue(isinstance(dist.requested, type(bool()))) @@ -244,7 +251,6 @@ def test_installed_files(self): # Test the iteration of installed files. # Test the distribution's installed files - from distutils2._backport.pkgutil import Distribution for distinfo_dir in self.distinfo_dirs: dist = Distribution(distinfo_dir) for path, md5_, size in dist.get_installed_files(): @@ -267,14 +273,12 @@ false_path = relpath(os.path.join(*false_path), sys.prefix) # Test if the distribution uses the file in question - from distutils2._backport.pkgutil import Distribution dist = Distribution(distinfo_dir) self.assertTrue(dist.uses(true_path)) self.assertFalse(dist.uses(false_path)) def test_get_distinfo_file(self): # Test the retrieval of dist-info file objects. - from distutils2._backport.pkgutil import Distribution distinfo_name = 'choxie-2.0.0.9' other_distinfo_name = 'grammar-1.0a4' distinfo_dir = os.path.join(self.fake_dists_path, @@ -295,7 +299,6 @@ # Is it the correct file? self.assertEqual(value.name, os.path.join(distinfo_dir, distfile)) - from distutils2.errors import DistutilsError # Test an absolute path that is part of another distributions dist-info other_distinfo_file = os.path.join(self.fake_dists_path, other_distinfo_name + '.dist-info', 'REQUESTED') @@ -307,7 +310,6 @@ def test_get_distinfo_files(self): # Test for the iteration of RECORD path entries. - from distutils2._backport.pkgutil import Distribution distinfo_name = 'towel_stuff-0.1' distinfo_dir = os.path.join(self.fake_dists_path, distinfo_name + '.dist-info') @@ -345,7 +347,7 @@ # Given a name and a version, we expect the distinfo_dirname function # to return a standard distribution information directory name. - items = [# (name, version, standard_dirname) + items = [ # (name, version, standard_dirname) # Test for a very simple single word name and decimal # version number ('docutils', '0.5', 'docutils-0.5.dist-info'), @@ -356,9 +358,6 @@ ('python-ldap', '2.5 a---5', 'python_ldap-2.5 a---5.dist-info'), ] - # Import the function in question - from distutils2._backport.pkgutil import distinfo_dirname - # Loop through the items to validate the results for name, version, standard_dirname in items: dirname = distinfo_dirname(name, version) @@ -371,11 +370,6 @@ ('towel-stuff', '0.1')] found_dists = [] - # Import the function in question - from distutils2._backport.pkgutil import get_distributions, \ - Distribution, \ - EggInfoDistribution - # Verify the fake dists have been found. dists = [dist for dist in get_distributions()] for dist in dists: @@ -416,12 +410,7 @@ def test_get_distribution(self): # Test for looking up a distribution by name. # Test the lookup of the towel-stuff distribution - name = 'towel-stuff' # Note: This is different from the directory name - - # Import the function in question - from distutils2._backport.pkgutil import get_distribution, \ - Distribution, \ - EggInfoDistribution + name = 'towel-stuff' # Note: This is different from the directory name # Lookup the distribution dist = get_distribution(name) @@ -461,7 +450,6 @@ def test_get_file_users(self): # Test the iteration of distributions that use a file. - from distutils2._backport.pkgutil import get_file_users, Distribution name = 'towel_stuff-0.1' path = os.path.join(self.fake_dists_path, name, 'towel_stuff', '__init__.py') @@ -471,9 +459,6 @@ def test_provides(self): # Test for looking up distributions by what they provide - from distutils2._backport.pkgutil import provides_distribution - from distutils2.errors import DistutilsError - checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) l = [dist.name for dist in provides_distribution('truffles')] @@ -522,12 +507,10 @@ use_egg_info=True)] checkLists(l, ['strawberry']) - l = [dist.name for dist in provides_distribution('strawberry', '>0.6', use_egg_info=True)] checkLists(l, []) - l = [dist.name for dist in provides_distribution('banana', '0.4', use_egg_info=True)] checkLists(l, ['banana']) @@ -536,16 +519,12 @@ use_egg_info=True)] checkLists(l, ['banana']) - l = [dist.name for dist in provides_distribution('banana', '!=0.4', use_egg_info=True)] checkLists(l, []) def test_obsoletes(self): # Test looking for distributions based on what they obsolete - from distutils2._backport.pkgutil import obsoletes_distribution - from distutils2.errors import DistutilsError - checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) l = [dist.name for dist in obsoletes_distribution('truffles', '1.0')] @@ -555,7 +534,6 @@ use_egg_info=True)] checkLists(l, ['cheese', 'bacon']) - l = [dist.name for dist in obsoletes_distribution('truffles', '0.8')] checkLists(l, ['choxie']) @@ -575,7 +553,6 @@ def test_yield_distribution(self): # tests the internal function _yield_distributions - from distutils2._backport.pkgutil import _yield_distributions checkLists = lambda x, y: self.assertListEqual(sorted(x), sorted(y)) eggs = [('bacon', '0.1'), ('banana', '0.4'), ('strawberry', '0.6'), diff --git a/distutils2/_backport/tests/test_shutil.py b/distutils2/_backport/tests/test_shutil.py new file mode 100644 --- /dev/null +++ b/distutils2/_backport/tests/test_shutil.py @@ -0,0 +1,945 @@ +import os +import sys +import tempfile +import stat +import tarfile +from os.path import splitdrive +from StringIO import StringIO + +from distutils.spawn import find_executable, spawn +from distutils2._backport import shutil +from distutils2._backport.shutil import ( + _make_tarball, _make_zipfile, make_archive, unpack_archive, + register_archive_format, unregister_archive_format, get_archive_formats, + register_unpack_format, unregister_unpack_format, get_unpack_formats, + Error, RegistryError) + +from distutils2.tests import unittest, support, TESTFN + +try: + import bz2 + BZ2_SUPPORTED = True +except ImportError: + BZ2_SUPPORTED = False + +TESTFN2 = TESTFN + "2" + +try: + import grp + import pwd + UID_GID_SUPPORT = True +except ImportError: + UID_GID_SUPPORT = False + +try: + import zlib +except ImportError: + zlib = None + +try: + import zipfile + ZIP_SUPPORT = True +except ImportError: + ZIP_SUPPORT = find_executable('zip') + +class TestShutil(unittest.TestCase): + + def setUp(self): + super(TestShutil, self).setUp() + self.tempdirs = [] + + def tearDown(self): + super(TestShutil, self).tearDown() + while self.tempdirs: + d = self.tempdirs.pop() + shutil.rmtree(d, os.name in ('nt', 'cygwin')) + + def write_file(self, path, content='xxx'): + """Writes a file in the given path. + + + path can be a string or a sequence. + """ + if isinstance(path, (list, tuple)): + path = os.path.join(*path) + f = open(path, 'w') + try: + f.write(content) + finally: + f.close() + + def mkdtemp(self): + """Create a temporary directory that will be cleaned up. + + Returns the path of the directory. + """ + d = tempfile.mkdtemp() + self.tempdirs.append(d) + return d + + def test_rmtree_errors(self): + # filename is guaranteed not to exist + filename = tempfile.mktemp() + self.assertRaises(OSError, shutil.rmtree, filename) + + # See bug #1071513 for why we don't run this on cygwin + # and bug #1076467 for why we don't run this as root. + if (hasattr(os, 'chmod') and sys.platform[:6] != 'cygwin' + and not (hasattr(os, 'geteuid') and os.geteuid() == 0)): + def test_on_error(self): + self.errorState = 0 + os.mkdir(TESTFN) + self.childpath = os.path.join(TESTFN, 'a') + f = open(self.childpath, 'w') + f.close() + old_dir_mode = os.stat(TESTFN).st_mode + old_child_mode = os.stat(self.childpath).st_mode + # Make unwritable. + os.chmod(self.childpath, stat.S_IREAD) + os.chmod(TESTFN, stat.S_IREAD) + + shutil.rmtree(TESTFN, onerror=self.check_args_to_onerror) + # Test whether onerror has actually been called. + self.assertEqual(self.errorState, 2, + "Expected call to onerror function did not happen.") + + # Make writable again. + os.chmod(TESTFN, old_dir_mode) + os.chmod(self.childpath, old_child_mode) + + # Clean up. + shutil.rmtree(TESTFN) + + def check_args_to_onerror(self, func, arg, exc): + # test_rmtree_errors deliberately runs rmtree + # on a directory that is chmod 400, which will fail. + # This function is run when shutil.rmtree fails. + # 99.9% of the time it initially fails to remove + # a file in the directory, so the first time through + # func is os.remove. + # However, some Linux machines running ZFS on + # FUSE experienced a failure earlier in the process + # at os.listdir. The first failure may legally + # be either. + if self.errorState == 0: + if func is os.remove: + self.assertEqual(arg, self.childpath) + else: + self.assertIs(func, os.listdir, + "func must be either os.remove or os.listdir") + self.assertEqual(arg, TESTFN) + self.assertTrue(issubclass(exc[0], OSError)) + self.errorState = 1 + else: + self.assertEqual(func, os.rmdir) + self.assertEqual(arg, TESTFN) + self.assertTrue(issubclass(exc[0], OSError)) + self.errorState = 2 + + def test_rmtree_dont_delete_file(self): + # When called on a file instead of a directory, don't delete it. + handle, path = tempfile.mkstemp() + os.fdopen(handle).close() + self.assertRaises(OSError, shutil.rmtree, path) + os.remove(path) + + def _write_data(self, path, data): + f = open(path, "w") + f.write(data) + f.close() + + def test_copytree_simple(self): + + def read_data(path): + f = open(path) + data = f.read() + f.close() + return data + + src_dir = tempfile.mkdtemp() + dst_dir = os.path.join(tempfile.mkdtemp(), 'destination') + self._write_data(os.path.join(src_dir, 'test.txt'), '123') + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + + try: + shutil.copytree(src_dir, dst_dir) + self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test.txt'))) + self.assertTrue(os.path.isdir(os.path.join(dst_dir, 'test_dir'))) + self.assertTrue(os.path.isfile(os.path.join(dst_dir, 'test_dir', + 'test.txt'))) + actual = read_data(os.path.join(dst_dir, 'test.txt')) + self.assertEqual(actual, '123') + actual = read_data(os.path.join(dst_dir, 'test_dir', 'test.txt')) + self.assertEqual(actual, '456') + finally: + for path in ( + os.path.join(src_dir, 'test.txt'), + os.path.join(dst_dir, 'test.txt'), + os.path.join(src_dir, 'test_dir', 'test.txt'), + os.path.join(dst_dir, 'test_dir', 'test.txt'), + ): + if os.path.exists(path): + os.remove(path) + for path in (src_dir, + os.path.dirname(dst_dir) + ): + if os.path.exists(path): + shutil.rmtree(path) + + def test_copytree_with_exclude(self): + + def read_data(path): + f = open(path) + data = f.read() + f.close() + return data + + # creating data + join = os.path.join + exists = os.path.exists + src_dir = tempfile.mkdtemp() + try: + dst_dir = join(tempfile.mkdtemp(), 'destination') + self._write_data(join(src_dir, 'test.txt'), '123') + self._write_data(join(src_dir, 'test.tmp'), '123') + os.mkdir(join(src_dir, 'test_dir')) + self._write_data(join(src_dir, 'test_dir', 'test.txt'), '456') + os.mkdir(join(src_dir, 'test_dir2')) + self._write_data(join(src_dir, 'test_dir2', 'test.txt'), '456') + os.mkdir(join(src_dir, 'test_dir2', 'subdir')) + os.mkdir(join(src_dir, 'test_dir2', 'subdir2')) + self._write_data(join(src_dir, 'test_dir2', 'subdir', 'test.txt'), + '456') + self._write_data(join(src_dir, 'test_dir2', 'subdir2', 'test.py'), + '456') + + + # testing glob-like patterns + try: + patterns = shutil.ignore_patterns('*.tmp', 'test_dir2') + shutil.copytree(src_dir, dst_dir, ignore=patterns) + # checking the result: some elements should not be copied + self.assertTrue(exists(join(dst_dir, 'test.txt'))) + self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2'))) + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + try: + patterns = shutil.ignore_patterns('*.tmp', 'subdir*') + shutil.copytree(src_dir, dst_dir, ignore=patterns) + # checking the result: some elements should not be copied + self.assertTrue(not exists(join(dst_dir, 'test.tmp'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + + # testing callable-style + try: + def _filter(src, names): + res = [] + for name in names: + path = os.path.join(src, name) + + if (os.path.isdir(path) and + path.split()[-1] == 'subdir'): + res.append(name) + elif os.path.splitext(path)[-1] in ('.py'): + res.append(name) + return res + + shutil.copytree(src_dir, dst_dir, ignore=_filter) + + # checking the result: some elements should not be copied + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir2', + 'test.py'))) + self.assertTrue(not exists(join(dst_dir, 'test_dir2', 'subdir'))) + + finally: + if os.path.exists(dst_dir): + shutil.rmtree(dst_dir) + finally: + shutil.rmtree(src_dir) + shutil.rmtree(os.path.dirname(dst_dir)) + + @support.skip_unless_symlink + def test_dont_copy_file_onto_link_to_itself(self): + # bug 851123. + os.mkdir(TESTFN) + src = os.path.join(TESTFN, 'cheese') + dst = os.path.join(TESTFN, 'shop') + try: + f = open(src, 'w') + f.write('cheddar') + f.close() + + if hasattr(os, "link"): + os.link(src, dst) + self.assertRaises(shutil.Error, shutil.copyfile, src, dst) + f = open(src, 'r') + try: + self.assertEqual(f.read(), 'cheddar') + finally: + f.close() + os.remove(dst) + + # Using `src` here would mean we end up with a symlink pointing + # to TESTFN/TESTFN/cheese, while it should point at + # TESTFN/cheese. + os.symlink('cheese', dst) + self.assertRaises(shutil.Error, shutil.copyfile, src, dst) + f = open(src, 'r') + try: + self.assertEqual(f.read(), 'cheddar') + finally: + f.close() + os.remove(dst) + finally: + try: + shutil.rmtree(TESTFN) + except OSError: + pass + + @support.skip_unless_symlink + def test_rmtree_on_symlink(self): + # bug 1669. + os.mkdir(TESTFN) + try: + src = os.path.join(TESTFN, 'cheese') + dst = os.path.join(TESTFN, 'shop') + os.mkdir(src) + os.symlink(src, dst) + self.assertRaises(OSError, shutil.rmtree, dst) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + if hasattr(os, "mkfifo"): + # Issue #3002: copyfile and copytree block indefinitely on named pipes + def test_copyfile_named_pipe(self): + os.mkfifo(TESTFN) + try: + self.assertRaises(shutil.SpecialFileError, + shutil.copyfile, TESTFN, TESTFN2) + self.assertRaises(shutil.SpecialFileError, + shutil.copyfile, __file__, TESTFN) + finally: + os.remove(TESTFN) + + @unittest.skipUnless(hasattr(os, 'mkfifo'), 'requires os.mkfifo') + def test_copytree_named_pipe(self): + os.mkdir(TESTFN) + try: + subdir = os.path.join(TESTFN, "subdir") + os.mkdir(subdir) + pipe = os.path.join(subdir, "mypipe") + os.mkfifo(pipe) + try: + shutil.copytree(TESTFN, TESTFN2) + except shutil.Error, e: + errors = e.args[0] + self.assertEqual(len(errors), 1) + src, dst, error_msg = errors[0] + self.assertEqual("`%s` is a named pipe" % pipe, error_msg) + else: + self.fail("shutil.Error should have been raised") + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + shutil.rmtree(TESTFN2, ignore_errors=True) + + def test_copytree_special_func(self): + + src_dir = self.mkdtemp() + dst_dir = os.path.join(self.mkdtemp(), 'destination') + self._write_data(os.path.join(src_dir, 'test.txt'), '123') + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + + copied = [] + def _copy(src, dst): + copied.append((src, dst)) + + shutil.copytree(src_dir, dst_dir, copy_function=_copy) + self.assertEquals(len(copied), 2) + + @support.skip_unless_symlink + def test_copytree_dangling_symlinks(self): + + # a dangling symlink raises an error at the end + src_dir = self.mkdtemp() + dst_dir = os.path.join(self.mkdtemp(), 'destination') + os.symlink('IDONTEXIST', os.path.join(src_dir, 'test.txt')) + os.mkdir(os.path.join(src_dir, 'test_dir')) + self._write_data(os.path.join(src_dir, 'test_dir', 'test.txt'), '456') + self.assertRaises(Error, shutil.copytree, src_dir, dst_dir) + + # a dangling symlink is ignored with the proper flag + dst_dir = os.path.join(self.mkdtemp(), 'destination2') + shutil.copytree(src_dir, dst_dir, ignore_dangling_symlinks=True) + self.assertNotIn('test.txt', os.listdir(dst_dir)) + + # a dangling symlink is copied if symlinks=True + dst_dir = os.path.join(self.mkdtemp(), 'destination3') + shutil.copytree(src_dir, dst_dir, symlinks=True) + self.assertIn('test.txt', os.listdir(dst_dir)) + + @unittest.skipUnless(zlib, "requires zlib") + def test_make_tarball(self): + # creating something to tar + tmpdir = self.mkdtemp() + self.write_file([tmpdir, 'file1'], 'xxx') + self.write_file([tmpdir, 'file2'], 'xxx') + os.mkdir(os.path.join(tmpdir, 'sub')) + self.write_file([tmpdir, 'sub', 'file3'], 'xxx') + + tmpdir2 = self.mkdtemp() + unittest.skipUnless(splitdrive(tmpdir)[0] == splitdrive(tmpdir2)[0], + "source and target should be on same drive") + + base_name = os.path.join(tmpdir2, 'archive') + + # working with relative paths to avoid tar warnings + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(splitdrive(base_name)[1], '.') + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + tarball = base_name + '.tar.gz' + self.assertTrue(os.path.exists(tarball)) + + # trying an uncompressed one + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(splitdrive(base_name)[1], '.', compress=None) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + def _tarinfo(self, path): + tar = tarfile.open(path) + try: + names = tar.getnames() + names.sort() + return tuple(names) + finally: + tar.close() + + def _create_files(self): + # creating something to tar + tmpdir = self.mkdtemp() + dist = os.path.join(tmpdir, 'dist') + os.mkdir(dist) + self.write_file([dist, 'file1'], 'xxx') + self.write_file([dist, 'file2'], 'xxx') + os.mkdir(os.path.join(dist, 'sub')) + self.write_file([dist, 'sub', 'file3'], 'xxx') + os.mkdir(os.path.join(dist, 'sub2')) + tmpdir2 = self.mkdtemp() + base_name = os.path.join(tmpdir2, 'archive') + return tmpdir, tmpdir2, base_name + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(find_executable('tar') and find_executable('gzip'), + 'Need the tar command to run') + def test_tarfile_vs_tar(self): + tmpdir, tmpdir2, base_name = self._create_files() + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist') + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + tarball = base_name + '.tar.gz' + self.assertTrue(os.path.exists(tarball)) + + # now create another tarball using `tar` + tarball2 = os.path.join(tmpdir, 'archive2.tar.gz') + tar_cmd = ['tar', '-cf', 'archive2.tar', 'dist'] + gzip_cmd = ['gzip', '-f9', 'archive2.tar'] + old_dir = os.getcwd() + old_stdout = sys.stdout + os.chdir(tmpdir) + sys.stdout = StringIO() + + try: + spawn(tar_cmd) + spawn(gzip_cmd) + finally: + os.chdir(old_dir) + sys.stdout = old_stdout + + self.assertTrue(os.path.exists(tarball2)) + # let's compare both tarballs + self.assertEquals(self._tarinfo(tarball), self._tarinfo(tarball2)) + + # trying an uncompressed one + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist', compress=None) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + # now for a dry_run + base_name = os.path.join(tmpdir2, 'archive') + old_dir = os.getcwd() + os.chdir(tmpdir) + try: + _make_tarball(base_name, 'dist', compress=None, dry_run=True) + finally: + os.chdir(old_dir) + tarball = base_name + '.tar' + self.assertTrue(os.path.exists(tarball)) + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(ZIP_SUPPORT, 'Need zip support to run') + def test_make_zipfile(self): + # creating something to tar + tmpdir = self.mkdtemp() + self.write_file([tmpdir, 'file1'], 'xxx') + self.write_file([tmpdir, 'file2'], 'xxx') + + tmpdir2 = self.mkdtemp() + base_name = os.path.join(tmpdir2, 'archive') + _make_zipfile(base_name, tmpdir) + + # check if the compressed tarball was created + tarball = base_name + '.zip' + self.assertTrue(os.path.exists(tarball)) + + + def test_make_archive(self): + tmpdir = self.mkdtemp() + base_name = os.path.join(tmpdir, 'archive') + self.assertRaises(ValueError, make_archive, base_name, 'xxx') + + @unittest.skipUnless(zlib, "Requires zlib") + def test_make_archive_owner_group(self): + # testing make_archive with owner and group, with various combinations + # this works even if there's not gid/uid support + if UID_GID_SUPPORT: + group = grp.getgrgid(0)[0] + owner = pwd.getpwuid(0)[0] + else: + group = owner = 'root' + + base_dir, root_dir, base_name = self._create_files() + base_name = os.path.join(self.mkdtemp() , 'archive') + res = make_archive(base_name, 'zip', root_dir, base_dir, owner=owner, + group=group) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'zip', root_dir, base_dir) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'tar', root_dir, base_dir, + owner=owner, group=group) + self.assertTrue(os.path.exists(res)) + + res = make_archive(base_name, 'tar', root_dir, base_dir, + owner='kjhkjhkjg', group='oihohoh') + self.assertTrue(os.path.exists(res)) + + + @unittest.skipUnless(zlib, "Requires zlib") + @unittest.skipUnless(UID_GID_SUPPORT, "Requires grp and pwd support") + def test_tarfile_root_owner(self): + tmpdir, tmpdir2, base_name = self._create_files() + old_dir = os.getcwd() + os.chdir(tmpdir) + group = grp.getgrgid(0)[0] + owner = pwd.getpwuid(0)[0] + try: + archive_name = _make_tarball(base_name, 'dist', compress=None, + owner=owner, group=group) + finally: + os.chdir(old_dir) + + # check if the compressed tarball was created + self.assertTrue(os.path.exists(archive_name)) + + # now checks the rights + archive = tarfile.open(archive_name) + try: + for member in archive.getmembers(): + self.assertEquals(member.uid, 0) + self.assertEquals(member.gid, 0) + finally: + archive.close() + + def test_make_archive_cwd(self): + current_dir = os.getcwd() + def _breaks(*args, **kw): + raise RuntimeError() + + register_archive_format('xxx', _breaks, [], 'xxx file') + try: + try: + make_archive('xxx', 'xxx', root_dir=self.mkdtemp()) + except Exception: + pass + self.assertEquals(os.getcwd(), current_dir) + finally: + unregister_archive_format('xxx') + + def test_register_archive_format(self): + + self.assertRaises(TypeError, register_archive_format, 'xxx', 1) + self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x, + 1) + self.assertRaises(TypeError, register_archive_format, 'xxx', lambda: x, + [(1, 2), (1, 2, 3)]) + + register_archive_format('xxx', lambda: x, [(1, 2)], 'xxx file') + formats = [name for name, params in get_archive_formats()] + self.assertIn('xxx', formats) + + unregister_archive_format('xxx') + formats = [name for name, params in get_archive_formats()] + self.assertNotIn('xxx', formats) + + def _compare_dirs(self, dir1, dir2): + # check that dir1 and dir2 are equivalent, + # return the diff + diff = [] + for root, dirs, files in os.walk(dir1): + for file_ in files: + path = os.path.join(root, file_) + target_path = os.path.join(dir2, os.path.split(path)[-1]) + if not os.path.exists(target_path): + diff.append(file_) + return diff + + @unittest.skipUnless(zlib, "Requires zlib") + def test_unpack_archive(self): + formats = ['tar', 'gztar', 'zip'] + if BZ2_SUPPORTED: + formats.append('bztar') + + for format in formats: + tmpdir = self.mkdtemp() + base_dir, root_dir, base_name = self._create_files() + tmpdir2 = self.mkdtemp() + filename = make_archive(base_name, format, root_dir, base_dir) + + # let's try to unpack it now + unpack_archive(filename, tmpdir2) + diff = self._compare_dirs(tmpdir, tmpdir2) + self.assertEquals(diff, []) + + def test_unpack_registery(self): + + formats = get_unpack_formats() + + def _boo(filename, extract_dir, extra): + self.assertEquals(extra, 1) + self.assertEquals(filename, 'stuff.boo') + self.assertEquals(extract_dir, 'xx') + + register_unpack_format('Boo', ['.boo', '.b2'], _boo, [('extra', 1)]) + unpack_archive('stuff.boo', 'xx') + + # trying to register a .boo unpacker again + self.assertRaises(RegistryError, register_unpack_format, 'Boo2', + ['.boo'], _boo) + + # should work now + unregister_unpack_format('Boo') + register_unpack_format('Boo2', ['.boo'], _boo) + self.assertIn(('Boo2', ['.boo'], ''), get_unpack_formats()) + self.assertNotIn(('Boo', ['.boo'], ''), get_unpack_formats()) + + # let's leave a clean state + unregister_unpack_format('Boo2') + self.assertEquals(get_unpack_formats(), formats) + + +class TestMove(unittest.TestCase): + + def setUp(self): + filename = "foo" + self.src_dir = tempfile.mkdtemp() + self.dst_dir = tempfile.mkdtemp() + self.src_file = os.path.join(self.src_dir, filename) + self.dst_file = os.path.join(self.dst_dir, filename) + # Try to create a dir in the current directory, hoping that it is + # not located on the same filesystem as the system tmp dir. + try: + self.dir_other_fs = tempfile.mkdtemp( + dir=os.path.dirname(__file__)) + self.file_other_fs = os.path.join(self.dir_other_fs, + filename) + except OSError: + self.dir_other_fs = None + f = open(self.src_file, "wb") + try: + f.write("spam") + finally: + f.close() + + def tearDown(self): + for d in (self.src_dir, self.dst_dir, self.dir_other_fs): + try: + if d: + shutil.rmtree(d) + except: + pass + + def _check_move_file(self, src, dst, real_dst): + f = open(src, "rb") + try: + contents = f.read() + finally: + f.close() + + shutil.move(src, dst) + f = open(real_dst, "rb") + try: + self.assertEqual(contents, f.read()) + finally: + f.close() + + self.assertFalse(os.path.exists(src)) + + def _check_move_dir(self, src, dst, real_dst): + contents = sorted(os.listdir(src)) + shutil.move(src, dst) + self.assertEqual(contents, sorted(os.listdir(real_dst))) + self.assertFalse(os.path.exists(src)) + + def test_move_file(self): + # Move a file to another location on the same filesystem. + self._check_move_file(self.src_file, self.dst_file, self.dst_file) + + def test_move_file_to_dir(self): + # Move a file inside an existing dir on the same filesystem. + self._check_move_file(self.src_file, self.dst_dir, self.dst_file) + + def test_move_file_other_fs(self): + # Move a file to an existing dir on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_file(self.src_file, self.file_other_fs, + self.file_other_fs) + + def test_move_file_to_dir_other_fs(self): + # Move a file to another location on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_file(self.src_file, self.dir_other_fs, + self.file_other_fs) + + def test_move_dir(self): + # Move a dir to another location on the same filesystem. + dst_dir = tempfile.mktemp() + try: + self._check_move_dir(self.src_dir, dst_dir, dst_dir) + finally: + try: + shutil.rmtree(dst_dir) + except: + pass + + def test_move_dir_other_fs(self): + # Move a dir to another location on another filesystem. + if not self.dir_other_fs: + # skip + return + dst_dir = tempfile.mktemp(dir=self.dir_other_fs) + try: + self._check_move_dir(self.src_dir, dst_dir, dst_dir) + finally: + try: + shutil.rmtree(dst_dir) + except: + pass + + def test_move_dir_to_dir(self): + # Move a dir inside an existing dir on the same filesystem. + self._check_move_dir(self.src_dir, self.dst_dir, + os.path.join(self.dst_dir, os.path.basename(self.src_dir))) + + def test_move_dir_to_dir_other_fs(self): + # Move a dir inside an existing dir on another filesystem. + if not self.dir_other_fs: + # skip + return + self._check_move_dir(self.src_dir, self.dir_other_fs, + os.path.join(self.dir_other_fs, os.path.basename(self.src_dir))) + + def test_existing_file_inside_dest_dir(self): + # A file with the same name inside the destination dir already exists. + f = open(self.dst_file, "wb") + try: + pass + finally: + f.close() + self.assertRaises(shutil.Error, shutil.move, self.src_file, self.dst_dir) + + def test_dont_move_dir_in_itself(self): + # Moving a dir inside itself raises an Error. + dst = os.path.join(self.src_dir, "bar") + self.assertRaises(shutil.Error, shutil.move, self.src_dir, dst) + + def test_destinsrc_false_negative(self): + os.mkdir(TESTFN) + try: + for src, dst in [('srcdir', 'srcdir/dest')]: + src = os.path.join(TESTFN, src) + dst = os.path.join(TESTFN, dst) + self.assertTrue(shutil._destinsrc(src, dst), + msg='_destinsrc() wrongly concluded that ' + 'dst (%s) is not in src (%s)' % (dst, src)) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + def test_destinsrc_false_positive(self): + os.mkdir(TESTFN) + try: + for src, dst in [('srcdir', 'src/dest'), ('srcdir', 'srcdir.new')]: + src = os.path.join(TESTFN, src) + dst = os.path.join(TESTFN, dst) + self.assertFalse(shutil._destinsrc(src, dst), + msg='_destinsrc() wrongly concluded that ' + 'dst (%s) is in src (%s)' % (dst, src)) + finally: + shutil.rmtree(TESTFN, ignore_errors=True) + + +class TestCopyFile(unittest.TestCase): + + _delete = False + + class Faux(object): + _entered = False + _exited_with = None + _raised = False + + def __init__(self, raise_in_exit=False, suppress_at_exit=True): + self._raise_in_exit = raise_in_exit + self._suppress_at_exit = suppress_at_exit + + def read(self, *args): + return '' + + def __enter__(self): + self._entered = True + + def __exit__(self, exc_type, exc_val, exc_tb): + self._exited_with = exc_type, exc_val, exc_tb + if self._raise_in_exit: + self._raised = True + raise IOError("Cannot close") + return self._suppress_at_exit + + def tearDown(self): + if self._delete: + del shutil.open + + def _set_shutil_open(self, func): + shutil.open = func + self._delete = True + + def test_w_source_open_fails(self): + def _open(filename, mode='r'): + if filename == 'srcfile': + raise IOError('Cannot open "srcfile"') + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + self.assertRaises(IOError, shutil.copyfile, 'srcfile', 'destfile') + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_dest_open_fails(self): + + srcfile = self.Faux() + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + raise IOError('Cannot open "destfile"') + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + shutil.copyfile('srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(srcfile._exited_with[0] is IOError) + self.assertEqual(srcfile._exited_with[1].args, + ('Cannot open "destfile"',)) + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_dest_close_fails(self): + + srcfile = self.Faux() + destfile = self.Faux(True) + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + return destfile + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + shutil.copyfile('srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(destfile._entered) + self.assertTrue(destfile._raised) + self.assertTrue(srcfile._exited_with[0] is IOError) + self.assertEqual(srcfile._exited_with[1].args, + ('Cannot close',)) + + @unittest.skip("can't use the with statement and support 2.4") + def test_w_source_close_fails(self): + + srcfile = self.Faux(True) + destfile = self.Faux() + + def _open(filename, mode='r'): + if filename == 'srcfile': + return srcfile + if filename == 'destfile': + return destfile + assert 0 # shouldn't reach here. + + self._set_shutil_open(_open) + + self.assertRaises(IOError, + shutil.copyfile, 'srcfile', 'destfile') + self.assertTrue(srcfile._entered) + self.assertTrue(destfile._entered) + self.assertFalse(destfile._raised) + self.assertTrue(srcfile._exited_with[0] is None) + self.assertTrue(srcfile._raised) + + +def test_suite(): + suite = unittest.TestSuite() + load = unittest.defaultTestLoader.loadTestsFromTestCase + suite.addTest(load(TestCopyFile)) + suite.addTest(load(TestMove)) + suite.addTest(load(TestShutil)) + return suite + + +if __name__ == '__main__': + unittest.main(defaultTest='test_suite') diff --git a/distutils2/_backport/tests/test_sysconfig.py b/distutils2/_backport/tests/test_sysconfig.py --- a/distutils2/_backport/tests/test_sysconfig.py +++ b/distutils2/_backport/tests/test_sysconfig.py @@ -4,7 +4,7 @@ import sys import subprocess import shutil -from copy import copy, deepcopy +from copy import copy from ConfigParser import RawConfigParser from StringIO import StringIO @@ -15,13 +15,9 @@ get_scheme_names, _main, _SCHEMES) from distutils2.tests import unittest -from distutils2.tests.support import EnvironGuard +from distutils2.tests.support import EnvironGuard, skip_unless_symlink from test.test_support import TESTFN, unlink -try: - from test.test_support import skip_unless_symlink -except ImportError: - skip_unless_symlink = unittest.skip( - 'requires test.test_support.skip_unless_symlink') + class TestSysConfig(EnvironGuard, unittest.TestCase): diff --git a/distutils2/command/build_py.py b/distutils2/command/build_py.py --- a/distutils2/command/build_py.py +++ b/distutils2/command/build_py.py @@ -8,7 +8,6 @@ import logging from glob import glob -import distutils2 from distutils2.command.cmd import Command from distutils2.errors import DistutilsOptionError, DistutilsFileError from distutils2.util import convert_path @@ -163,11 +162,13 @@ Helper function for `run()`. """ + # FIXME add tests for this method for package, src_dir, build_dir, filenames in self.data_files: for filename in filenames: target = os.path.join(build_dir, filename) + srcfile = os.path.join(src_dir, filename) self.mkpath(os.path.dirname(target)) - outf, copied = self.copy_file(os.path.join(src_dir, filename), + outf, copied = self.copy_file(srcfile, target, preserve_mode=False) if copied and srcfile in self.distribution.convert_2to3.doctests: self._doctests_2to3.append(outf) diff --git a/distutils2/command/cmd.py b/distutils2/command/cmd.py --- a/distutils2/command/cmd.py +++ b/distutils2/command/cmd.py @@ -165,7 +165,10 @@ header = "command options for '%s':" % self.get_command_name() self.announce(indent + header, level=logging.INFO) indent = indent + " " + negative_opt = getattr(self, 'negative_opt', ()) for (option, _, _) in self.user_options: + if option in negative_opt: + continue option = option.replace('-', '_') if option[-1] == "=": option = option[:-1] diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -7,7 +7,8 @@ from ConfigParser import RawConfigParser from distutils2 import logger -from distutils2.util import check_environ, resolve_name +from distutils2.errors import DistutilsOptionError +from distutils2.util import check_environ, resolve_name, strtobool from distutils2.compiler import set_compiler from distutils2.command import set_command diff --git a/distutils2/index/dist.py b/distutils2/index/dist.py --- a/distutils2/index/dist.py +++ b/distutils2/index/dist.py @@ -17,19 +17,19 @@ import urllib import urlparse import zipfile - try: import hashlib except ImportError: from distutils2._backport import hashlib +from distutils2._backport.shutil import unpack_archive from distutils2.errors import IrrationalVersionError from distutils2.index.errors import (HashDoesNotMatch, UnsupportedHashName, CantParseArchiveName) from distutils2.version import (suggest_normalized_version, NormalizedVersion, get_version_predicate) from distutils2.metadata import DistributionMetadata -from distutils2.util import untar_file, unzip_file, splitext +from distutils2.util import splitext __all__ = ['ReleaseInfo', 'DistInfo', 'ReleasesList', 'get_infos_from_url'] @@ -206,6 +206,7 @@ __hash__ = object.__hash__ + class DistInfo(IndexReference): """Represents a distribution retrieved from an index (sdist, bdist, ...) """ @@ -313,17 +314,8 @@ filename = self.download() content_type = mimetypes.guess_type(filename)[0] + self._unpacked_dir = unpack_archive(filename) - if (content_type == 'application/zip' - or filename.endswith('.zip') - or filename.endswith('.pybundle') - or zipfile.is_zipfile(filename)): - unzip_file(filename, path, flatten=not filename.endswith('.pybundle')) - elif (content_type == 'application/x-gzip' - or tarfile.is_tarfile(filename) - or splitext(filename)[1].lower() in ('.tar', '.tar.gz', '.tar.bz2', '.tgz', '.tbz')): - untar_file(filename, path) - self._unpacked_dir = path return self._unpacked_dir def _check_md5(self, filename): diff --git a/distutils2/index/xmlrpc.py b/distutils2/index/xmlrpc.py --- a/distutils2/index/xmlrpc.py +++ b/distutils2/index/xmlrpc.py @@ -127,10 +127,17 @@ return release def get_metadata(self, project_name, version): - """Retreive project metadatas. + """Retrieve project metadata. Return a ReleaseInfo object, with metadata informations filled in. """ + # to be case-insensitive, get the informations from the XMLRPC API + projects = [d['name'] for d in + self.proxy.search({'name': project_name}) + if d['name'].lower() == project_name] + if len(projects) > 0: + project_name = projects[0] + metadata = self.proxy.release_data(project_name, version) project = self._get_project(project_name) if version not in project.get_versions(): diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -1,5 +1,4 @@ from tempfile import mkdtemp -import logging import shutil import os import sys @@ -8,11 +7,15 @@ import itertools import tempfile +from distutils2 import logger from distutils2._backport.pkgutil import get_distributions +<<<<<<< local from distutils2._backport.pkgutil import get_distribution +from distutils2._backport.sysconfig import get_config_var from distutils2.depgraph import generate_graph from distutils2.index import wrapper from distutils2.index.errors import ProjectNotFound, ReleaseNotFound +from distutils2.version import get_version_predicate """Provides installations scripts. @@ -57,7 +60,63 @@ else: raise e os.rename(old, new) - yield(old, new) + yield (old, new) + + +def _run_d1_install(archive_dir, path): + # backward compat: using setuptools or plain-distutils + cmd = '%s setup.py install --root=%s --record=%s' + setup_py = os.path.join(archive_dir, 'setup.py') + if 'setuptools' in open(setup_py).read(): + cmd += ' --single-version-externally-managed' + + # how to place this file in the egg-info dir + # for non-distutils2 projects ? + record_file = os.path.join(archive_dir, 'RECORD') + os.system(cmd % (sys.executable, path, record_file)) + if not os.path.exists(record_file): + raise ValueError('Failed to install.') + return open(record_file).read().split('\n') + + +def _run_d2_install(archive_dir, path): + # using our own install command + raise NotImplementedError() + + +def _install_dist(dist, path): + """Install a distribution into a path. + + This: + + * unpack the distribution + * copy the files in "path" + * determine if the distribution is distutils2 or distutils1. + """ + where = dist.unpack(archive) + + # get into the dir + archive_dir = None + for item in os.listdir(where): + fullpath = os.path.join(where, item) + if os.path.isdir(fullpath): + archive_dir = fullpath + break + + if archive_dir is None: + raise ValueError('Cannot locate the unpacked archive') + + # install + old_dir = os.getcwd() + os.chdir(archive_dir) + try: + # distutils2 or distutils1 ? + if 'setup.py' in os.listdir(archive_dir): + return _run_d1_install(archive_dir, path) + else: + return _run_d2_install(archive_dir, path) + finally: + os.chdir(old_dir) def install_dists(dists, path=None): @@ -69,19 +128,23 @@ Return a list of installed files. :param dists: distributions to install - :param path: base path to install distribution on + :param path: base path to install distribution in """ if not path: path = mkdtemp() installed_dists, installed_files = [], [] for d in dists: + logger.info('Installing %s %s' % (d.name, d.version)) try: - installed_files.extend(d.install(path)) + installed_files.extend(_install_dist(d, path)) installed_dists.append(d) except Exception, e : + logger.info('Failed. %s' % str(e)) + + # reverting for d in installed_dists: - d.uninstall() + uninstall(d) raise e return installed_files @@ -127,16 +190,26 @@ try: if install: installed_files = install_dists(install, install_path) # install to tmp first - for files in temp_files.itervalues(): - for old, new in files: - os.remove(new) - except Exception,e: + except: # if an error occurs, put back the files in the good place. - for files in temp_files.itervalues(): + for files in temp_files.values(): for old, new in files: shutil.move(new, old) + # now re-raising + raise + + # we can remove them for good + for files in temp_files.values(): + for old, new in files: + os.remove(new) + + +def _get_setuptools_deps(release): + # NotImplementedError + pass + def get_infos(requirements, index=None, installed=None, prefer_final=True): """Return the informations on what's going to be installed and upgraded. @@ -158,44 +231,74 @@ Conflict contains all the conflicting distributions, if there is a conflict. """ + if not installed: + logger.info('Reading installed distributions') + installed = get_distributions(use_egg_info=True) + + infos = {'install': [], 'remove': [], 'conflict': []} + # Is a compatible version of the project is already installed ? + predicate = get_version_predicate(requirements) + found = False + installed = list(installed) + + # check that the project isnt already installed + for installed_project in installed: + # is it a compatible project ? + if predicate.name.lower() != installed_project.name.lower(): + continue + found = True + logger.info('Found %s %s' % (installed_project.name, + installed_project.version)) + + # if we already have something installed, check it matches the + # requirements + if predicate.match(installed_project.version): + return infos + break + + if not found: + logger.info('Project not installed.') if not index: index = wrapper.ClientWrapper() - if not installed: - installed = get_distributions(use_egg_info=True) - # Get all the releases that match the requirements try: releases = index.get_releases(requirements) except (ReleaseNotFound, ProjectNotFound), e: raise InstallationException('Release not found: "%s"' % requirements) - + # Pick up a release, and try to get the dependency tree release = releases.get_last(requirements, prefer_final=prefer_final) - # Iter since we found something without conflicts + if release is None: + logger.info('Could not find a matching project') + return infos + + # this works for Metadata 1.2 metadata = release.fetch_metadata() - # Get the distributions already_installed on the system - # and add the one we want to install + # for earlier, we need to build setuptools deps if any + if 'requires_dist' not in metadata: + deps = _get_setuptools_deps(release) + else: + deps = metadata['requires_dist'] distributions = itertools.chain(installed, [release]) depgraph = generate_graph(distributions) # Store all the already_installed packages in a list, in case of rollback. - infos = {'install': [], 'remove': [], 'conflict': []} - # Get what the missing deps are - for dists in depgraph.missing.itervalues(): - if dists: - logging.info("missing dependencies found, installing them") - # we have missing deps - for dist in dists: - _update_infos(infos, get_infos(dist, index, installed)) + dists = depgraph.missing[release] + if dists: + logger.info("missing dependencies found, retrieving metadata") + # we have missing deps + for dist in dists: + _update_infos(infos, get_infos(dist, index, installed)) # Fill in the infos existing = [d for d in installed if d.name == release.name] + if existing: infos['remove'].append(existing[0]) infos['conflict'].extend(depgraph.reverse_list[existing[0]]) @@ -207,7 +310,7 @@ """extends the lists contained in the `info` dict with those contained in the `new_info` one """ - for key, value in infos.iteritems(): + for key, value in infos.items(): if key in new_infos: infos[key].extend(new_infos[key]) @@ -253,5 +356,28 @@ attrs['requirements'] = sys.argv[1] get_infos(**attrs) + +def install(project): + logger.info('Getting information about "%s".' % project) + try: + info = get_infos(project) + except InstallationException: + logger.info('Cound not find "%s".' % project) + return + + if info['install'] == []: + logger.info('Nothing to install.') + return + + install_path = get_config_var('base') + try: + install_from_infos(info['install'], info['remove'], info['conflict'], + install_path=install_path) + + except InstallationConflict, e: + projects = ['%s %s' % (p.name, p.version) for p in e.args[0]] + logger.info('"%s" conflicts with "%s"' % (project, ','.join(projects))) + + if __name__ == '__main__': main() diff --git a/distutils2/run.py b/distutils2/run.py --- a/distutils2/run.py +++ b/distutils2/run.py @@ -1,7 +1,9 @@ import os import sys from optparse import OptionParser +import logging +from distutils2 import logger from distutils2.util import grok_environment_error from distutils2.errors import (DistutilsSetupError, DistutilsArgError, DistutilsError, CCompilerError) @@ -9,6 +11,7 @@ from distutils2 import __version__ from distutils2._backport.pkgutil import get_distributions, get_distribution from distutils2.depgraph import generate_graph +from distutils2.install import install # This is a barebones help message generated displayed when the user # runs the setup script with no arguments at all. More useful help @@ -115,8 +118,17 @@ return dist +def _set_logger(): + logger.setLevel(logging.INFO) + sth = logging.StreamHandler(sys.stderr) + sth.setLevel(logging.INFO) + logger.addHandler(sth) + logger.propagate = 0 + + def main(): """Main entry point for Distutils2""" + _set_logger() parser = OptionParser() parser.disable_interspersed_args() parser.usage = '%prog [options] cmd1 cmd2 ..' @@ -141,6 +153,14 @@ action="store_true", dest="fgraph", default=False, help="Display the full graph for installed distributions.") + parser.add_option("-i", "--install", + action="store", dest="install", + help="Install a project.") + + parser.add_option("-r", "--remove", + action="store", dest="remove", + help="Remove a project.") + options, args = parser.parse_args() if options.version: print('Distutils2 %s' % __version__) @@ -199,6 +219,10 @@ print(graph) sys.exit(0) + if options.install is not None: + install(options.install) + sys.exit(0) + if len(args) == 0: parser.print_help() sys.exit(0) diff --git a/distutils2/tests/pypi_server.py b/distutils2/tests/pypi_server.py --- a/distutils2/tests/pypi_server.py +++ b/distutils2/tests/pypi_server.py @@ -375,6 +375,7 @@ def __init__(self, dists=[]): self._dists = dists + self._search_result = [] def add_distributions(self, dists): for dist in dists: diff --git a/distutils2/tests/support.py b/distutils2/tests/support.py --- a/distutils2/tests/support.py +++ b/distutils2/tests/support.py @@ -17,10 +17,11 @@ super(SomeTestCase, self).setUp() ... # other setup code -Read each class' docstring to see its purpose and usage. +Also provided is a DummyCommand class, useful to mock commands in the +tests of another command that needs them, a create_distribution function +and a skip_unless_symlink decorator. -Also provided is a DummyCommand class, useful to mock commands in the -tests of another command that needs them (see docstring). +Each class or function has a docstring to explain its purpose and usage. """ import os @@ -35,7 +36,8 @@ from distutils2.tests import unittest __all__ = ['LoggingCatcher', 'WarningsCatcher', 'TempdirManager', - 'EnvironGuard', 'DummyCommand', 'unittest'] + 'EnvironGuard', 'DummyCommand', 'unittest', 'create_distribution', + 'skip_unless_symlink'] class LoggingCatcher(object): @@ -135,7 +137,7 @@ finally: f.close() - def create_dist(self, pkg_name='foo', **kw): + def create_dist(self, **kw): """Create a stub distribution object and files. This function creates a Distribution instance (use keyword arguments @@ -143,17 +145,19 @@ (currently an empty directory). It returns the path to the directory and the Distribution instance. - You can use TempdirManager.write_file to write any file in that + You can use self.write_file to write any file in that directory, e.g. setup scripts or Python modules. """ # Late import so that third parties can import support without # loading a ton of distutils2 modules in memory. from distutils2.dist import Distribution + if 'name' not in kw: + kw['name'] = 'foo' tmp_dir = self.mkdtemp() - pkg_dir = os.path.join(tmp_dir, pkg_name) - os.mkdir(pkg_dir) + project_dir = os.path.join(tmp_dir, kw['name']) + os.mkdir(project_dir) dist = Distribution(attrs=kw) - return pkg_dir, dist + return project_dir, dist def assertIsFile(self, *args): path = os.path.join(*args) @@ -226,3 +230,9 @@ d.parse_command_line() return d + +try: + from test.test_support import skip_unless_symlink +except ImportError: + skip_unless_symlink = unittest.skip( + 'requires test.test_support.skip_unless_symlink') diff --git a/distutils2/tests/test_command_install_dist.py b/distutils2/tests/test_command_install_dist.py --- a/distutils2/tests/test_command_install_dist.py +++ b/distutils2/tests/test_command_install_dist.py @@ -180,8 +180,8 @@ cmd.user = 'user' self.assertRaises(DistutilsOptionError, cmd.finalize_options) - def test_record(self): - + def test_old_record(self): + # test pre-PEP 376 --record option (outside dist-info dir) install_dir = self.mkdtemp() pkgdir, dist = self.create_dist() @@ -189,11 +189,11 @@ cmd = install_dist(dist) dist.command_obj['install_dist'] = cmd cmd.root = install_dir - cmd.record = os.path.join(pkgdir, 'RECORD') + cmd.record = os.path.join(pkgdir, 'filelist') cmd.ensure_finalized() cmd.run() - # let's check the RECORD file was created with four + # let's check the record file was created with four # lines, one for each .dist-info entry: METADATA, # INSTALLER, REQUSTED, RECORD f = open(cmd.record) diff --git a/distutils2/tests/test_install.py b/distutils2/tests/test_install.py --- a/distutils2/tests/test_install.py +++ b/distutils2/tests/test_install.py @@ -29,27 +29,16 @@ class ToInstallDist(object): """Distribution that will be installed""" - def __init__(self, raise_error=False, files=False): - self._raise_error = raise_error + def __init__(self, files=False): self._files = files - self.install_called = False - self.install_called_with = {} self.uninstall_called = False self._real_files = [] + self.name = "fake" + self.version = "fake" if files: for f in range(0,3): self._real_files.append(mkstemp()) - def install(self, *args): - self.install_called = True - self.install_called_with = args - if self._raise_error: - raise Exception('Oops !') - return ['/path/to/foo', '/path/to/bar'] - - def uninstall(self, **args): - self.uninstall_called = True - def get_installed_files(self, **args): if self._files: return [f[1] for f in self._real_files] @@ -58,7 +47,49 @@ return self.get_installed_files() +class MagicMock(object): + def __init__(self, return_value=None, raise_exception=False): + self.called = False + self._times_called = 0 + self._called_with = [] + self._return_value = return_value + self._raise = raise_exception + + def __call__(self, *args, **kwargs): + self.called = True + self._times_called = self._times_called + 1 + self._called_with.append((args, kwargs)) + iterable = hasattr(self._raise, '__iter__') + if self._raise: + if ((not iterable and self._raise) + or self._raise[self._times_called - 1]): + raise Exception + return self._return_value + + def called_with(self, *args, **kwargs): + return (args, kwargs) in self._called_with + + +def patch(parent, to_patch): + """monkey match a module""" + def wrapper(func): + print func + print dir(func) + old_func = getattr(parent, to_patch) + def wrapped(*args, **kwargs): + parent.__dict__[to_patch] = MagicMock() + try: + out = func(*args, **kwargs) + finally: + setattr(parent, to_patch, old_func) + return out + return wrapped + return wrapper + + def get_installed_dists(dists): + """Return a list of fake installed dists. + The list is name, version, deps""" objects = [] for (name, version, deps) in dists: objects.append(InstalledDist(name, version, deps)) @@ -69,6 +100,12 @@ def _get_client(self, server, *args, **kwargs): return Client(server.full_address, *args, **kwargs) + def _patch_run_install(self): + """Patch run install""" + + def _unpatch_run_install(self): + """Unpatch run install for d2 and d1""" + def _get_results(self, output): """return a list of results""" installed = [(o.name, '%s' % o.version) for o in output['install']] @@ -150,6 +187,8 @@ # Tests that conflicts are detected client = self._get_client(server) archive_path = '%s/distribution.tar.gz' % server.full_address + + # choxie depends on towel-stuff, which depends on bacon. server.xmlrpc.set_distributions([ {'name':'choxie', 'version': '2.0.0.9', @@ -164,7 +203,9 @@ 'requires_dist': [], 'url': archive_path}, ]) - already_installed = [('bacon', '0.1', []), + + # name, version, deps. + already_installed = [('bacon', '0.1', []), ('chicken', '1.1', ['bacon (0.1)'])] output = install.get_infos("choxie", index=client, installed= get_installed_dists(already_installed)) @@ -221,23 +262,39 @@ # if one of the distribution installation fails, call uninstall on all # installed distributions. - d1 = ToInstallDist() - d2 = ToInstallDist(raise_error=True) - self.assertRaises(Exception, install.install_dists, [d1, d2]) - for dist in (d1, d2): - self.assertTrue(dist.install_called) - self.assertTrue(d1.uninstall_called) - self.assertFalse(d2.uninstall_called) + old_install_dist = install._install_dist + old_uninstall = getattr(install, 'uninstall', None) + + install._install_dist = MagicMock(return_value=[], + raise_exception=(False, True)) + install.uninstall = MagicMock() + try: + d1 = ToInstallDist() + d2 = ToInstallDist() + path = self.mkdtemp() + self.assertRaises(Exception, install.install_dists, [d1, d2], path) + self.assertTrue(install._install_dist.called_with(d1, path)) + self.assertTrue(install.uninstall.called) + finally: + install._install_dist = old_install_dist + install.uninstall = old_uninstall + def test_install_dists_success(self): - # test that the install method is called on each of the distributions. - d1 = ToInstallDist() - d2 = ToInstallDist() - install.install_dists([d1, d2]) - for dist in (d1, d2): - self.assertTrue(dist.install_called) - self.assertFalse(d1.uninstall_called) - self.assertFalse(d2.uninstall_called) + old_install_dist = install._install_dist + install._install_dist = MagicMock(return_value=[]) + try: + # test that the install method is called on each of the distributions. + d1 = ToInstallDist() + d2 = ToInstallDist() + + # should call install + path = self.mkdtemp() + install.install_dists([d1, d2], path) + for dist in (d1, d2): + self.assertTrue(install._install_dist.called_with(dist, path)) + finally: + install._install_dist = old_install_dist def test_install_from_infos_conflict(self): # assert conflicts raise an exception @@ -262,29 +319,46 @@ install.install_dists = old_install_dists def test_install_from_infos_remove_rollback(self): - # assert that if an error occurs, the removed files are restored. - remove = [] - for i in range(0,2): - remove.append(ToInstallDist(files=True, raise_error=True)) - to_install = [ToInstallDist(raise_error=True), - ToInstallDist()] + old_install_dist = install._install_dist + old_uninstall = getattr(install, 'uninstall', None) - install.install_from_infos(remove=remove, install=to_install) - # assert that the files are in the same place - # assert that the files have been removed - for dist in remove: - for f in dist.get_installed_files(): - self.assertTrue(os.path.exists(f)) + install._install_dist = MagicMock(return_value=[], + raise_exception=(False, True)) + install.uninstall = MagicMock() + try: + # assert that if an error occurs, the removed files are restored. + remove = [] + for i in range(0,2): + remove.append(ToInstallDist(files=True)) + to_install = [ToInstallDist(), ToInstallDist()] + + self.assertRaises(Exception, install.install_from_infos, + remove=remove, install=to_install) + # assert that the files are in the same place + # assert that the files have been removed + for dist in remove: + for f in dist.get_installed_files(): + self.assertTrue(os.path.exists(f)) + finally: + install.install_dist = old_install_dist + install.uninstall = old_uninstall + def test_install_from_infos_install_succes(self): - # assert that the distribution can be installed - install_path = "my_install_path" - to_install = [ToInstallDist(), ToInstallDist()] + old_install_dist = install._install_dist + install._install_dist = MagicMock([]) + try: + # assert that the distribution can be installed + install_path = "my_install_path" + to_install = [ToInstallDist(), ToInstallDist()] - install.install_from_infos(install=to_install, - install_path=install_path) - for dist in to_install: - self.assertEqual(dist.install_called_with, (install_path,)) + install.install_from_infos(install=to_install, + install_path=install_path) + for dist in to_install: + install._install_dist.called_with(install_path) + finally: + install._install_dist = old_install_dist + def test_suite(): suite = unittest.TestSuite() diff --git a/distutils2/util.py b/distutils2/util.py --- a/distutils2/util.py +++ b/distutils2/util.py @@ -675,83 +675,6 @@ return base, ext -def unzip_file(filename, location, flatten=True): - """Unzip the file (zip file located at filename) to the destination - location""" - if not os.path.exists(location): - os.makedirs(location) - zipfp = open(filename, 'rb') - try: - zip = zipfile.ZipFile(zipfp) - leading = has_leading_dir(zip.namelist()) and flatten - for name in zip.namelist(): - data = zip.read(name) - fn = name - if leading: - fn = split_leading_dir(name)[1] - fn = os.path.join(location, fn) - dir = os.path.dirname(fn) - if not os.path.exists(dir): - os.makedirs(dir) - if fn.endswith('/') or fn.endswith('\\'): - # A directory - if not os.path.exists(fn): - os.makedirs(fn) - else: - fp = open(fn, 'wb') - try: - fp.write(data) - finally: - fp.close() - finally: - zipfp.close() - - -def untar_file(filename, location): - """Untar the file (tar file located at filename) to the destination - location - """ - if not os.path.exists(location): - os.makedirs(location) - if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): - mode = 'r:gz' - elif (filename.lower().endswith('.bz2') - or filename.lower().endswith('.tbz')): - mode = 'r:bz2' - elif filename.lower().endswith('.tar'): - mode = 'r' - else: - mode = 'r:*' - tar = tarfile.open(filename, mode) - try: - leading = has_leading_dir([member.name for member in tar.getmembers()]) - for member in tar.getmembers(): - fn = member.name - if leading: - fn = split_leading_dir(fn)[1] - path = os.path.join(location, fn) - if member.isdir(): - if not os.path.exists(path): - os.makedirs(path) - else: - try: - fp = tar.extractfile(member) - except (KeyError, AttributeError): - # Some corrupt tar files seem to produce this - # (specifically bad symlinks) - continue - if not os.path.exists(os.path.dirname(path)): - os.makedirs(os.path.dirname(path)) - destfp = open(path, 'wb') - try: - shutil.copyfileobj(fp, destfp) - finally: - destfp.close() - fp.close() - finally: - tar.close() - - def has_leading_dir(paths): """Returns true if all the paths have the same leading path name (i.e., everything is in one subdirectory in an archive)""" diff --git a/docs/source/library/distutils2.tests.pypi_server.rst b/docs/source/library/distutils2.tests.pypi_server.rst --- a/docs/source/library/distutils2.tests.pypi_server.rst +++ b/docs/source/library/distutils2.tests.pypi_server.rst @@ -77,6 +77,7 @@ @use_pypi_server() def test_somthing(self, server): # your tests goes here + ... The decorator will instantiate the server for you, and run and stop it just before and after your method call. You also can pass the server initializer, @@ -85,4 +86,4 @@ class SampleTestCase(TestCase): @use_pypi_server("test_case_name") def test_something(self, server): - # something + ... diff --git a/docs/source/library/pkgutil.rst b/docs/source/library/pkgutil.rst --- a/docs/source/library/pkgutil.rst +++ b/docs/source/library/pkgutil.rst @@ -4,77 +4,204 @@ .. module:: pkgutil :synopsis: Utilities to support packages. -.. TODO Follow the reST conventions used in the stdlib +This module provides utilities to manipulate packages: support for the +Importer protocol defined in :PEP:`302` and implementation of the API +described in :PEP:`376` to work with the database of installed Python +distributions. -This module provides functions to manipulate packages, as well as -the necessary functions to provide support for the "Importer Protocol" as -described in :PEP:`302` and for working with the database of installed Python -distributions which is specified in :PEP:`376`. In addition to the functions -required in :PEP:`376`, back support for older ``.egg`` and ``.egg-info`` -distributions is provided as well. These distributions are represented by the -class :class:`~distutils2._backport.pkgutil.EggInfoDistribution` and most -functions provide an extra argument ``use_egg_info`` which indicates if -they should consider these old styled distributions. This document details -first the functions and classes available and then presents several use cases. - +Import system utilities +----------------------- .. function:: extend_path(path, name) - Extend the search path for the modules which comprise a package. Intended use is - to place the following code in a package's :file:`__init__.py`:: + Extend the search path for the modules which comprise a package. Intended + use is to place the following code in a package's :file:`__init__.py`:: from pkgutil import extend_path __path__ = extend_path(__path__, __name__) - This will add to the package's ``__path__`` all subdirectories of directories on - ``sys.path`` named after the package. This is useful if one wants to distribute - different parts of a single logical package as multiple directories. + This will add to the package's ``__path__`` all subdirectories of directories + on :data:`sys.path` named after the package. This is useful if one wants to + distribute different parts of a single logical package as multiple + directories. - It also looks for :file:`\*.pkg` files beginning where ``*`` matches the *name* - argument. This feature is similar to :file:`\*.pth` files (see the :mod:`site` - module for more information), except that it doesn't special-case lines starting - with ``import``. A :file:`\*.pkg` file is trusted at face value: apart from - checking for duplicates, all entries found in a :file:`\*.pkg` file are added to - the path, regardless of whether they exist on the filesystem. (This is a - feature.) + It also looks for :file:`\*.pkg` files beginning where ``*`` matches the + *name* argument. This feature is similar to :file:`\*.pth` files (see the + :mod:`site` module for more information), except that it doesn't special-case + lines starting with ``import``. A :file:`\*.pkg` file is trusted at face + value: apart from checking for duplicates, all entries found in a + :file:`\*.pkg` file are added to the path, regardless of whether they exist + on the filesystem. (This is a feature.) If the input path is not a list (as is the case for frozen packages) it is returned unchanged. The input path is not modified; an extended copy is returned. Items are only appended to the copy at the end. - It is assumed that ``sys.path`` is a sequence. Items of ``sys.path`` that are - not strings referring to existing directories are ignored. Unicode items on - ``sys.path`` that cause errors when used as filenames may cause this function - to raise an exception (in line with :func:`os.path.isdir` behavior). + It is assumed that :data:`sys.path` is a sequence. Items of :data:`sys.path` + that are not strings referring to existing directories are ignored. Unicode + items on :data:`sys.path` that cause errors when used as filenames may cause + this function to raise an exception (in line with :func:`os.path.isdir` + behavior). + + +.. class:: ImpImporter(dirname=None) + + :pep:`302` Importer that wraps Python's "classic" import algorithm. + + If *dirname* is a string, a :pep:`302` importer is created that searches that + directory. If *dirname* is ``None``, a :pep:`302` importer is created that + searches the current :data:`sys.path`, plus any modules that are frozen or + built-in. + + Note that :class:`ImpImporter` does not currently support being used by + placement on :data:`sys.meta_path`. + + +.. class:: ImpLoader(fullname, file, filename, etc) + + :pep:`302` Loader that wraps Python's "classic" import algorithm. + + +.. function:: find_loader(fullname) + + Find a :pep:`302` "loader" object for *fullname*. + + If *fullname* contains dots, path must be the containing package's + ``__path__``. Returns ``None`` if the module cannot be found or imported. + This function uses :func:`iter_importers`, and is thus subject to the same + limitations regarding platform-specific special import locations such as the + Windows registry. + + +.. function:: get_importer(path_item) + + Retrieve a :pep:`302` importer for the given *path_item*. + + The returned importer is cached in :data:`sys.path_importer_cache` if it was + newly created by a path hook. + + If there is no importer, a wrapper around the basic import machinery is + returned. This wrapper is never inserted into the importer cache (None is + inserted instead). + + The cache (or part of it) can be cleared manually if a rescan of + :data:`sys.path_hooks` is necessary. + + +.. function:: get_loader(module_or_name) + + Get a :pep:`302` "loader" object for *module_or_name*. + + If the module or package is accessible via the normal import mechanism, a + wrapper around the relevant part of that machinery is returned. Returns + ``None`` if the module cannot be found or imported. If the named module is + not already imported, its containing package (if any) is imported, in order + to establish the package ``__path__``. + + This function uses :func:`iter_importers`, and is thus subject to the same + limitations regarding platform-specific special import locations such as the + Windows registry. + + +.. function:: iter_importers(fullname='') + + Yield :pep:`302` importers for the given module name. + + If fullname contains a '.', the importers will be for the package containing + fullname, otherwise they will be importers for :data:`sys.meta_path`, + :data:`sys.path`, and Python's "classic" import machinery, in that order. If + the named module is in a package, that package is imported as a side effect + of invoking this function. + + Non-:pep:`302` mechanisms (e.g. the Windows registry) used by the standard + import machinery to find files in alternative locations are partially + supported, but are searched *after* :data:`sys.path`. Normally, these + locations are searched *before* :data:`sys.path`, preventing :data:`sys.path` + entries from shadowing them. + + For this to cause a visible difference in behaviour, there must be a module + or package name that is accessible via both :data:`sys.path` and one of the + non-:pep:`302` file system mechanisms. In this case, the emulation will find + the former version, while the builtin import mechanism will find the latter. + + Items of the following types can be affected by this discrepancy: + ``imp.C_EXTENSION``, ``imp.PY_SOURCE``, ``imp.PY_COMPILED``, + ``imp.PKG_DIRECTORY``. + + +.. function:: iter_modules(path=None, prefix='') + + Yields ``(module_loader, name, ispkg)`` for all submodules on *path*, or, if + path is ``None``, all top-level modules on :data:`sys.path`. + + *path* should be either ``None`` or a list of paths to look for modules in. + + *prefix* is a string to output on the front of every module name on output. + + +.. function:: walk_packages(path=None, prefix='', onerror=None) + + Yields ``(module_loader, name, ispkg)`` for all modules recursively on + *path*, or, if path is ``None``, all accessible modules. + + *path* should be either ``None`` or a list of paths to look for modules in. + + *prefix* is a string to output on the front of every module name on output. + + Note that this function must import all *packages* (*not* all modules!) on + the given *path*, in order to access the ``__path__`` attribute to find + submodules. + + *onerror* is a function which gets called with one argument (the name of the + package which was being imported) if any exception occurs while trying to + import a package. If no *onerror* function is supplied, :exc:`ImportError`\s + are caught and ignored, while all other exceptions are propagated, + terminating the search. + + Examples:: + + # list all modules python can access + walk_packages() + + # list all submodules of ctypes + walk_packages(ctypes.__path__, ctypes.__name__ + '.') + .. function:: get_data(package, resource) Get a resource from a package. - This is a wrapper for the :pep:`302` loader :func:`get_data` API. The package - argument should be the name of a package, in standard module format - (foo.bar). The resource argument should be in the form of a relative - filename, using ``/`` as the path separator. The parent directory name + This is a wrapper for the :pep:`302` loader :func:`get_data` API. The + *package* argument should be the name of a package, in standard module format + (``foo.bar``). The *resource* argument should be in the form of a relative + filename, using ``/`` as the path separator. The parent directory name ``..`` is not allowed, and nor is a rooted name (starting with a ``/``). - The function returns a binary string that is the contents of the - specified resource. + The function returns a binary string that is the contents of the specified + resource. For packages located in the filesystem, which have already been imported, this is the rough equivalent of:: - d = os.path.dirname(sys.modules[package].__file__) - data = open(os.path.join(d, resource), 'rb').read() + d = os.path.dirname(sys.modules[package].__file__) + data = open(os.path.join(d, resource), 'rb').read() If the package cannot be located or loaded, or it uses a :pep:`302` loader - which does not support :func:`get_data`, then None is returned. + which does not support :func:`get_data`, then ``None`` is returned. -API Reference -============= +Installed distributions database +-------------------------------- -.. automodule:: distutils2._backport.pkgutil - :members: +Installed Python distributions are represented by instances of +:class:`~distutils2._backport.pkgutil.Distribution`, or its subclass +:class:`~distutils2._backport.pkgutil.EggInfoDistribution` for legacy ``.egg`` +and ``.egg-info`` formats). Most functions also provide an extra argument +``use_egg_info`` to take legacy distributions into account. + +.. TODO write docs here, don't rely on automodule + classes: Distribution and descendents + functions: provides, obsoletes, replaces, etc. Caching +++++++ @@ -86,11 +213,10 @@ :func:`~distutils2._backport.pkgutil.clear_cache`. +Examples +-------- -Example Usage -============= - -Print All Information About a Distribution +Print all information about a distribution ++++++++++++++++++++++++++++++++++++++++++ Given a path to a ``.dist-info`` distribution, we shall print out all @@ -182,7 +308,7 @@ ===== * It was installed as a dependency -Find Out Obsoleted Distributions +Find out obsoleted distributions ++++++++++++++++++++++++++++++++ Now, we take tackle a different problem, we are interested in finding out -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: Building extensions from the setup.cfg Message-ID: tarek.ziade pushed f8657bc04959 to distutils2: http://hg.python.org/distutils2/rev/f8657bc04959 changeset: 953:f8657bc04959 parent: 927:11f13263c188 user: Andre Espaze date: Sat Jan 29 17:08:28 2011 +0100 summary: Building extensions from the setup.cfg This changeset adds the setup.cfg syntax for building binary extensions. Note the extension key defined by the section name is not yet used for managing build dependencies. files: distutils2/config.py distutils2/tests/test_config.py diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -3,14 +3,32 @@ Know how to read all config files Distutils2 uses. """ import os +import re import sys from ConfigParser import RawConfigParser from distutils2 import logger from distutils2.util import check_environ, resolve_name +from distutils2.compiler.extension import Extension from distutils2.compiler import set_compiler from distutils2.command import set_command + +def pop_values(values_dct, key): + """Remove values from the dictionary and convert them as a list""" + vals_str = values_dct.pop(key, None) + if not vals_str: + return + # Get bash options like `gcc -print-file-name=libgcc.a` + vals = re.search('(`.*?`)', vals_str) or [] + if vals: + vals = list(vals.groups()) + vals_str = re.sub('`.*?`', '', vals_str) + vals.extend(vals_str.split()) + if vals: + return vals + + class Config(object): """Reads configuration files and work with the Distribution instance """ @@ -181,6 +199,34 @@ # manifest template self.dist.extra_files = files.get('extra_files', []) + ext_modules = self.dist.ext_modules + for section_key in content: + labels = section_key.split('=') + if (len(labels) == 2) and (labels[0] == 'extension'): + # labels[1] not used from now but should be implemented + # for extension build dependency + values_dct = content[section_key] + ext_modules.append(Extension( + values_dct.pop('name'), + pop_values(values_dct, 'sources'), + pop_values(values_dct, 'include_dirs'), + pop_values(values_dct, 'define_macros'), + pop_values(values_dct, 'undef_macros'), + pop_values(values_dct, 'library_dirs'), + pop_values(values_dct, 'libraries'), + pop_values(values_dct, 'runtime_library_dirs'), + pop_values(values_dct, 'extra_objects'), + pop_values(values_dct, 'extra_compile_args'), + pop_values(values_dct, 'extra_link_args'), + pop_values(values_dct, 'export_symbols'), + pop_values(values_dct, 'swig_opts'), + pop_values(values_dct, 'depends'), + values_dct.pop('language', None), + values_dct.pop('optional', None), + **values_dct + )) + + def parse_config_files(self, filenames=None): if filenames is None: filenames = self.find_config_files() diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -93,6 +93,30 @@ sub_commands = foo """ +# Can not be merged with SETUP_CFG else install_dist +# command will fail when trying to compile C sources +EXT_SETUP_CFG = """ +[files] +packages = one + two + +[extension=speed_coconuts] +name = one.speed_coconuts +sources = c_src/speed_coconuts.c +extra_link_args = `gcc -print-file-name=libgcc.a` -shared +define_macros = HAVE_CAIRO HAVE_GTK2 + +[extension=fast_taunt] +name = three.fast_taunt +sources = cxx_src/utils_taunt.cxx + cxx_src/python_module.cxx +include_dirs = /usr/include/gecode + /usr/include/blitz +extra_compile_args = -fPIC -O2 +language = cxx + +""" + class DCompiler(object): name = 'd' @@ -134,7 +158,14 @@ super(ConfigTestCase, self).setUp() self.addCleanup(setattr, sys, 'stdout', sys.stdout) self.addCleanup(setattr, sys, 'stderr', sys.stderr) + sys.stdout = sys.stderr = StringIO() + self.addCleanup(os.chdir, os.getcwd()) + tempdir = self.mkdtemp() + os.chdir(tempdir) + self.tempdir = tempdir + + self.addCleanup(setattr, sys, 'argv', sys.argv) def write_setup(self, kwargs=None): opts = {'description-file': 'README', 'extra-files':''} @@ -156,8 +187,6 @@ return dist def test_config(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) self.write_setup() self.write_file('README', 'yeah') @@ -232,9 +261,6 @@ def test_multiple_description_file(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) - self.write_setup({'description-file': 'README CHANGES'}) self.write_file('README', 'yeah') self.write_file('CHANGES', 'changelog2') @@ -242,9 +268,6 @@ self.assertEqual(dist.metadata.requires_files, ['README', 'CHANGES']) def test_multiline_description_file(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) - self.write_setup({'description-file': 'README\n CHANGES'}) self.write_file('README', 'yeah') self.write_file('CHANGES', 'changelog') @@ -252,9 +275,28 @@ self.assertEqual(dist.metadata['description'], 'yeah\nchangelog') self.assertEqual(dist.metadata.requires_files, ['README', 'CHANGES']) + def test_parse_extensions_in_config(self): + self.write_file('setup.cfg', EXT_SETUP_CFG) + dist = self.run_setup('--version') + + ext_modules = dict((mod.name, mod) for mod in dist.ext_modules) + self.assertEqual(len(ext_modules), 2) + ext = ext_modules.get('one.speed_coconuts') + self.assertEqual(ext.sources, ['c_src/speed_coconuts.c']) + self.assertEqual(ext.define_macros, ['HAVE_CAIRO', 'HAVE_GTK2']) + self.assertEqual(ext.extra_link_args, + ['`gcc -print-file-name=libgcc.a`', '-shared']) + + ext = ext_modules.get('three.fast_taunt') + self.assertEqual(ext.sources, + ['cxx_src/utils_taunt.cxx', 'cxx_src/python_module.cxx']) + self.assertEqual(ext.include_dirs, + ['/usr/include/gecode', '/usr/include/blitz']) + self.assertEqual(ext.extra_compile_args, ['-fPIC', '-O2']) + self.assertEqual(ext.language, 'cxx') + + def test_metadata_requires_description_files_missing(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) self.write_setup({'description-file': 'README\n README2'}) self.write_file('README', 'yeah') self.write_file('README2', 'yeah') @@ -278,8 +320,6 @@ self.assertRaises(DistutilsFileError, cmd.make_distribution) def test_metadata_requires_description_files(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) self.write_setup({'description-file': 'README\n README2', 'extra-files':'\n README2'}) self.write_file('README', 'yeah') @@ -315,8 +355,6 @@ self.assertIn('README\nREADME2\n', open('MANIFEST').read()) def test_sub_commands(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) self.write_setup() self.write_file('README', 'yeah') self.write_file('haven.py', '#') -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: merge with Andr? Message-ID: tarek.ziade pushed 6c98c1c2bd67 to distutils2: http://hg.python.org/distutils2/rev/6c98c1c2bd67 changeset: 954:6c98c1c2bd67 parent: 952:1e23203b0675 parent: 953:f8657bc04959 user: Alexis Metaireau date: Sat Jan 29 18:41:32 2011 +0100 summary: merge with Andr? files: distutils2/config.py diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -3,15 +3,32 @@ Know how to read all config files Distutils2 uses. """ import os +import re import sys from ConfigParser import RawConfigParser from distutils2 import logger from distutils2.errors import DistutilsOptionError +from distutils2.compiler.extension import Extension from distutils2.util import check_environ, resolve_name, strtobool from distutils2.compiler import set_compiler from distutils2.command import set_command +def pop_values(values_dct, key): + """Remove values from the dictionary and convert them as a list""" + vals_str = values_dct.pop(key, None) + if not vals_str: + return + # Get bash options like `gcc -print-file-name=libgcc.a` + vals = re.search('(`.*?`)', vals_str) or [] + if vals: + vals = list(vals.groups()) + vals_str = re.sub('`.*?`', '', vals_str) + vals.extend(vals_str.split()) + if vals: + return vals + + class Config(object): """Reads configuration files and work with the Distribution instance """ @@ -182,6 +199,34 @@ # manifest template self.dist.extra_files = files.get('extra_files', []) + ext_modules = self.dist.ext_modules + for section_key in content: + labels = section_key.split('=') + if (len(labels) == 2) and (labels[0] == 'extension'): + # labels[1] not used from now but should be implemented + # for extension build dependency + values_dct = content[section_key] + ext_modules.append(Extension( + values_dct.pop('name'), + pop_values(values_dct, 'sources'), + pop_values(values_dct, 'include_dirs'), + pop_values(values_dct, 'define_macros'), + pop_values(values_dct, 'undef_macros'), + pop_values(values_dct, 'library_dirs'), + pop_values(values_dct, 'libraries'), + pop_values(values_dct, 'runtime_library_dirs'), + pop_values(values_dct, 'extra_objects'), + pop_values(values_dct, 'extra_compile_args'), + pop_values(values_dct, 'extra_link_args'), + pop_values(values_dct, 'export_symbols'), + pop_values(values_dct, 'swig_opts'), + pop_values(values_dct, 'depends'), + values_dct.pop('language', None), + values_dct.pop('optional', None), + **values_dct + )) + + def parse_config_files(self, filenames=None): if filenames is None: filenames = self.find_config_files() diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -93,6 +93,30 @@ sub_commands = foo """ +# Can not be merged with SETUP_CFG else install_dist +# command will fail when trying to compile C sources +EXT_SETUP_CFG = """ +[files] +packages = one + two + +[extension=speed_coconuts] +name = one.speed_coconuts +sources = c_src/speed_coconuts.c +extra_link_args = `gcc -print-file-name=libgcc.a` -shared +define_macros = HAVE_CAIRO HAVE_GTK2 + +[extension=fast_taunt] +name = three.fast_taunt +sources = cxx_src/utils_taunt.cxx + cxx_src/python_module.cxx +include_dirs = /usr/include/gecode + /usr/include/blitz +extra_compile_args = -fPIC -O2 +language = cxx + +""" + class DCompiler(object): name = 'd' @@ -134,7 +158,14 @@ super(ConfigTestCase, self).setUp() self.addCleanup(setattr, sys, 'stdout', sys.stdout) self.addCleanup(setattr, sys, 'stderr', sys.stderr) + sys.stdout = sys.stderr = StringIO() + self.addCleanup(os.chdir, os.getcwd()) + tempdir = self.mkdtemp() + os.chdir(tempdir) + self.tempdir = tempdir + + self.addCleanup(setattr, sys, 'argv', sys.argv) def write_setup(self, kwargs=None): opts = {'description-file': 'README', 'extra-files':''} @@ -156,8 +187,6 @@ return dist def test_config(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) self.write_setup() self.write_file('README', 'yeah') @@ -232,9 +261,6 @@ def test_multiple_description_file(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) - self.write_setup({'description-file': 'README CHANGES'}) self.write_file('README', 'yeah') self.write_file('CHANGES', 'changelog2') @@ -242,9 +268,6 @@ self.assertEqual(dist.metadata.requires_files, ['README', 'CHANGES']) def test_multiline_description_file(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) - self.write_setup({'description-file': 'README\n CHANGES'}) self.write_file('README', 'yeah') self.write_file('CHANGES', 'changelog') @@ -252,9 +275,28 @@ self.assertEqual(dist.metadata['description'], 'yeah\nchangelog') self.assertEqual(dist.metadata.requires_files, ['README', 'CHANGES']) + def test_parse_extensions_in_config(self): + self.write_file('setup.cfg', EXT_SETUP_CFG) + dist = self.run_setup('--version') + + ext_modules = dict((mod.name, mod) for mod in dist.ext_modules) + self.assertEqual(len(ext_modules), 2) + ext = ext_modules.get('one.speed_coconuts') + self.assertEqual(ext.sources, ['c_src/speed_coconuts.c']) + self.assertEqual(ext.define_macros, ['HAVE_CAIRO', 'HAVE_GTK2']) + self.assertEqual(ext.extra_link_args, + ['`gcc -print-file-name=libgcc.a`', '-shared']) + + ext = ext_modules.get('three.fast_taunt') + self.assertEqual(ext.sources, + ['cxx_src/utils_taunt.cxx', 'cxx_src/python_module.cxx']) + self.assertEqual(ext.include_dirs, + ['/usr/include/gecode', '/usr/include/blitz']) + self.assertEqual(ext.extra_compile_args, ['-fPIC', '-O2']) + self.assertEqual(ext.language, 'cxx') + + def test_metadata_requires_description_files_missing(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) self.write_setup({'description-file': 'README\n README2'}) self.write_file('README', 'yeah') self.write_file('README2', 'yeah') @@ -278,8 +320,6 @@ self.assertRaises(DistutilsFileError, cmd.make_distribution) def test_metadata_requires_description_files(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) self.write_setup({'description-file': 'README\n README2', 'extra-files':'\n README2'}) self.write_file('README', 'yeah') @@ -315,8 +355,6 @@ self.assertIn('README\nREADME2\n', open('MANIFEST').read()) def test_sub_commands(self): - tempdir = self.mkdtemp() - os.chdir(tempdir) self.write_setup() self.write_file('README', 'yeah') self.write_file('haven.py', '#') -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: make a private function private :) Message-ID: tarek.ziade pushed 4b89c997484d to distutils2: http://hg.python.org/distutils2/rev/4b89c997484d changeset: 955:4b89c997484d user: Alexis Metaireau date: Sat Jan 29 18:42:22 2011 +0100 summary: make a private function private :) files: distutils2/config.py diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -14,7 +14,8 @@ from distutils2.compiler import set_compiler from distutils2.command import set_command -def pop_values(values_dct, key): + +def _pop_values(values_dct, key): """Remove values from the dictionary and convert them as a list""" vals_str = values_dct.pop(key, None) if not vals_str: @@ -208,19 +209,19 @@ values_dct = content[section_key] ext_modules.append(Extension( values_dct.pop('name'), - pop_values(values_dct, 'sources'), - pop_values(values_dct, 'include_dirs'), - pop_values(values_dct, 'define_macros'), - pop_values(values_dct, 'undef_macros'), - pop_values(values_dct, 'library_dirs'), - pop_values(values_dct, 'libraries'), - pop_values(values_dct, 'runtime_library_dirs'), - pop_values(values_dct, 'extra_objects'), - pop_values(values_dct, 'extra_compile_args'), - pop_values(values_dct, 'extra_link_args'), - pop_values(values_dct, 'export_symbols'), - pop_values(values_dct, 'swig_opts'), - pop_values(values_dct, 'depends'), + _pop_values(values_dct, 'sources'), + _pop_values(values_dct, 'include_dirs'), + _pop_values(values_dct, 'define_macros'), + _pop_values(values_dct, 'undef_macros'), + _pop_values(values_dct, 'library_dirs'), + _pop_values(values_dct, 'libraries'), + _pop_values(values_dct, 'runtime_library_dirs'), + _pop_values(values_dct, 'extra_objects'), + _pop_values(values_dct, 'extra_compile_args'), + _pop_values(values_dct, 'extra_link_args'), + _pop_values(values_dct, 'export_symbols'), + _pop_values(values_dct, 'swig_opts'), + _pop_values(values_dct, 'depends'), values_dct.pop('language', None), values_dct.pop('optional', None), **values_dct -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: update setupcfg documentation page with some notes and new examples Message-ID: tarek.ziade pushed 7dc4323bb965 to distutils2: http://hg.python.org/distutils2/rev/7dc4323bb965 changeset: 956:7dc4323bb965 parent: 919:34210b95cffd user: Julien Jehannet date: Sat Jan 29 16:19:39 2011 +0100 summary: update setupcfg documentation page with some notes and new examples - replace underscore by dash in fields - use PEP rst directive - new section information Notes: - field names are case-insensitive - some metadata fields are automatically generated New examples: - setup_hook - use-2to3 files: docs/source/setupcfg.rst diff --git a/docs/source/setupcfg.rst b/docs/source/setupcfg.rst --- a/docs/source/setupcfg.rst +++ b/docs/source/setupcfg.rst @@ -10,21 +10,32 @@ - Options that are marked *\*multi* can have multiple values, one value per line. - Options that are marked *\*optional* can be omited. -- Options that are marked *\*environ* can use environement markes, as described - in PEP 345. +- Options that are marked *\*environ* can use environment markers, as described + in :PEP:`345`. + The sections are: -- global -- metadata -- files -- command sections +global + Global options for Distutils2. + +metadata + The metadata section contains the metadata for the project as described in + :PEP:`345`. + +files + Declaration of package files included in the project. + +`command` sections + Redefinition of user options for Distutils2 commands. global ====== -Contains global options for Distutils2. This section is shared with Distutils1. +Contains global options for Distutils2. This section is shared with Distutils1 +(legacy version distributed in python 2.X standard library). + - **commands**: Defined Distutils2 command. A command is defined by its fully qualified name. @@ -44,7 +55,7 @@ [global] compiler = - package.compilers.CustomCCompiler + package.compiler.CustomCCompiler *\*optional* *\*multi* @@ -52,21 +63,28 @@ :file:`setup.cfg` file is read. The callable receives the configuration in form of a mapping and can make some changes to it. *\*optional* + Example:: + + [global] + setup_hook = distutils2.tests.test_config.hook + metadata ======== The metadata section contains the metadata for the project as described in -PEP 345. +:PEP:`345`. +.. Note:: + Field names are case-insensitive. Fields: - **name**: Name of the project. -- **version**: Version of the project. Must comply with PEP 386. +- **version**: Version of the project. Must comply with :PEP:`386`. - **platform**: Platform specification describing an operating system supported by the distribution which is not listed in the "Operating System" Trove - classifiers. *\*multi* *\*optional* + classifiers (:PEP:`301`). *\*multi* *\*optional* - **supported-platform**: Binary distributions containing a PKG-INFO file will use the Supported-Platform field in their metadata to specify the OS and CPU for which the binary distribution was compiled. The semantics of @@ -113,14 +131,18 @@ name = pypi2rpm version = 0.1 author = Tarek Ziade - author_email = tarek at ziade.org + author-email = tarek at ziade.org summary = Script that transforms a sdist archive into a rpm archive description-file = README - home_page = http://bitbucket.org/tarek/pypi2rpm + home-page = http://bitbucket.org/tarek/pypi2rpm + project-url: RSS feed, https://bitbucket.org/tarek/pypi2rpm/rss classifier = Development Status :: 3 - Alpha License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1) +.. Note:: + Some metadata fields seen in :PEP:`345` are automatically generated + as the Metadata-Version value for instance. files @@ -150,15 +172,20 @@ setup.py -command sections -================ +`command` sections +================== -Each command can have its options described in :file:`setup.cfg` - +Each Distutils2 command can have its own user options defined in :file:`setup.cfg` Example:: [sdist] - manifest_makers = package.module.Maker + manifest-builders = package.module.Maker +To override the building class in order to compile your python2 files to python3:: + + [build_py] + use-2to3 = True + + -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:43:58 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:43:58 +0100 Subject: [Python-checkins] distutils2: merged doc for juj Message-ID: tarek.ziade pushed 8106777a8748 to distutils2: http://hg.python.org/distutils2/rev/8106777a8748 changeset: 957:8106777a8748 tag: tip parent: 955:4b89c997484d parent: 956:7dc4323bb965 user: Tarek Ziade date: Sun Jan 30 10:42:44 2011 +0100 summary: merged doc for juj files: diff --git a/docs/source/setupcfg.rst b/docs/source/setupcfg.rst --- a/docs/source/setupcfg.rst +++ b/docs/source/setupcfg.rst @@ -10,21 +10,32 @@ - Options that are marked *\*multi* can have multiple values, one value per line. - Options that are marked *\*optional* can be omited. -- Options that are marked *\*environ* can use environement markes, as described - in PEP 345. +- Options that are marked *\*environ* can use environment markers, as described + in :PEP:`345`. + The sections are: -- global -- metadata -- files -- command sections +global + Global options for Distutils2. + +metadata + The metadata section contains the metadata for the project as described in + :PEP:`345`. + +files + Declaration of package files included in the project. + +`command` sections + Redefinition of user options for Distutils2 commands. global ====== -Contains global options for Distutils2. This section is shared with Distutils1. +Contains global options for Distutils2. This section is shared with Distutils1 +(legacy version distributed in python 2.X standard library). + - **commands**: Defined Distutils2 command. A command is defined by its fully qualified name. @@ -44,7 +55,7 @@ [global] compiler = - package.compilers.CustomCCompiler + package.compiler.CustomCCompiler *\*optional* *\*multi* @@ -52,21 +63,28 @@ :file:`setup.cfg` file is read. The callable receives the configuration in form of a mapping and can make some changes to it. *\*optional* + Example:: + + [global] + setup_hook = distutils2.tests.test_config.hook + metadata ======== The metadata section contains the metadata for the project as described in -PEP 345. +:PEP:`345`. +.. Note:: + Field names are case-insensitive. Fields: - **name**: Name of the project. -- **version**: Version of the project. Must comply with PEP 386. +- **version**: Version of the project. Must comply with :PEP:`386`. - **platform**: Platform specification describing an operating system supported by the distribution which is not listed in the "Operating System" Trove - classifiers. *\*multi* *\*optional* + classifiers (:PEP:`301`). *\*multi* *\*optional* - **supported-platform**: Binary distributions containing a PKG-INFO file will use the Supported-Platform field in their metadata to specify the OS and CPU for which the binary distribution was compiled. The semantics of @@ -113,14 +131,18 @@ name = pypi2rpm version = 0.1 author = Tarek Ziade - author_email = tarek at ziade.org + author-email = tarek at ziade.org summary = Script that transforms a sdist archive into a rpm archive description-file = README - home_page = http://bitbucket.org/tarek/pypi2rpm + home-page = http://bitbucket.org/tarek/pypi2rpm + project-url: RSS feed, https://bitbucket.org/tarek/pypi2rpm/rss classifier = Development Status :: 3 - Alpha License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1) +.. Note:: + Some metadata fields seen in :PEP:`345` are automatically generated + as the Metadata-Version value for instance. files @@ -150,15 +172,20 @@ setup.py -command sections -================ +`command` sections +================== -Each command can have its options described in :file:`setup.cfg` - +Each Distutils2 command can have its own user options defined in :file:`setup.cfg` Example:: [sdist] - manifest_makers = package.module.Maker + manifest-builders = package.module.Maker +To override the building class in order to compile your python2 files to python3:: + + [build_py] + use-2to3 = True + + -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:45:09 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:45:09 +0100 Subject: [Python-checkins] distutils2: corrected a leaked temp dir problem Message-ID: tarek.ziade pushed c732ac2c3105 to distutils2: http://hg.python.org/distutils2/rev/c732ac2c3105 changeset: 958:c732ac2c3105 parent: 952:1e23203b0675 user: Yannick Gingras date: Sat Jan 29 16:18:17 2011 -0500 summary: corrected a leaked temp dir problem files: distutils2/install.py diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -317,13 +317,13 @@ def remove(project_name, paths=sys.path): """Removes a single project from the installation""" - tmp = tempfile.mkdtemp(prefix=project_name+'-uninstall') dist = get_distribution(project_name, paths=paths) if dist is None: raise DistutilsError('Distribution %s not found' % project_name) files = dist.get_installed_files(local=True) rmdirs = [] rmfiles = [] + tmp = tempfile.mkdtemp(prefix=project_name+'-uninstall') try: for file, md5, size in files: @@ -339,8 +339,8 @@ rmfiles.append(file) if dirname not in rmdirs: rmdirs.append(dirname) - except OSError: - os.rmdir(tmp) + finally: + shutil.rmtree(tmp) for file in rmfiles: os.remove(file) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:45:09 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:45:09 +0100 Subject: [Python-checkins] distutils2: fixed another leaking tempdir Message-ID: tarek.ziade pushed 486bb332c45f to distutils2: http://hg.python.org/distutils2/rev/486bb332c45f changeset: 959:486bb332c45f user: Yannick Gingras date: Sat Jan 29 18:10:22 2011 -0500 summary: fixed another leaking tempdir files: distutils2/install.py diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -130,8 +130,10 @@ :param dists: distributions to install :param path: base path to install distribution in """ + path_is_tmp = False if not path: path = mkdtemp() + path_is_tmp = True installed_dists, installed_files = [], [] for d in dists: @@ -146,6 +148,10 @@ for d in installed_dists: uninstall(d) raise e + finally: + if path_is_tmp: + shutil.rmtree(path) + return installed_files -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:45:09 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:45:09 +0100 Subject: [Python-checkins] distutils2: Automated merge with ssh://bitbucket.org/tarek/distutils2 Message-ID: tarek.ziade pushed d031f7444d8b to distutils2: http://hg.python.org/distutils2/rev/d031f7444d8b changeset: 960:d031f7444d8b parent: 955:4b89c997484d parent: 959:486bb332c45f user: Yannick Gingras date: Sat Jan 29 18:32:36 2011 -0500 summary: Automated merge with ssh://bitbucket.org/tarek/distutils2 files: diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -130,8 +130,10 @@ :param dists: distributions to install :param path: base path to install distribution in """ + path_is_tmp = False if not path: path = mkdtemp() + path_is_tmp = True installed_dists, installed_files = [], [] for d in dists: @@ -146,6 +148,10 @@ for d in installed_dists: uninstall(d) raise e + finally: + if path_is_tmp: + shutil.rmtree(path) + return installed_files @@ -317,13 +323,13 @@ def remove(project_name, paths=sys.path): """Removes a single project from the installation""" - tmp = tempfile.mkdtemp(prefix=project_name+'-uninstall') dist = get_distribution(project_name, paths=paths) if dist is None: raise DistutilsError('Distribution %s not found' % project_name) files = dist.get_installed_files(local=True) rmdirs = [] rmfiles = [] + tmp = tempfile.mkdtemp(prefix=project_name+'-uninstall') try: for file, md5, size in files: @@ -339,8 +345,8 @@ rmfiles.append(file) if dirname not in rmdirs: rmdirs.append(dirname) - except OSError: - os.rmdir(tmp) + finally: + shutil.rmtree(tmp) for file in rmfiles: os.remove(file) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:45:09 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:45:09 +0100 Subject: [Python-checkins] distutils2: removed the installation to an empty path from the API and fixed a leaking Message-ID: tarek.ziade pushed 4070dc9752ef to distutils2: http://hg.python.org/distutils2/rev/4070dc9752ef changeset: 961:4070dc9752ef user: Yannick Gingras date: Sat Jan 29 20:21:12 2011 -0500 summary: removed the installation to an empty path from the API and fixed a leaking tempdir in the process files: distutils2/install.py distutils2/tests/test_install.py diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -35,7 +35,7 @@ """Raised when a conflict is detected""" -def move_files(files, destination=None): +def move_files(files, destination): """Move the list of files in the destination folder, keeping the same structure. @@ -43,13 +43,11 @@ :param files: a list of files to move. :param destination: the destination directory to put on the files. - if not defined, create a new one, using mkdtemp """ - if not destination: - destination = mkdtemp() - for old in files: - new = '%s%s' % (destination, old) + # not using os.path.join() because basename() might not be + # unique in destination + new = "%s%s" % (destination, old) # try to make the paths. try: @@ -119,7 +117,7 @@ os.chdir(old_dir) -def install_dists(dists, path=None): +def install_dists(dists, path): """Install all distributions provided in dists, with the given prefix. If an error occurs while installing one of the distributions, uninstall all @@ -130,10 +128,6 @@ :param dists: distributions to install :param path: base path to install distribution in """ - path_is_tmp = False - if not path: - path = mkdtemp() - path_is_tmp = True installed_dists, installed_files = [], [] for d in dists: @@ -148,14 +142,11 @@ for d in installed_dists: uninstall(d) raise e - finally: - if path_is_tmp: - shutil.rmtree(path) return installed_files -def install_from_infos(install=[], remove=[], conflicts=[], install_path=None): +def install_from_infos(install_path=None, install=[], remove=[], conflicts=[]): """Install and remove the given distributions. The function signature is made to be compatible with the one of get_infos. @@ -174,35 +165,42 @@ 4. Else, move the distributions to the right locations, and remove for real the distributions thats need to be removed. - :param install: list of distributions that will be installed. + :param install_path: the installation path where we want to install the + distributions. + :param install: list of distributions that will be installed; install_path + must be provided if this list is not empty. :param remove: list of distributions that will be removed. :param conflicts: list of conflicting distributions, eg. that will be in conflict once the install and remove distribution will be processed. - :param install_path: the installation path where we want to install the - distributions. """ # first of all, if we have conflicts, stop here. if conflicts: raise InstallationConflict(conflicts) + if install and not install_path: + raise ValueError("Distributions are to be installed but `install_path`" + " is not provided.") + # before removing the files, we will start by moving them away # then, if any error occurs, we could replace them in the good place. temp_files = {} # contains lists of {dist: (old, new)} paths + temp_dir = None if remove: + temp_dir = tempfile.mkdtemp() for dist in remove: files = dist.get_installed_files() - temp_files[dist] = move_files(files) + temp_files[dist] = move_files(files, temp_dir) try: if install: - installed_files = install_dists(install, install_path) # install to tmp first - + installed_files = install_dists(install, install_path) except: - # if an error occurs, put back the files in the good place. + # if an error occurs, put back the files in the right place. for files in temp_files.values(): for old, new in files: shutil.move(new, old) - + if temp_dir: + shutil.rmtree(temp_dir) # now re-raising raise @@ -210,6 +208,8 @@ for files in temp_files.values(): for old, new in files: os.remove(new) + if temp_dir: + shutil.rmtree(temp_dir) def _get_setuptools_deps(release): @@ -379,8 +379,8 @@ install_path = get_config_var('base') try: - install_from_infos(info['install'], info['remove'], info['conflict'], - install_path=install_path) + install_from_infos(install_path, + info['install'], info['remove'], info['conflict']) except InstallationConflict, e: projects = ['%s %s' % (p.name, p.version) for p in e.args[0]] diff --git a/distutils2/tests/test_install.py b/distutils2/tests/test_install.py --- a/distutils2/tests/test_install.py +++ b/distutils2/tests/test_install.py @@ -331,9 +331,11 @@ for i in range(0,2): remove.append(ToInstallDist(files=True)) to_install = [ToInstallDist(), ToInstallDist()] + temp_dir = self.mkdtemp() self.assertRaises(Exception, install.install_from_infos, - remove=remove, install=to_install) + install_path=temp_dir, install=to_install, + remove=remove) # assert that the files are in the same place # assert that the files have been removed for dist in remove: @@ -352,8 +354,7 @@ install_path = "my_install_path" to_install = [ToInstallDist(), ToInstallDist()] - install.install_from_infos(install=to_install, - install_path=install_path) + install.install_from_infos(install_path, install=to_install) for dist in to_install: install._install_dist.called_with(install_path) finally: -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:45:09 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:45:09 +0100 Subject: [Python-checkins] distutils2: added some cleanup after the tests to make sure that we don't leak temp files Message-ID: tarek.ziade pushed 18cd862b069f to distutils2: http://hg.python.org/distutils2/rev/18cd862b069f changeset: 962:18cd862b069f user: Yannick Gingras date: Sat Jan 29 20:37:55 2011 -0500 summary: added some cleanup after the tests to make sure that we don't leak temp files files: distutils2/tests/test_install.py diff --git a/distutils2/tests/test_install.py b/distutils2/tests/test_install.py --- a/distutils2/tests/test_install.py +++ b/distutils2/tests/test_install.py @@ -39,6 +39,11 @@ for f in range(0,3): self._real_files.append(mkstemp()) + def _unlink_installed_files(self): + if self._files: + for f in self._real_files: + os.unlink(f[1]) + def get_installed_files(self, **args): if self._files: return [f[1] for f in self._real_files] @@ -341,6 +346,7 @@ for dist in remove: for f in dist.get_installed_files(): self.assertTrue(os.path.exists(f)) + dist._unlink_installed_files() finally: install.install_dist = old_install_dist install.uninstall = old_uninstall -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 10:45:09 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 10:45:09 +0100 Subject: [Python-checkins] distutils2: merged doc from Yannick Message-ID: tarek.ziade pushed 50d8e9211704 to distutils2: http://hg.python.org/distutils2/rev/50d8e9211704 changeset: 963:50d8e9211704 tag: tip parent: 957:8106777a8748 parent: 962:18cd862b069f user: Tarek Ziade date: Sun Jan 30 10:44:37 2011 +0100 summary: merged doc from Yannick files: diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -35,7 +35,7 @@ """Raised when a conflict is detected""" -def move_files(files, destination=None): +def move_files(files, destination): """Move the list of files in the destination folder, keeping the same structure. @@ -43,13 +43,11 @@ :param files: a list of files to move. :param destination: the destination directory to put on the files. - if not defined, create a new one, using mkdtemp """ - if not destination: - destination = mkdtemp() - for old in files: - new = '%s%s' % (destination, old) + # not using os.path.join() because basename() might not be + # unique in destination + new = "%s%s" % (destination, old) # try to make the paths. try: @@ -119,7 +117,7 @@ os.chdir(old_dir) -def install_dists(dists, path=None): +def install_dists(dists, path): """Install all distributions provided in dists, with the given prefix. If an error occurs while installing one of the distributions, uninstall all @@ -130,8 +128,6 @@ :param dists: distributions to install :param path: base path to install distribution in """ - if not path: - path = mkdtemp() installed_dists, installed_files = [], [] for d in dists: @@ -146,10 +142,11 @@ for d in installed_dists: uninstall(d) raise e + return installed_files -def install_from_infos(install=[], remove=[], conflicts=[], install_path=None): +def install_from_infos(install_path=None, install=[], remove=[], conflicts=[]): """Install and remove the given distributions. The function signature is made to be compatible with the one of get_infos. @@ -168,35 +165,42 @@ 4. Else, move the distributions to the right locations, and remove for real the distributions thats need to be removed. - :param install: list of distributions that will be installed. + :param install_path: the installation path where we want to install the + distributions. + :param install: list of distributions that will be installed; install_path + must be provided if this list is not empty. :param remove: list of distributions that will be removed. :param conflicts: list of conflicting distributions, eg. that will be in conflict once the install and remove distribution will be processed. - :param install_path: the installation path where we want to install the - distributions. """ # first of all, if we have conflicts, stop here. if conflicts: raise InstallationConflict(conflicts) + if install and not install_path: + raise ValueError("Distributions are to be installed but `install_path`" + " is not provided.") + # before removing the files, we will start by moving them away # then, if any error occurs, we could replace them in the good place. temp_files = {} # contains lists of {dist: (old, new)} paths + temp_dir = None if remove: + temp_dir = tempfile.mkdtemp() for dist in remove: files = dist.get_installed_files() - temp_files[dist] = move_files(files) + temp_files[dist] = move_files(files, temp_dir) try: if install: - installed_files = install_dists(install, install_path) # install to tmp first - + installed_files = install_dists(install, install_path) except: - # if an error occurs, put back the files in the good place. + # if an error occurs, put back the files in the right place. for files in temp_files.values(): for old, new in files: shutil.move(new, old) - + if temp_dir: + shutil.rmtree(temp_dir) # now re-raising raise @@ -204,6 +208,8 @@ for files in temp_files.values(): for old, new in files: os.remove(new) + if temp_dir: + shutil.rmtree(temp_dir) def _get_setuptools_deps(release): @@ -317,13 +323,13 @@ def remove(project_name, paths=sys.path): """Removes a single project from the installation""" - tmp = tempfile.mkdtemp(prefix=project_name+'-uninstall') dist = get_distribution(project_name, paths=paths) if dist is None: raise DistutilsError('Distribution %s not found' % project_name) files = dist.get_installed_files(local=True) rmdirs = [] rmfiles = [] + tmp = tempfile.mkdtemp(prefix=project_name+'-uninstall') try: for file, md5, size in files: @@ -339,8 +345,8 @@ rmfiles.append(file) if dirname not in rmdirs: rmdirs.append(dirname) - except OSError: - os.rmdir(tmp) + finally: + shutil.rmtree(tmp) for file in rmfiles: os.remove(file) @@ -373,8 +379,8 @@ install_path = get_config_var('base') try: - install_from_infos(info['install'], info['remove'], info['conflict'], - install_path=install_path) + install_from_infos(install_path, + info['install'], info['remove'], info['conflict']) except InstallationConflict, e: projects = ['%s %s' % (p.name, p.version) for p in e.args[0]] diff --git a/distutils2/tests/test_install.py b/distutils2/tests/test_install.py --- a/distutils2/tests/test_install.py +++ b/distutils2/tests/test_install.py @@ -39,6 +39,11 @@ for f in range(0,3): self._real_files.append(mkstemp()) + def _unlink_installed_files(self): + if self._files: + for f in self._real_files: + os.unlink(f[1]) + def get_installed_files(self, **args): if self._files: return [f[1] for f in self._real_files] @@ -331,14 +336,17 @@ for i in range(0,2): remove.append(ToInstallDist(files=True)) to_install = [ToInstallDist(), ToInstallDist()] + temp_dir = self.mkdtemp() self.assertRaises(Exception, install.install_from_infos, - remove=remove, install=to_install) + install_path=temp_dir, install=to_install, + remove=remove) # assert that the files are in the same place # assert that the files have been removed for dist in remove: for f in dist.get_installed_files(): self.assertTrue(os.path.exists(f)) + dist._unlink_installed_files() finally: install.install_dist = old_install_dist install.uninstall = old_uninstall @@ -352,8 +360,7 @@ install_path = "my_install_path" to_install = [ToInstallDist(), ToInstallDist()] - install.install_from_infos(install=to_install, - install_path=install_path) + install.install_from_infos(install_path, install=to_install) for dist in to_install: install._install_dist.called_with(install_path) finally: -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 11:22:29 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 11:22:29 +0100 Subject: [Python-checkins] distutils2: cleaned up the install module Message-ID: tarek.ziade pushed 66f2c2a50996 to distutils2: http://hg.python.org/distutils2/rev/66f2c2a50996 changeset: 964:66f2c2a50996 tag: tip user: Tarek Ziade date: Sun Jan 30 11:22:19 2011 +0100 summary: cleaned up the install module files: distutils2/install.py distutils2/tests/test_install.py diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -1,4 +1,11 @@ -from tempfile import mkdtemp +"""Provides installations scripts. + +The goal of this script is to install a release from the indexes (eg. +PyPI), including the dependencies of the releases if needed. + +It uses the work made in pkgutil and by the index crawlers to browse the +installed distributions, and rely on the instalation commands to install. +""" import shutil import os import sys @@ -17,14 +24,9 @@ from distutils2.errors import DistutilsError from distutils2.version import get_version_predicate -"""Provides installations scripts. -The goal of this script is to install a release from the indexes (eg. -PyPI), including the dependencies of the releases if needed. - -It uses the work made in pkgutil and by the index crawlers to browse the -installed distributions, and rely on the instalation commands to install. -""" +__all__ = ['install_dists', 'install_from_infos', 'get_infos', 'remove', + 'install'] class InstallationException(Exception): @@ -35,7 +37,7 @@ """Raised when a conflict is detected""" -def move_files(files, destination): +def _move_files(files, destination): """Move the list of files in the destination folder, keeping the same structure. @@ -58,7 +60,7 @@ else: raise e os.rename(old, new) - yield (old, new) + yield old, new def _run_d1_install(archive_dir, path): @@ -91,7 +93,7 @@ * copy the files in "path" * determine if the distribution is distutils2 or distutils1. """ - where = dist.unpack(archive) + where = dist.unpack(path) # get into the dir archive_dir = None @@ -117,7 +119,7 @@ os.chdir(old_dir) -def install_dists(dists, path): +def install_dists(dists, path, paths=sys.path): """Install all distributions provided in dists, with the given prefix. If an error occurs while installing one of the distributions, uninstall all @@ -127,26 +129,28 @@ :param dists: distributions to install :param path: base path to install distribution in + :param paths: list of paths (defaults to sys.path) to look for info """ installed_dists, installed_files = [], [] - for d in dists: - logger.info('Installing %s %s' % (d.name, d.version)) + for dist in dists: + logger.info('Installing %s %s' % (dist.name, dist.version)) try: - installed_files.extend(_install_dist(d, path)) - installed_dists.append(d) - except Exception, e : + installed_files.extend(_install_dist(dist, path)) + installed_dists.append(dist) + except Exception, e: logger.info('Failed. %s' % str(e)) # reverting - for d in installed_dists: - uninstall(d) + for installed_dist in installed_dists: + _remove_dist(installed_dist, paths) raise e - + return installed_files -def install_from_infos(install_path=None, install=[], remove=[], conflicts=[]): +def install_from_infos(install_path=None, install=[], remove=[], conflicts=[], + paths=sys.path): """Install and remove the given distributions. The function signature is made to be compatible with the one of get_infos. @@ -173,6 +177,7 @@ :param conflicts: list of conflicting distributions, eg. that will be in conflict once the install and remove distribution will be processed. + :param paths: list of paths (defaults to sys.path) to look for info """ # first of all, if we have conflicts, stop here. if conflicts: @@ -190,10 +195,10 @@ temp_dir = tempfile.mkdtemp() for dist in remove: files = dist.get_installed_files() - temp_files[dist] = move_files(files, temp_dir) + temp_files[dist] = _move_files(files, temp_dir) try: if install: - installed_files = install_dists(install, install_path) + install_dists(install, install_path, paths) except: # if an error occurs, put back the files in the right place. for files in temp_files.values(): @@ -271,9 +276,9 @@ # Get all the releases that match the requirements try: releases = index.get_releases(requirements) - except (ReleaseNotFound, ProjectNotFound), e: + except (ReleaseNotFound, ProjectNotFound): raise InstallationException('Release not found: "%s"' % requirements) - + # Pick up a release, and try to get the dependency tree release = releases.get_last(requirements, prefer_final=prefer_final) @@ -290,6 +295,8 @@ else: deps = metadata['requires_dist'] + # XXX deps not used + distributions = itertools.chain(installed, [release]) depgraph = generate_graph(distributions) @@ -321,6 +328,10 @@ infos[key].extend(new_infos[key]) +def _remove_dist(dist, paths=sys.path): + remove(dist.name, paths) + + def remove(project_name, paths=sys.path): """Removes a single project from the installation""" dist = get_distribution(project_name, paths=paths) @@ -329,8 +340,7 @@ files = dist.get_installed_files(local=True) rmdirs = [] rmfiles = [] - tmp = tempfile.mkdtemp(prefix=project_name+'-uninstall') - + tmp = tempfile.mkdtemp(prefix=project_name + '-uninstall') try: for file, md5, size in files: if os.path.isfile(file): @@ -357,14 +367,6 @@ os.rmdir(dirname) - -def main(**attrs): - if 'script_args' not in attrs: - import sys - attrs['requirements'] = sys.argv[1] - get_infos(**attrs) - - def install(project): logger.info('Getting information about "%s".' % project) try: @@ -379,7 +381,7 @@ install_path = get_config_var('base') try: - install_from_infos(install_path, + install_from_infos(install_path, info['install'], info['remove'], info['conflict']) except InstallationConflict, e: @@ -387,5 +389,12 @@ logger.info('"%s" conflicts with "%s"' % (project, ','.join(projects))) +def _main(**attrs): + if 'script_args' not in attrs: + import sys + attrs['requirements'] = sys.argv[1] + get_infos(**attrs) + + if __name__ == '__main__': - main() + _main() diff --git a/distutils2/tests/test_install.py b/distutils2/tests/test_install.py --- a/distutils2/tests/test_install.py +++ b/distutils2/tests/test_install.py @@ -59,14 +59,14 @@ self._called_with = [] self._return_value = return_value self._raise = raise_exception - + def __call__(self, *args, **kwargs): self.called = True self._times_called = self._times_called + 1 self._called_with.append((args, kwargs)) iterable = hasattr(self._raise, '__iter__') if self._raise: - if ((not iterable and self._raise) + if ((not iterable and self._raise) or self._raise[self._times_called - 1]): raise Exception return self._return_value @@ -93,7 +93,7 @@ def get_installed_dists(dists): - """Return a list of fake installed dists. + """Return a list of fake installed dists. The list is name, version, deps""" objects = [] for (name, version, deps) in dists: @@ -210,7 +210,7 @@ ]) # name, version, deps. - already_installed = [('bacon', '0.1', []), + already_installed = [('bacon', '0.1', []), ('chicken', '1.1', ['bacon (0.1)'])] output = install.get_infos("choxie", index=client, installed= get_installed_dists(already_installed)) @@ -241,7 +241,7 @@ files = [os.path.join(path, '%s' % x) for x in range(1, 20)] for f in files: file(f, 'a+') - output = [o for o in install.move_files(files, newpath)] + output = [o for o in install._move_files(files, newpath)] # check that output return the list of old/new places for f in files: @@ -270,19 +270,19 @@ old_install_dist = install._install_dist old_uninstall = getattr(install, 'uninstall', None) - install._install_dist = MagicMock(return_value=[], + install._install_dist = MagicMock(return_value=[], raise_exception=(False, True)) - install.uninstall = MagicMock() + install.remove = MagicMock() try: d1 = ToInstallDist() d2 = ToInstallDist() path = self.mkdtemp() self.assertRaises(Exception, install.install_dists, [d1, d2], path) self.assertTrue(install._install_dist.called_with(d1, path)) - self.assertTrue(install.uninstall.called) + self.assertTrue(install.remove.called) finally: install._install_dist = old_install_dist - install.uninstall = old_uninstall + install.remove = old_uninstall def test_install_dists_success(self): @@ -327,7 +327,7 @@ old_install_dist = install._install_dist old_uninstall = getattr(install, 'uninstall', None) - install._install_dist = MagicMock(return_value=[], + install._install_dist = MagicMock(return_value=[], raise_exception=(False, True)) install.uninstall = MagicMock() try: @@ -338,8 +338,8 @@ to_install = [ToInstallDist(), ToInstallDist()] temp_dir = self.mkdtemp() - self.assertRaises(Exception, install.install_from_infos, - install_path=temp_dir, install=to_install, + self.assertRaises(Exception, install.install_from_infos, + install_path=temp_dir, install=to_install, remove=remove) # assert that the files are in the same place # assert that the files have been removed -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 11:32:28 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 11:32:28 +0100 Subject: [Python-checkins] distutils2: minor: update setupcfg documentation Message-ID: tarek.ziade pushed fcd52b00517a to distutils2: http://hg.python.org/distutils2/rev/fcd52b00517a changeset: 965:fcd52b00517a tag: tip user: Julien Jehannet date: Sun Jan 30 10:46:06 2011 +0100 summary: minor: update setupcfg documentation files: docs/source/distutils/sourcedist.rst docs/source/setupcfg.rst diff --git a/docs/source/distutils/sourcedist.rst b/docs/source/distutils/sourcedist.rst --- a/docs/source/distutils/sourcedist.rst +++ b/docs/source/distutils/sourcedist.rst @@ -86,8 +86,7 @@ distributions, but in the future there will be a standard for testing Python module distributions) -* :file:`README.txt` (or :file:`README`), :file:`setup.py` (or whatever you - called your setup script), and :file:`setup.cfg` +* The configuration file :file:`setup.cfg` * all files that matches the ``package_data`` metadata. See :ref:`distutils-installing-package-data`. @@ -95,6 +94,10 @@ * all files that matches the ``data_files`` metadata. See :ref:`distutils-additional-files`. +.. Warning:: + In Distutils2, setup.py and README (or README.txt) files are not more + included in source distribution by default + Sometimes this is enough, but usually you will want to specify additional files to distribute. The typical way to do this is to write a *manifest template*, called :file:`MANIFEST.in` by default. The manifest template is just a list of diff --git a/docs/source/setupcfg.rst b/docs/source/setupcfg.rst --- a/docs/source/setupcfg.rst +++ b/docs/source/setupcfg.rst @@ -7,8 +7,8 @@ Each section contains a description of its options. -- Options that are marked *\*multi* can have multiple values, one value - per line. +- Options that are marked *\*multi* can have multiple values, one value per + line. - Options that are marked *\*optional* can be omited. - Options that are marked *\*environ* can use environment markers, as described in :PEP:`345`. @@ -49,7 +49,7 @@ *\*optional* *\*multi* - **compilers**: Defined Distutils2 compiler. A compiler is defined by its fully - qualified name. + qualified name. Example:: @@ -66,7 +66,8 @@ Example:: [global] - setup_hook = distutils2.tests.test_config.hook + setup_hook = + distutils2.tests.test_config.hook metadata @@ -142,7 +143,7 @@ .. Note:: Some metadata fields seen in :PEP:`345` are automatically generated - as the Metadata-Version value for instance. + (for instance Metadata-Version value). files @@ -170,6 +171,14 @@ extra_files = setup.py + README + +.. Note:: + In Distutils2, setup.cfg will be implicitly included. + +.. Warning:: + In Distutils2, setup.py and README (or README.txt) files are not more + included in source distribution by default `command` sections @@ -183,7 +192,7 @@ manifest-builders = package.module.Maker -To override the building class in order to compile your python2 files to python3:: +To override the build class in order to generate Python3 code from your Python2 base:: [build_py] use-2to3 = True -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 13:19:35 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 30 Jan 2011 13:19:35 +0100 (CET) Subject: [Python-checkins] r88263 - in python/branches/py3k: Lib/argparse.py Lib/test/test_argparse.py Misc/NEWS Message-ID: <20110130121935.BC7B4EE983@mail.python.org> Author: georg.brandl Date: Sun Jan 30 13:19:35 2011 New Revision: 88263 Log: #10680: fix mutually exclusive arguments in argument groups. Modified: python/branches/py3k/Lib/argparse.py python/branches/py3k/Lib/test/test_argparse.py python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Lib/argparse.py ============================================================================== --- python/branches/py3k/Lib/argparse.py (original) +++ python/branches/py3k/Lib/argparse.py Sun Jan 30 13:19:35 2011 @@ -1495,6 +1495,7 @@ self._defaults = container._defaults self._has_negative_number_optionals = \ container._has_negative_number_optionals + self._mutually_exclusive_groups = container._mutually_exclusive_groups def _add_action(self, action): action = super(_ArgumentGroup, self)._add_action(action) Modified: python/branches/py3k/Lib/test/test_argparse.py ============================================================================== --- python/branches/py3k/Lib/test/test_argparse.py (original) +++ python/branches/py3k/Lib/test/test_argparse.py Sun Jan 30 13:19:35 2011 @@ -2540,6 +2540,46 @@ ''' +class TestMutuallyExclusiveInGroup(MEMixin, TestCase): + + def get_parser(self, required=None): + parser = ErrorRaisingArgumentParser(prog='PROG') + titled_group = parser.add_argument_group( + title='Titled group', description='Group description') + mutex_group = \ + titled_group.add_mutually_exclusive_group(required=required) + mutex_group.add_argument('--bar', help='bar help') + mutex_group.add_argument('--baz', help='baz help') + return parser + + failures = ['--bar X --baz Y', '--baz X --bar Y'] + successes = [ + ('--bar X', NS(bar='X', baz=None)), + ('--baz Y', NS(bar=None, baz='Y')), + ] + successes_when_not_required = [ + ('', NS(bar=None, baz=None)), + ] + + usage_when_not_required = '''\ + usage: PROG [-h] [--bar BAR | --baz BAZ] + ''' + usage_when_required = '''\ + usage: PROG [-h] (--bar BAR | --baz BAZ) + ''' + help = '''\ + + optional arguments: + -h, --help show this help message and exit + + Titled group: + Group description + + --bar BAR bar help + --baz BAZ baz help + ''' + + class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase): def get_parser(self, required): Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sun Jan 30 13:19:35 2011 @@ -91,6 +91,9 @@ - Issue #10961: The new pydoc server now better handles exceptions raised during request handling. +- Issue #10680: Fix mutually exclusive arguments for argument groups in + argparse. + Build ----- From python-checkins at python.org Sun Jan 30 14:49:23 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:23 +0100 Subject: [Python-checkins] distutils2: cleanup Message-ID: tarek.ziade pushed 5e6e1c546a70 to distutils2: http://hg.python.org/distutils2/rev/5e6e1c546a70 changeset: 966:5e6e1c546a70 user: Tarek Ziade date: Sun Jan 30 12:01:46 2011 +0100 summary: cleanup files: distutils2/run.py diff --git a/distutils2/run.py b/distutils2/run.py --- a/distutils2/run.py +++ b/distutils2/run.py @@ -83,10 +83,10 @@ dist = distclass(attrs) except DistutilsSetupError, msg: if 'name' in attrs: - raise SystemExit, "error in %s setup command: %s" % \ - (attrs['name'], msg) + raise SystemExit("error in %s setup command: %s" % \ + (attrs['name'], msg)) else: - raise SystemExit, "error in setup command: %s" % msg + raise SystemExit("error in setup command: %s" % msg) # Find and parse the config file(s): they will override options from # the setup script, but be overridden by the command line. @@ -98,22 +98,21 @@ try: res = dist.parse_command_line() except DistutilsArgError, msg: - raise SystemExit, gen_usage(dist.script_name) + "\nerror: %s" % msg + raise SystemExit(gen_usage(dist.script_name) + "\nerror: %s" % msg) # And finally, run all the commands found on the command line. if res: try: dist.run_commands() except KeyboardInterrupt: - raise SystemExit, "interrupted" + raise SystemExit("interrupted") except (IOError, os.error), exc: error = grok_environment_error(exc) - raise SystemExit, error + raise SystemExit(error) except (DistutilsError, CCompilerError), msg: - raise - raise SystemExit, "error: " + str(msg) + raise SystemExit("error: " + str(msg)) return dist @@ -127,7 +126,10 @@ def main(): - """Main entry point for Distutils2""" + """Main entry point for Distutils2 + + Execute an action or delegate to the commands system. + """ _set_logger() parser = OptionParser() parser.disable_interspersed_args() @@ -164,7 +166,7 @@ options, args = parser.parse_args() if options.version: print('Distutils2 %s' % __version__) -# sys.exit(0) + return 0 if len(options.metadata): from distutils2.dist import Distribution @@ -178,18 +180,18 @@ keys = options.metadata if len(keys) == 1: print metadata[keys[0]] - sys.exit(0) + return for key in keys: if key in metadata: - print(metadata._convert_name(key)+':') + print(metadata._convert_name(key) + ':') value = metadata[key] if isinstance(value, list): for v in value: - print(' '+v) + print(' ' + v) else: - print(' '+value.replace('\n', '\n ')) - sys.exit(0) + print(' ' + value.replace('\n', '\n ')) + return 0 if options.search is not None: search = options.search.lower() @@ -199,7 +201,7 @@ print('%s %s at %s' % (dist.name, dist.metadata['version'], dist.path)) - sys.exit(0) + return 0 if options.graph is not None: name = options.graph @@ -211,25 +213,25 @@ graph = generate_graph(dists) print(graph.repr_node(dist)) - sys.exit(0) + return 0 if options.fgraph: dists = get_distributions(use_egg_info=True) graph = generate_graph(dists) print(graph) - sys.exit(0) + return 0 if options.install is not None: install(options.install) - sys.exit(0) + return 0 if len(args) == 0: parser.print_help() - sys.exit(0) + return 0 - return commands_main() -# sys.exit(0) + commands_main() + return 0 if __name__ == '__main__': - main() + sys.exit(main()) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:25 +0100 Subject: [Python-checkins] distutils2: Fixing tests on provides_distribution (the two beers bug) Message-ID: tarek.ziade pushed 6527d3106e9f to distutils2: http://hg.python.org/distutils2/rev/6527d3106e9f changeset: 968:6527d3106e9f parent: 963:50d8e9211704 user: Andre Espaze date: Sun Jan 30 11:36:32 2011 +0100 summary: Fixing tests on provides_distribution (the two beers bug) When testing provides_distribution, a package should not provide itself. As a consequence, the corresponding code on EggInfoDistrbution has been removed (even if it should have been done in commit 11adbbb89d73). Thanks for the beers :-) files: distutils2/_backport/pkgutil.py distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO distutils2/_backport/tests/test_pkgutil.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -922,10 +922,6 @@ for field in ('Obsoletes', 'Requires', 'Provides'): del self.metadata[field] - provides = "%s (%s)" % (self.metadata['name'], - self.metadata['version']) - self.metadata['Provides-Dist'] += (provides,) - reqs = [] if requires is not None: diff --git a/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO b/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO new file mode 100644 --- /dev/null +++ b/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO @@ -0,0 +1,5 @@ +Metadata-Version: 1.2 +Name: coconuts-aster +Version: 10.3 +Provides-Dist: strawberry (0.6) +Provides-Dist: banana (0.4) diff --git a/distutils2/_backport/tests/test_pkgutil.py b/distutils2/_backport/tests/test_pkgutil.py --- a/distutils2/_backport/tests/test_pkgutil.py +++ b/distutils2/_backport/tests/test_pkgutil.py @@ -389,6 +389,7 @@ # Now, test if the egg-info distributions are found correctly as well fake_dists += [('bacon', '0.1'), ('cheese', '2.0.2'), + ('coconuts-aster', '10.3'), ('banana', '0.4'), ('strawberry', '0.6'), ('truffles', '5.0'), ('nut', 'funkyversion')] found_dists = [] @@ -494,18 +495,18 @@ l = [dist.name for dist in provides_distribution('truffles', '>1.5', use_egg_info=True)] - checkLists(l, ['bacon', 'truffles']) + checkLists(l, ['bacon']) l = [dist.name for dist in provides_distribution('truffles', '>=1.0')] checkLists(l, ['choxie', 'towel-stuff']) l = [dist.name for dist in provides_distribution('strawberry', '0.6', use_egg_info=True)] - checkLists(l, ['strawberry']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('strawberry', '>=0.5', use_egg_info=True)] - checkLists(l, ['strawberry']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('strawberry', '>0.6', use_egg_info=True)] @@ -513,11 +514,11 @@ l = [dist.name for dist in provides_distribution('banana', '0.4', use_egg_info=True)] - checkLists(l, ['banana']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('banana', '>=0.3', use_egg_info=True)] - checkLists(l, ['banana']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('banana', '!=0.4', use_egg_info=True)] @@ -557,7 +558,7 @@ eggs = [('bacon', '0.1'), ('banana', '0.4'), ('strawberry', '0.6'), ('truffles', '5.0'), ('cheese', '2.0.2'), - ('nut', 'funkyversion')] + ('coconuts-aster', '10.3'), ('nut', 'funkyversion')] dists = [('choxie', '2.0.0.9'), ('grammar', '1.0a4'), ('towel-stuff', '0.1')] -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:25 +0100 Subject: [Python-checkins] distutils2: Parsing compiler arguments with shlex.split Message-ID: tarek.ziade pushed 5d00f818f749 to distutils2: http://hg.python.org/distutils2/rev/5d00f818f749 changeset: 969:5d00f818f749 user: Andre Espaze date: Sun Jan 30 11:56:32 2011 +0100 summary: Parsing compiler arguments with shlex.split Thanks to Julien Jehannet for the tip. files: distutils2/config.py distutils2/tests/test_config.py diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -6,6 +6,7 @@ import re import sys from ConfigParser import RawConfigParser +from shlex import split from distutils2 import logger from distutils2.errors import DistutilsOptionError @@ -17,15 +18,9 @@ def _pop_values(values_dct, key): """Remove values from the dictionary and convert them as a list""" - vals_str = values_dct.pop(key, None) - if not vals_str: - return + vals_str = values_dct.pop(key, '') # Get bash options like `gcc -print-file-name=libgcc.a` - vals = re.search('(`.*?`)', vals_str) or [] - if vals: - vals = list(vals.groups()) - vals_str = re.sub('`.*?`', '', vals_str) - vals.extend(vals_str.split()) + vals = split(vals_str) if vals: return vals diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -103,7 +103,7 @@ [extension=speed_coconuts] name = one.speed_coconuts sources = c_src/speed_coconuts.c -extra_link_args = `gcc -print-file-name=libgcc.a` -shared +extra_link_args = "`gcc -print-file-name=libgcc.a`" -shared define_macros = HAVE_CAIRO HAVE_GTK2 [extension=fast_taunt] -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:25 +0100 Subject: [Python-checkins] distutils2: remove useless functions in test_install Message-ID: tarek.ziade pushed 196b52136e10 to distutils2: http://hg.python.org/distutils2/rev/196b52136e10 changeset: 972:196b52136e10 parent: 962:18cd862b069f user: Alexis Metaireau date: Sun Jan 30 10:47:12 2011 +0100 summary: remove useless functions in test_install files: distutils2/tests/test_install.py diff --git a/distutils2/tests/test_install.py b/distutils2/tests/test_install.py --- a/distutils2/tests/test_install.py +++ b/distutils2/tests/test_install.py @@ -75,23 +75,6 @@ return (args, kwargs) in self._called_with -def patch(parent, to_patch): - """monkey match a module""" - def wrapper(func): - print func - print dir(func) - old_func = getattr(parent, to_patch) - def wrapped(*args, **kwargs): - parent.__dict__[to_patch] = MagicMock() - try: - out = func(*args, **kwargs) - finally: - setattr(parent, to_patch, old_func) - return out - return wrapped - return wrapper - - def get_installed_dists(dists): """Return a list of fake installed dists. The list is name, version, deps""" @@ -105,12 +88,6 @@ def _get_client(self, server, *args, **kwargs): return Client(server.full_address, *args, **kwargs) - def _patch_run_install(self): - """Patch run install""" - - def _unpatch_run_install(self): - """Unpatch run install for d2 and d1""" - def _get_results(self, output): """return a list of results""" installed = [(o.name, '%s' % o.version) for o in output['install']] -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:25 +0100 Subject: [Python-checkins] distutils2: merge with Andr? Message-ID: tarek.ziade pushed e29ec36290b6 to distutils2: http://hg.python.org/distutils2/rev/e29ec36290b6 changeset: 970:e29ec36290b6 parent: 965:fcd52b00517a parent: 969:5d00f818f749 user: Alexis Metaireau date: Sun Jan 30 12:04:25 2011 +0100 summary: merge with Andr? files: diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -922,10 +922,6 @@ for field in ('Obsoletes', 'Requires', 'Provides'): del self.metadata[field] - provides = "%s (%s)" % (self.metadata['name'], - self.metadata['version']) - self.metadata['Provides-Dist'] += (provides,) - reqs = [] if requires is not None: diff --git a/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO b/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO new file mode 100644 --- /dev/null +++ b/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO @@ -0,0 +1,5 @@ +Metadata-Version: 1.2 +Name: coconuts-aster +Version: 10.3 +Provides-Dist: strawberry (0.6) +Provides-Dist: banana (0.4) diff --git a/distutils2/_backport/tests/test_pkgutil.py b/distutils2/_backport/tests/test_pkgutil.py --- a/distutils2/_backport/tests/test_pkgutil.py +++ b/distutils2/_backport/tests/test_pkgutil.py @@ -389,6 +389,7 @@ # Now, test if the egg-info distributions are found correctly as well fake_dists += [('bacon', '0.1'), ('cheese', '2.0.2'), + ('coconuts-aster', '10.3'), ('banana', '0.4'), ('strawberry', '0.6'), ('truffles', '5.0'), ('nut', 'funkyversion')] found_dists = [] @@ -494,18 +495,18 @@ l = [dist.name for dist in provides_distribution('truffles', '>1.5', use_egg_info=True)] - checkLists(l, ['bacon', 'truffles']) + checkLists(l, ['bacon']) l = [dist.name for dist in provides_distribution('truffles', '>=1.0')] checkLists(l, ['choxie', 'towel-stuff']) l = [dist.name for dist in provides_distribution('strawberry', '0.6', use_egg_info=True)] - checkLists(l, ['strawberry']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('strawberry', '>=0.5', use_egg_info=True)] - checkLists(l, ['strawberry']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('strawberry', '>0.6', use_egg_info=True)] @@ -513,11 +514,11 @@ l = [dist.name for dist in provides_distribution('banana', '0.4', use_egg_info=True)] - checkLists(l, ['banana']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('banana', '>=0.3', use_egg_info=True)] - checkLists(l, ['banana']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('banana', '!=0.4', use_egg_info=True)] @@ -557,7 +558,7 @@ eggs = [('bacon', '0.1'), ('banana', '0.4'), ('strawberry', '0.6'), ('truffles', '5.0'), ('cheese', '2.0.2'), - ('nut', 'funkyversion')] + ('coconuts-aster', '10.3'), ('nut', 'funkyversion')] dists = [('choxie', '2.0.0.9'), ('grammar', '1.0a4'), ('towel-stuff', '0.1')] diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -6,6 +6,7 @@ import re import sys from ConfigParser import RawConfigParser +from shlex import split from distutils2 import logger from distutils2.errors import DistutilsOptionError @@ -17,15 +18,9 @@ def _pop_values(values_dct, key): """Remove values from the dictionary and convert them as a list""" - vals_str = values_dct.pop(key, None) - if not vals_str: - return + vals_str = values_dct.pop(key, '') # Get bash options like `gcc -print-file-name=libgcc.a` - vals = re.search('(`.*?`)', vals_str) or [] - if vals: - vals = list(vals.groups()) - vals_str = re.sub('`.*?`', '', vals_str) - vals.extend(vals_str.split()) + vals = split(vals_str) if vals: return vals diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -103,7 +103,7 @@ [extension=speed_coconuts] name = one.speed_coconuts sources = c_src/speed_coconuts.c -extra_link_args = `gcc -print-file-name=libgcc.a` -shared +extra_link_args = "`gcc -print-file-name=libgcc.a`" -shared define_macros = HAVE_CAIRO HAVE_GTK2 [extension=fast_taunt] -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:25 +0100 Subject: [Python-checkins] distutils2: add the configfile discussions file in design Message-ID: tarek.ziade pushed 577f6269464e to distutils2: http://hg.python.org/distutils2/rev/577f6269464e changeset: 971:577f6269464e user: Alexis Metaireau date: Sun Jan 30 12:34:11 2011 +0100 summary: add the configfile discussions file in design files: docs/design/configfile.rst diff --git a/docs/design/configfile.rst b/docs/design/configfile.rst new file mode 100644 --- /dev/null +++ b/docs/design/configfile.rst @@ -0,0 +1,132 @@ +.. _setup-config: + +************************************ +Writing the Setup Configuration File +************************************ + +Often, it's not possible to write down everything needed to build a distribution +*a priori*: you may need to get some information from the user, or from the +user's system, in order to proceed. As long as that information is fairly +simple---a list of directories to search for C header files or libraries, for +example---then providing a configuration file, :file:`setup.cfg`, for users to +edit is a cheap and easy way to solicit it. Configuration files also let you +provide default values for any command option, which the installer can then +override either on the command line or by editing the config file. + +The setup configuration file is a useful middle-ground between the setup script +---which, ideally, would be opaque to installers [#]_---and the command line to +the setup script, which is outside of your control and entirely up to the +installer. In fact, :file:`setup.cfg` (and any other Distutils configuration +files present on the target system) are processed after the contents of the +setup script, but before the command line. This has several useful +consequences: + +.. If you have more advanced needs, such as determining which extensions to + build based on what capabilities are present on the target system, then you + need the Distutils auto-configuration facility. This started to appear in + Distutils 0.9 but, as of this writing, isn't mature or stable enough yet + for real-world use. + +* installers can override some of what you put in :file:`setup.py` by editing + :file:`setup.cfg` + +* you can provide non-standard defaults for options that are not easily set in + :file:`setup.py` + +* installers can override anything in :file:`setup.cfg` using the command-line + options to :file:`setup.py` + +The basic syntax of the configuration file is simple:: + + [command] + option=value + ... + +where *command* is one of the Distutils commands (e.g. :command:`build_py`, +:command:`install`), and *option* is one of the options that command supports. +Any number of options can be supplied for each command, and any number of +command sections can be included in the file. Blank lines are ignored, as are +comments, which run from a ``'#'`` character until the end of the line. Long +option values can be split across multiple lines simply by indenting the +continuation lines. + +You can find out the list of options supported by a particular command with the +universal :option:`--help` option, e.g. :: + + > python setup.py --help build_ext + [...] + Options for 'build_ext' command: + --build-lib (-b) directory for compiled extension modules + --build-temp (-t) directory for temporary files (build by-products) + --inplace (-i) ignore build-lib and put compiled extensions into the + source directory alongside your pure Python modules + --include-dirs (-I) list of directories to search for header files + --define (-D) C preprocessor macros to define + --undef (-U) C preprocessor macros to undefine + --swig-opts list of SWIG command-line options + [...] + +.. XXX do we want to support ``setup.py --help metadata``? + +Note that an option spelled :option:`--foo-bar` on the command line is spelled +:option:`foo_bar` in configuration files. + +For example, say you want your extensions to be built "in-place"---that is, you +have an extension :mod:`pkg.ext`, and you want the compiled extension file +(:file:`ext.so` on Unix, say) to be put in the same source directory as your +pure Python modules :mod:`pkg.mod1` and :mod:`pkg.mod2`. You can always use the +:option:`--inplace` option on the command line to ensure this:: + + python setup.py build_ext --inplace + +But this requires that you always specify the :command:`build_ext` command +explicitly, and remember to provide :option:`--inplace`. An easier way is to +"set and forget" this option, by encoding it in :file:`setup.cfg`, the +configuration file for this distribution:: + + [build_ext] + inplace=1 + +This will affect all builds of this module distribution, whether or not you +explicitly specify :command:`build_ext`. If you include :file:`setup.cfg` in +your source distribution, it will also affect end-user builds---which is +probably a bad idea for this option, since always building extensions in-place +would break installation of the module distribution. In certain peculiar cases, +though, modules are built right in their installation directory, so this is +conceivably a useful ability. (Distributing extensions that expect to be built +in their installation directory is almost always a bad idea, though.) + +Another example: certain commands take a lot of options that don't change from +run to run; for example, :command:`bdist_rpm` needs to know everything required +to generate a "spec" file for creating an RPM distribution. Some of this +information comes from the setup script, and some is automatically generated by +the Distutils (such as the list of files installed). But some of it has to be +supplied as options to :command:`bdist_rpm`, which would be very tedious to do +on the command line for every run. Hence, here is a snippet from the Distutils' +own :file:`setup.cfg`:: + + [bdist_rpm] + release = 1 + packager = Greg Ward + doc_files = CHANGES.txt + README.txt + USAGE.txt + doc/ + examples/ + +Note that the :option:`doc_files` option is simply a whitespace-separated string +split across multiple lines for readability. + + +.. seealso:: + + :ref:`inst-config-syntax` in "Installing Python Modules" + More information on the configuration files is available in the manual for + system administrators. + + +.. rubric:: Footnotes + +.. [#] This ideal probably won't be achieved until auto-configuration is fully + supported by the Distutils. + -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:25 +0100 Subject: [Python-checkins] distutils2: branch merge Message-ID: tarek.ziade pushed aaa6cf4324b5 to distutils2: http://hg.python.org/distutils2/rev/aaa6cf4324b5 changeset: 973:aaa6cf4324b5 parent: 972:196b52136e10 parent: 971:577f6269464e user: Alexis Metaireau date: Sun Jan 30 12:40:31 2011 +0100 summary: branch merge files: distutils2/tests/test_install.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -922,10 +922,6 @@ for field in ('Obsoletes', 'Requires', 'Provides'): del self.metadata[field] - provides = "%s (%s)" % (self.metadata['name'], - self.metadata['version']) - self.metadata['Provides-Dist'] += (provides,) - reqs = [] if requires is not None: diff --git a/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO b/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO new file mode 100644 --- /dev/null +++ b/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO @@ -0,0 +1,5 @@ +Metadata-Version: 1.2 +Name: coconuts-aster +Version: 10.3 +Provides-Dist: strawberry (0.6) +Provides-Dist: banana (0.4) diff --git a/distutils2/_backport/tests/test_pkgutil.py b/distutils2/_backport/tests/test_pkgutil.py --- a/distutils2/_backport/tests/test_pkgutil.py +++ b/distutils2/_backport/tests/test_pkgutil.py @@ -389,6 +389,7 @@ # Now, test if the egg-info distributions are found correctly as well fake_dists += [('bacon', '0.1'), ('cheese', '2.0.2'), + ('coconuts-aster', '10.3'), ('banana', '0.4'), ('strawberry', '0.6'), ('truffles', '5.0'), ('nut', 'funkyversion')] found_dists = [] @@ -494,18 +495,18 @@ l = [dist.name for dist in provides_distribution('truffles', '>1.5', use_egg_info=True)] - checkLists(l, ['bacon', 'truffles']) + checkLists(l, ['bacon']) l = [dist.name for dist in provides_distribution('truffles', '>=1.0')] checkLists(l, ['choxie', 'towel-stuff']) l = [dist.name for dist in provides_distribution('strawberry', '0.6', use_egg_info=True)] - checkLists(l, ['strawberry']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('strawberry', '>=0.5', use_egg_info=True)] - checkLists(l, ['strawberry']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('strawberry', '>0.6', use_egg_info=True)] @@ -513,11 +514,11 @@ l = [dist.name for dist in provides_distribution('banana', '0.4', use_egg_info=True)] - checkLists(l, ['banana']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('banana', '>=0.3', use_egg_info=True)] - checkLists(l, ['banana']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('banana', '!=0.4', use_egg_info=True)] @@ -557,7 +558,7 @@ eggs = [('bacon', '0.1'), ('banana', '0.4'), ('strawberry', '0.6'), ('truffles', '5.0'), ('cheese', '2.0.2'), - ('nut', 'funkyversion')] + ('coconuts-aster', '10.3'), ('nut', 'funkyversion')] dists = [('choxie', '2.0.0.9'), ('grammar', '1.0a4'), ('towel-stuff', '0.1')] diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -6,6 +6,7 @@ import re import sys from ConfigParser import RawConfigParser +from shlex import split from distutils2 import logger from distutils2.errors import DistutilsOptionError @@ -17,15 +18,9 @@ def _pop_values(values_dct, key): """Remove values from the dictionary and convert them as a list""" - vals_str = values_dct.pop(key, None) - if not vals_str: - return + vals_str = values_dct.pop(key, '') # Get bash options like `gcc -print-file-name=libgcc.a` - vals = re.search('(`.*?`)', vals_str) or [] - if vals: - vals = list(vals.groups()) - vals_str = re.sub('`.*?`', '', vals_str) - vals.extend(vals_str.split()) + vals = split(vals_str) if vals: return vals diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -1,4 +1,11 @@ -from tempfile import mkdtemp +"""Provides installations scripts. + +The goal of this script is to install a release from the indexes (eg. +PyPI), including the dependencies of the releases if needed. + +It uses the work made in pkgutil and by the index crawlers to browse the +installed distributions, and rely on the instalation commands to install. +""" import shutil import os import sys @@ -17,14 +24,9 @@ from distutils2.errors import DistutilsError from distutils2.version import get_version_predicate -"""Provides installations scripts. -The goal of this script is to install a release from the indexes (eg. -PyPI), including the dependencies of the releases if needed. - -It uses the work made in pkgutil and by the index crawlers to browse the -installed distributions, and rely on the instalation commands to install. -""" +__all__ = ['install_dists', 'install_from_infos', 'get_infos', 'remove', + 'install'] class InstallationException(Exception): @@ -35,7 +37,7 @@ """Raised when a conflict is detected""" -def move_files(files, destination): +def _move_files(files, destination): """Move the list of files in the destination folder, keeping the same structure. @@ -58,7 +60,7 @@ else: raise e os.rename(old, new) - yield (old, new) + yield old, new def _run_d1_install(archive_dir, path): @@ -91,7 +93,7 @@ * copy the files in "path" * determine if the distribution is distutils2 or distutils1. """ - where = dist.unpack(archive) + where = dist.unpack(path) # get into the dir archive_dir = None @@ -117,7 +119,7 @@ os.chdir(old_dir) -def install_dists(dists, path): +def install_dists(dists, path, paths=sys.path): """Install all distributions provided in dists, with the given prefix. If an error occurs while installing one of the distributions, uninstall all @@ -127,26 +129,28 @@ :param dists: distributions to install :param path: base path to install distribution in + :param paths: list of paths (defaults to sys.path) to look for info """ installed_dists, installed_files = [], [] - for d in dists: - logger.info('Installing %s %s' % (d.name, d.version)) + for dist in dists: + logger.info('Installing %s %s' % (dist.name, dist.version)) try: - installed_files.extend(_install_dist(d, path)) - installed_dists.append(d) - except Exception, e : + installed_files.extend(_install_dist(dist, path)) + installed_dists.append(dist) + except Exception, e: logger.info('Failed. %s' % str(e)) # reverting - for d in installed_dists: - uninstall(d) + for installed_dist in installed_dists: + _remove_dist(installed_dist, paths) raise e - + return installed_files -def install_from_infos(install_path=None, install=[], remove=[], conflicts=[]): +def install_from_infos(install_path=None, install=[], remove=[], conflicts=[], + paths=sys.path): """Install and remove the given distributions. The function signature is made to be compatible with the one of get_infos. @@ -173,6 +177,7 @@ :param conflicts: list of conflicting distributions, eg. that will be in conflict once the install and remove distribution will be processed. + :param paths: list of paths (defaults to sys.path) to look for info """ # first of all, if we have conflicts, stop here. if conflicts: @@ -190,10 +195,10 @@ temp_dir = tempfile.mkdtemp() for dist in remove: files = dist.get_installed_files() - temp_files[dist] = move_files(files, temp_dir) + temp_files[dist] = _move_files(files, temp_dir) try: if install: - installed_files = install_dists(install, install_path) + install_dists(install, install_path, paths) except: # if an error occurs, put back the files in the right place. for files in temp_files.values(): @@ -271,9 +276,9 @@ # Get all the releases that match the requirements try: releases = index.get_releases(requirements) - except (ReleaseNotFound, ProjectNotFound), e: + except (ReleaseNotFound, ProjectNotFound): raise InstallationException('Release not found: "%s"' % requirements) - + # Pick up a release, and try to get the dependency tree release = releases.get_last(requirements, prefer_final=prefer_final) @@ -290,6 +295,8 @@ else: deps = metadata['requires_dist'] + # XXX deps not used + distributions = itertools.chain(installed, [release]) depgraph = generate_graph(distributions) @@ -321,6 +328,10 @@ infos[key].extend(new_infos[key]) +def _remove_dist(dist, paths=sys.path): + remove(dist.name, paths) + + def remove(project_name, paths=sys.path): """Removes a single project from the installation""" dist = get_distribution(project_name, paths=paths) @@ -329,8 +340,7 @@ files = dist.get_installed_files(local=True) rmdirs = [] rmfiles = [] - tmp = tempfile.mkdtemp(prefix=project_name+'-uninstall') - + tmp = tempfile.mkdtemp(prefix=project_name + '-uninstall') try: for file, md5, size in files: if os.path.isfile(file): @@ -357,14 +367,6 @@ os.rmdir(dirname) - -def main(**attrs): - if 'script_args' not in attrs: - import sys - attrs['requirements'] = sys.argv[1] - get_infos(**attrs) - - def install(project): logger.info('Getting information about "%s".' % project) try: @@ -379,7 +381,7 @@ install_path = get_config_var('base') try: - install_from_infos(install_path, + install_from_infos(install_path, info['install'], info['remove'], info['conflict']) except InstallationConflict, e: @@ -387,5 +389,12 @@ logger.info('"%s" conflicts with "%s"' % (project, ','.join(projects))) +def _main(**attrs): + if 'script_args' not in attrs: + import sys + attrs['requirements'] = sys.argv[1] + get_infos(**attrs) + + if __name__ == '__main__': - main() + _main() diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -103,7 +103,7 @@ [extension=speed_coconuts] name = one.speed_coconuts sources = c_src/speed_coconuts.c -extra_link_args = `gcc -print-file-name=libgcc.a` -shared +extra_link_args = "`gcc -print-file-name=libgcc.a`" -shared define_macros = HAVE_CAIRO HAVE_GTK2 [extension=fast_taunt] diff --git a/distutils2/tests/test_install.py b/distutils2/tests/test_install.py --- a/distutils2/tests/test_install.py +++ b/distutils2/tests/test_install.py @@ -59,14 +59,14 @@ self._called_with = [] self._return_value = return_value self._raise = raise_exception - + def __call__(self, *args, **kwargs): self.called = True self._times_called = self._times_called + 1 self._called_with.append((args, kwargs)) iterable = hasattr(self._raise, '__iter__') if self._raise: - if ((not iterable and self._raise) + if ((not iterable and self._raise) or self._raise[self._times_called - 1]): raise Exception return self._return_value @@ -76,7 +76,7 @@ def get_installed_dists(dists): - """Return a list of fake installed dists. + """Return a list of fake installed dists. The list is name, version, deps""" objects = [] for (name, version, deps) in dists: @@ -187,7 +187,7 @@ ]) # name, version, deps. - already_installed = [('bacon', '0.1', []), + already_installed = [('bacon', '0.1', []), ('chicken', '1.1', ['bacon (0.1)'])] output = install.get_infos("choxie", index=client, installed= get_installed_dists(already_installed)) @@ -218,7 +218,7 @@ files = [os.path.join(path, '%s' % x) for x in range(1, 20)] for f in files: file(f, 'a+') - output = [o for o in install.move_files(files, newpath)] + output = [o for o in install._move_files(files, newpath)] # check that output return the list of old/new places for f in files: @@ -247,19 +247,19 @@ old_install_dist = install._install_dist old_uninstall = getattr(install, 'uninstall', None) - install._install_dist = MagicMock(return_value=[], + install._install_dist = MagicMock(return_value=[], raise_exception=(False, True)) - install.uninstall = MagicMock() + install.remove = MagicMock() try: d1 = ToInstallDist() d2 = ToInstallDist() path = self.mkdtemp() self.assertRaises(Exception, install.install_dists, [d1, d2], path) self.assertTrue(install._install_dist.called_with(d1, path)) - self.assertTrue(install.uninstall.called) + self.assertTrue(install.remove.called) finally: install._install_dist = old_install_dist - install.uninstall = old_uninstall + install.remove = old_uninstall def test_install_dists_success(self): @@ -304,7 +304,7 @@ old_install_dist = install._install_dist old_uninstall = getattr(install, 'uninstall', None) - install._install_dist = MagicMock(return_value=[], + install._install_dist = MagicMock(return_value=[], raise_exception=(False, True)) install.uninstall = MagicMock() try: @@ -315,8 +315,8 @@ to_install = [ToInstallDist(), ToInstallDist()] temp_dir = self.mkdtemp() - self.assertRaises(Exception, install.install_from_infos, - install_path=temp_dir, install=to_install, + self.assertRaises(Exception, install.install_from_infos, + install_path=temp_dir, install=to_install, remove=remove) # assert that the files are in the same place # assert that the files have been removed diff --git a/docs/design/configfile.rst b/docs/design/configfile.rst new file mode 100644 --- /dev/null +++ b/docs/design/configfile.rst @@ -0,0 +1,132 @@ +.. _setup-config: + +************************************ +Writing the Setup Configuration File +************************************ + +Often, it's not possible to write down everything needed to build a distribution +*a priori*: you may need to get some information from the user, or from the +user's system, in order to proceed. As long as that information is fairly +simple---a list of directories to search for C header files or libraries, for +example---then providing a configuration file, :file:`setup.cfg`, for users to +edit is a cheap and easy way to solicit it. Configuration files also let you +provide default values for any command option, which the installer can then +override either on the command line or by editing the config file. + +The setup configuration file is a useful middle-ground between the setup script +---which, ideally, would be opaque to installers [#]_---and the command line to +the setup script, which is outside of your control and entirely up to the +installer. In fact, :file:`setup.cfg` (and any other Distutils configuration +files present on the target system) are processed after the contents of the +setup script, but before the command line. This has several useful +consequences: + +.. If you have more advanced needs, such as determining which extensions to + build based on what capabilities are present on the target system, then you + need the Distutils auto-configuration facility. This started to appear in + Distutils 0.9 but, as of this writing, isn't mature or stable enough yet + for real-world use. + +* installers can override some of what you put in :file:`setup.py` by editing + :file:`setup.cfg` + +* you can provide non-standard defaults for options that are not easily set in + :file:`setup.py` + +* installers can override anything in :file:`setup.cfg` using the command-line + options to :file:`setup.py` + +The basic syntax of the configuration file is simple:: + + [command] + option=value + ... + +where *command* is one of the Distutils commands (e.g. :command:`build_py`, +:command:`install`), and *option* is one of the options that command supports. +Any number of options can be supplied for each command, and any number of +command sections can be included in the file. Blank lines are ignored, as are +comments, which run from a ``'#'`` character until the end of the line. Long +option values can be split across multiple lines simply by indenting the +continuation lines. + +You can find out the list of options supported by a particular command with the +universal :option:`--help` option, e.g. :: + + > python setup.py --help build_ext + [...] + Options for 'build_ext' command: + --build-lib (-b) directory for compiled extension modules + --build-temp (-t) directory for temporary files (build by-products) + --inplace (-i) ignore build-lib and put compiled extensions into the + source directory alongside your pure Python modules + --include-dirs (-I) list of directories to search for header files + --define (-D) C preprocessor macros to define + --undef (-U) C preprocessor macros to undefine + --swig-opts list of SWIG command-line options + [...] + +.. XXX do we want to support ``setup.py --help metadata``? + +Note that an option spelled :option:`--foo-bar` on the command line is spelled +:option:`foo_bar` in configuration files. + +For example, say you want your extensions to be built "in-place"---that is, you +have an extension :mod:`pkg.ext`, and you want the compiled extension file +(:file:`ext.so` on Unix, say) to be put in the same source directory as your +pure Python modules :mod:`pkg.mod1` and :mod:`pkg.mod2`. You can always use the +:option:`--inplace` option on the command line to ensure this:: + + python setup.py build_ext --inplace + +But this requires that you always specify the :command:`build_ext` command +explicitly, and remember to provide :option:`--inplace`. An easier way is to +"set and forget" this option, by encoding it in :file:`setup.cfg`, the +configuration file for this distribution:: + + [build_ext] + inplace=1 + +This will affect all builds of this module distribution, whether or not you +explicitly specify :command:`build_ext`. If you include :file:`setup.cfg` in +your source distribution, it will also affect end-user builds---which is +probably a bad idea for this option, since always building extensions in-place +would break installation of the module distribution. In certain peculiar cases, +though, modules are built right in their installation directory, so this is +conceivably a useful ability. (Distributing extensions that expect to be built +in their installation directory is almost always a bad idea, though.) + +Another example: certain commands take a lot of options that don't change from +run to run; for example, :command:`bdist_rpm` needs to know everything required +to generate a "spec" file for creating an RPM distribution. Some of this +information comes from the setup script, and some is automatically generated by +the Distutils (such as the list of files installed). But some of it has to be +supplied as options to :command:`bdist_rpm`, which would be very tedious to do +on the command line for every run. Hence, here is a snippet from the Distutils' +own :file:`setup.cfg`:: + + [bdist_rpm] + release = 1 + packager = Greg Ward + doc_files = CHANGES.txt + README.txt + USAGE.txt + doc/ + examples/ + +Note that the :option:`doc_files` option is simply a whitespace-separated string +split across multiple lines for readability. + + +.. seealso:: + + :ref:`inst-config-syntax` in "Installing Python Modules" + More information on the configuration files is available in the manual for + system administrators. + + +.. rubric:: Footnotes + +.. [#] This ideal probably won't be achieved until auto-configuration is fully + supported by the Distutils. + diff --git a/docs/source/distutils/sourcedist.rst b/docs/source/distutils/sourcedist.rst --- a/docs/source/distutils/sourcedist.rst +++ b/docs/source/distutils/sourcedist.rst @@ -86,8 +86,7 @@ distributions, but in the future there will be a standard for testing Python module distributions) -* :file:`README.txt` (or :file:`README`), :file:`setup.py` (or whatever you - called your setup script), and :file:`setup.cfg` +* The configuration file :file:`setup.cfg` * all files that matches the ``package_data`` metadata. See :ref:`distutils-installing-package-data`. @@ -95,6 +94,10 @@ * all files that matches the ``data_files`` metadata. See :ref:`distutils-additional-files`. +.. Warning:: + In Distutils2, setup.py and README (or README.txt) files are not more + included in source distribution by default + Sometimes this is enough, but usually you will want to specify additional files to distribute. The typical way to do this is to write a *manifest template*, called :file:`MANIFEST.in` by default. The manifest template is just a list of diff --git a/docs/source/setupcfg.rst b/docs/source/setupcfg.rst --- a/docs/source/setupcfg.rst +++ b/docs/source/setupcfg.rst @@ -7,24 +7,35 @@ Each section contains a description of its options. -- Options that are marked *\*multi* can have multiple values, one value - per line. +- Options that are marked *\*multi* can have multiple values, one value per + line. - Options that are marked *\*optional* can be omited. -- Options that are marked *\*environ* can use environement markes, as described - in PEP 345. +- Options that are marked *\*environ* can use environment markers, as described + in :PEP:`345`. + The sections are: -- global -- metadata -- files -- command sections +global + Global options for Distutils2. + +metadata + The metadata section contains the metadata for the project as described in + :PEP:`345`. + +files + Declaration of package files included in the project. + +`command` sections + Redefinition of user options for Distutils2 commands. global ====== -Contains global options for Distutils2. This section is shared with Distutils1. +Contains global options for Distutils2. This section is shared with Distutils1 +(legacy version distributed in python 2.X standard library). + - **commands**: Defined Distutils2 command. A command is defined by its fully qualified name. @@ -38,13 +49,13 @@ *\*optional* *\*multi* - **compilers**: Defined Distutils2 compiler. A compiler is defined by its fully - qualified name. + qualified name. Example:: [global] compiler = - package.compilers.CustomCCompiler + package.compiler.CustomCCompiler *\*optional* *\*multi* @@ -52,21 +63,29 @@ :file:`setup.cfg` file is read. The callable receives the configuration in form of a mapping and can make some changes to it. *\*optional* + Example:: + + [global] + setup_hook = + distutils2.tests.test_config.hook + metadata ======== The metadata section contains the metadata for the project as described in -PEP 345. +:PEP:`345`. +.. Note:: + Field names are case-insensitive. Fields: - **name**: Name of the project. -- **version**: Version of the project. Must comply with PEP 386. +- **version**: Version of the project. Must comply with :PEP:`386`. - **platform**: Platform specification describing an operating system supported by the distribution which is not listed in the "Operating System" Trove - classifiers. *\*multi* *\*optional* + classifiers (:PEP:`301`). *\*multi* *\*optional* - **supported-platform**: Binary distributions containing a PKG-INFO file will use the Supported-Platform field in their metadata to specify the OS and CPU for which the binary distribution was compiled. The semantics of @@ -113,14 +132,18 @@ name = pypi2rpm version = 0.1 author = Tarek Ziade - author_email = tarek at ziade.org + author-email = tarek at ziade.org summary = Script that transforms a sdist archive into a rpm archive description-file = README - home_page = http://bitbucket.org/tarek/pypi2rpm + home-page = http://bitbucket.org/tarek/pypi2rpm + project-url: RSS feed, https://bitbucket.org/tarek/pypi2rpm/rss classifier = Development Status :: 3 - Alpha License :: OSI Approved :: Mozilla Public License 1.1 (MPL 1.1) +.. Note:: + Some metadata fields seen in :PEP:`345` are automatically generated + (for instance Metadata-Version value). files @@ -148,17 +171,30 @@ extra_files = setup.py + README +.. Note:: + In Distutils2, setup.cfg will be implicitly included. -command sections -================ +.. Warning:: + In Distutils2, setup.py and README (or README.txt) files are not more + included in source distribution by default -Each command can have its options described in :file:`setup.cfg` +`command` sections +================== + +Each Distutils2 command can have its own user options defined in :file:`setup.cfg` Example:: [sdist] - manifest_makers = package.module.Maker + manifest-builders = package.module.Maker +To override the build class in order to generate Python3 code from your Python2 base:: + + [build_py] + use-2to3 = True + + -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:25 +0100 Subject: [Python-checkins] distutils2: Fixing mkcfg conversion if no data_files in setup.py Message-ID: tarek.ziade pushed 201fa9f427bb to distutils2: http://hg.python.org/distutils2/rev/201fa9f427bb changeset: 974:201fa9f427bb parent: 970:e29ec36290b6 user: Andre Espaze date: Sun Jan 30 12:46:59 2011 +0100 summary: Fixing mkcfg conversion if no data_files in setup.py files: distutils2/mkcfg.py diff --git a/distutils2/mkcfg.py b/distutils2/mkcfg.py --- a/distutils2/mkcfg.py +++ b/distutils2/mkcfg.py @@ -266,23 +266,25 @@ data['packages'].extend(dist.packages or []) data['modules'].extend(dist.py_modules or []) # 2.1 data_files -> resources. - if len(dist.data_files) < 2 or isinstance(dist.data_files[1], str): - dist.data_files = [('', dist.data_files)] - #add tokens in the destination paths - vars = {'distribution.name':data['name']} - path_tokens = sysconfig.get_paths(vars=vars).items() - #sort tokens to use the longest one first - path_tokens.sort(cmp=lambda x,y: cmp(len(y), len(x)), - key=lambda x: x[1]) - for dest, srcs in (dist.data_files or []): - dest = os.path.join(sys.prefix, dest) - for tok, path in path_tokens: - if dest.startswith(path): - dest = ('{%s}' % tok) + dest[len(path):] - files = [('/ '.join(src.rsplit('/', 1)), dest) - for src in srcs] - data['resources'].extend(files) - continue + if dist.data_files: + if len(dist.data_files) < 2 or \ + isinstance(dist.data_files[1], str): + dist.data_files = [('', dist.data_files)] + #add tokens in the destination paths + vars = {'distribution.name':data['name']} + path_tokens = sysconfig.get_paths(vars=vars).items() + #sort tokens to use the longest one first + path_tokens.sort(cmp=lambda x,y: cmp(len(y), len(x)), + key=lambda x: x[1]) + for dest, srcs in (dist.data_files or []): + dest = os.path.join(sys.prefix, dest) + for tok, path in path_tokens: + if dest.startswith(path): + dest = ('{%s}' % tok) + dest[len(path):] + files = [('/ '.join(src.rsplit('/', 1)), dest) + for src in srcs] + data['resources'].extend(files) + continue # 2.2 package_data -> extra_files package_dirs = dist.package_dir or {} for package, extras in dist.package_data.iteritems() or []: -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:25 +0100 Subject: [Python-checkins] distutils2: merge Message-ID: tarek.ziade pushed ce8f067c392a to distutils2: http://hg.python.org/distutils2/rev/ce8f067c392a changeset: 975:ce8f067c392a parent: 971:577f6269464e parent: 974:201fa9f427bb user: Alexis Metaireau date: Sun Jan 30 12:53:52 2011 +0100 summary: merge files: diff --git a/distutils2/mkcfg.py b/distutils2/mkcfg.py --- a/distutils2/mkcfg.py +++ b/distutils2/mkcfg.py @@ -266,23 +266,25 @@ data['packages'].extend(dist.packages or []) data['modules'].extend(dist.py_modules or []) # 2.1 data_files -> resources. - if len(dist.data_files) < 2 or isinstance(dist.data_files[1], str): - dist.data_files = [('', dist.data_files)] - #add tokens in the destination paths - vars = {'distribution.name':data['name']} - path_tokens = sysconfig.get_paths(vars=vars).items() - #sort tokens to use the longest one first - path_tokens.sort(cmp=lambda x,y: cmp(len(y), len(x)), - key=lambda x: x[1]) - for dest, srcs in (dist.data_files or []): - dest = os.path.join(sys.prefix, dest) - for tok, path in path_tokens: - if dest.startswith(path): - dest = ('{%s}' % tok) + dest[len(path):] - files = [('/ '.join(src.rsplit('/', 1)), dest) - for src in srcs] - data['resources'].extend(files) - continue + if dist.data_files: + if len(dist.data_files) < 2 or \ + isinstance(dist.data_files[1], str): + dist.data_files = [('', dist.data_files)] + #add tokens in the destination paths + vars = {'distribution.name':data['name']} + path_tokens = sysconfig.get_paths(vars=vars).items() + #sort tokens to use the longest one first + path_tokens.sort(cmp=lambda x,y: cmp(len(y), len(x)), + key=lambda x: x[1]) + for dest, srcs in (dist.data_files or []): + dest = os.path.join(sys.prefix, dest) + for tok, path in path_tokens: + if dest.startswith(path): + dest = ('{%s}' % tok) + dest[len(path):] + files = [('/ '.join(src.rsplit('/', 1)), dest) + for src in srcs] + data['resources'].extend(files) + continue # 2.2 package_data -> extra_files package_dirs = dist.package_dir or {} for package, extras in dist.package_data.iteritems() or []: -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:25 +0100 Subject: [Python-checkins] distutils2: merge with upstream Message-ID: tarek.ziade pushed 69240ad43f64 to distutils2: http://hg.python.org/distutils2/rev/69240ad43f64 changeset: 976:69240ad43f64 parent: 975:ce8f067c392a parent: 973:aaa6cf4324b5 user: Alexis Metaireau date: Sun Jan 30 12:58:44 2011 +0100 summary: merge with upstream files: diff --git a/distutils2/tests/test_install.py b/distutils2/tests/test_install.py --- a/distutils2/tests/test_install.py +++ b/distutils2/tests/test_install.py @@ -75,23 +75,6 @@ return (args, kwargs) in self._called_with -def patch(parent, to_patch): - """monkey match a module""" - def wrapper(func): - print func - print dir(func) - old_func = getattr(parent, to_patch) - def wrapped(*args, **kwargs): - parent.__dict__[to_patch] = MagicMock() - try: - out = func(*args, **kwargs) - finally: - setattr(parent, to_patch, old_func) - return out - return wrapped - return wrapper - - def get_installed_dists(dists): """Return a list of fake installed dists. The list is name, version, deps""" @@ -105,12 +88,6 @@ def _get_client(self, server, *args, **kwargs): return Client(server.full_address, *args, **kwargs) - def _patch_run_install(self): - """Patch run install""" - - def _unpatch_run_install(self): - """Unpatch run install for d2 and d1""" - def _get_results(self, output): """return a list of results""" installed = [(o.name, '%s' % o.version) for o in output['install']] -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:25 +0100 Subject: [Python-checkins] distutils2: added a test for the unpack API Message-ID: tarek.ziade pushed 2b01c666abd7 to distutils2: http://hg.python.org/distutils2/rev/2b01c666abd7 changeset: 977:2b01c666abd7 parent: 967:cc0a674dca07 user: Tarek Ziade date: Sun Jan 30 14:48:53 2011 +0100 summary: added a test for the unpack API files: distutils2/_backport/shutil.py distutils2/index/dist.py distutils2/tests/pypiserver/downloads_with_md5/simple/foobar/foobar-0.1.tar.gz distutils2/tests/test_index_dist.py diff --git a/distutils2/_backport/shutil.py b/distutils2/_backport/shutil.py --- a/distutils2/_backport/shutil.py +++ b/distutils2/_backport/shutil.py @@ -764,3 +764,5 @@ if func is None: raise ValueError('Unknown archive format: %s' % filename) + + return extract_dir diff --git a/distutils2/index/dist.py b/distutils2/index/dist.py --- a/distutils2/index/dist.py +++ b/distutils2/index/dist.py @@ -149,6 +149,16 @@ dist = self.dists.values()[0] return dist + def unpack(self, path=None, prefer_source=True): + """Unpack the distribution to the given path. + + If not destination is given, creates a temporary location. + + Returns the location of the extracted files (root). + """ + return self.get_distribution(prefer_source=prefer_source)\ + .unpack(path=path) + def download(self, temp_path=None, prefer_source=True): """Download the distribution, using the requirements. @@ -312,7 +322,7 @@ if path is None: path = tempfile.mkdtemp() - filename = self.download() + filename = self.download(path) content_type = mimetypes.guess_type(filename)[0] self._unpacked_dir = unpack_archive(filename) @@ -332,8 +342,11 @@ % (hashval.hexdigest(), expected_hashval)) def __repr__(self): + if self.release is None: + return "" % self.dist_type + return "<%s %s %s>" % ( - self.release.name, self.release.version, self.dist_type or "") + self.release.name, self.release.version, self.dist_type or "") class ReleasesList(IndexReference): diff --git a/distutils2/tests/pypiserver/downloads_with_md5/simple/foobar/foobar-0.1.tar.gz b/distutils2/tests/pypiserver/downloads_with_md5/simple/foobar/foobar-0.1.tar.gz index 0000000000000000000000000000000000000000..333961eb18a6e7db80fefd41c339ab218d5180c4 GIT binary patch literal 110 zc$|~(=3uy!>FUeC{PvtR-ysJc)&sVu?9yZ7`(A1Di)P(6s!I71JWZ;--fWND`LA)=lAmk-7Jbj=XMlnFEsQ#U Kd|Vkc7#IK&xGYxy diff --git a/distutils2/tests/test_index_dist.py b/distutils2/tests/test_index_dist.py --- a/distutils2/tests/test_index_dist.py +++ b/distutils2/tests/test_index_dist.py @@ -127,7 +127,7 @@ url = "%s/simple/foobar/foobar-0.1.tar.gz" % server.full_address # check md5 if given dist = Dist(url=url, hashname="md5", - hashval="d41d8cd98f00b204e9800998ecf8427e") + hashval="fe18804c5b722ff024cabdf514924fc4") dist.download(self.mkdtemp()) # a wrong md5 fails @@ -157,6 +157,24 @@ hashname="invalid_hashname", hashval="value") + @use_pypi_server('downloads_with_md5') + def test_unpack(self, server): + url = "%s/simple/foobar/foobar-0.1.tar.gz" % server.full_address + dist = Dist(url=url) + # doing an unpack + here = self.mkdtemp() + there = dist.unpack(here) + result = os.listdir(there) + self.assertIn('paf', result) + + def test_hashname(self): + # Invalid hashnames raises an exception on assignation + Dist(hashname="md5", hashval="value") + + self.assertRaises(UnsupportedHashName, Dist, + hashname="invalid_hashname", + hashval="value") + class TestReleasesList(unittest.TestCase): -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:25 +0100 Subject: [Python-checkins] distutils2: merged Message-ID: tarek.ziade pushed 301ad616c208 to distutils2: http://hg.python.org/distutils2/rev/301ad616c208 changeset: 978:301ad616c208 tag: tip parent: 977:2b01c666abd7 parent: 976:69240ad43f64 user: Tarek Ziade date: Sun Jan 30 14:49:01 2011 +0100 summary: merged files: diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -922,10 +922,6 @@ for field in ('Obsoletes', 'Requires', 'Provides'): del self.metadata[field] - provides = "%s (%s)" % (self.metadata['name'], - self.metadata['version']) - self.metadata['Provides-Dist'] += (provides,) - reqs = [] if requires is not None: diff --git a/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO b/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO new file mode 100644 --- /dev/null +++ b/distutils2/_backport/tests/fake_dists/coconuts-aster-10.3.egg-info/PKG-INFO @@ -0,0 +1,5 @@ +Metadata-Version: 1.2 +Name: coconuts-aster +Version: 10.3 +Provides-Dist: strawberry (0.6) +Provides-Dist: banana (0.4) diff --git a/distutils2/_backport/tests/test_pkgutil.py b/distutils2/_backport/tests/test_pkgutil.py --- a/distutils2/_backport/tests/test_pkgutil.py +++ b/distutils2/_backport/tests/test_pkgutil.py @@ -389,6 +389,7 @@ # Now, test if the egg-info distributions are found correctly as well fake_dists += [('bacon', '0.1'), ('cheese', '2.0.2'), + ('coconuts-aster', '10.3'), ('banana', '0.4'), ('strawberry', '0.6'), ('truffles', '5.0'), ('nut', 'funkyversion')] found_dists = [] @@ -494,18 +495,18 @@ l = [dist.name for dist in provides_distribution('truffles', '>1.5', use_egg_info=True)] - checkLists(l, ['bacon', 'truffles']) + checkLists(l, ['bacon']) l = [dist.name for dist in provides_distribution('truffles', '>=1.0')] checkLists(l, ['choxie', 'towel-stuff']) l = [dist.name for dist in provides_distribution('strawberry', '0.6', use_egg_info=True)] - checkLists(l, ['strawberry']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('strawberry', '>=0.5', use_egg_info=True)] - checkLists(l, ['strawberry']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('strawberry', '>0.6', use_egg_info=True)] @@ -513,11 +514,11 @@ l = [dist.name for dist in provides_distribution('banana', '0.4', use_egg_info=True)] - checkLists(l, ['banana']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('banana', '>=0.3', use_egg_info=True)] - checkLists(l, ['banana']) + checkLists(l, ['coconuts-aster']) l = [dist.name for dist in provides_distribution('banana', '!=0.4', use_egg_info=True)] @@ -557,7 +558,7 @@ eggs = [('bacon', '0.1'), ('banana', '0.4'), ('strawberry', '0.6'), ('truffles', '5.0'), ('cheese', '2.0.2'), - ('nut', 'funkyversion')] + ('coconuts-aster', '10.3'), ('nut', 'funkyversion')] dists = [('choxie', '2.0.0.9'), ('grammar', '1.0a4'), ('towel-stuff', '0.1')] diff --git a/distutils2/config.py b/distutils2/config.py --- a/distutils2/config.py +++ b/distutils2/config.py @@ -6,6 +6,7 @@ import re import sys from ConfigParser import RawConfigParser +from shlex import split from distutils2 import logger from distutils2.errors import DistutilsOptionError @@ -17,15 +18,9 @@ def _pop_values(values_dct, key): """Remove values from the dictionary and convert them as a list""" - vals_str = values_dct.pop(key, None) - if not vals_str: - return + vals_str = values_dct.pop(key, '') # Get bash options like `gcc -print-file-name=libgcc.a` - vals = re.search('(`.*?`)', vals_str) or [] - if vals: - vals = list(vals.groups()) - vals_str = re.sub('`.*?`', '', vals_str) - vals.extend(vals_str.split()) + vals = split(vals_str) if vals: return vals diff --git a/distutils2/mkcfg.py b/distutils2/mkcfg.py --- a/distutils2/mkcfg.py +++ b/distutils2/mkcfg.py @@ -266,23 +266,25 @@ data['packages'].extend(dist.packages or []) data['modules'].extend(dist.py_modules or []) # 2.1 data_files -> resources. - if len(dist.data_files) < 2 or isinstance(dist.data_files[1], str): - dist.data_files = [('', dist.data_files)] - #add tokens in the destination paths - vars = {'distribution.name':data['name']} - path_tokens = sysconfig.get_paths(vars=vars).items() - #sort tokens to use the longest one first - path_tokens.sort(cmp=lambda x,y: cmp(len(y), len(x)), - key=lambda x: x[1]) - for dest, srcs in (dist.data_files or []): - dest = os.path.join(sys.prefix, dest) - for tok, path in path_tokens: - if dest.startswith(path): - dest = ('{%s}' % tok) + dest[len(path):] - files = [('/ '.join(src.rsplit('/', 1)), dest) - for src in srcs] - data['resources'].extend(files) - continue + if dist.data_files: + if len(dist.data_files) < 2 or \ + isinstance(dist.data_files[1], str): + dist.data_files = [('', dist.data_files)] + #add tokens in the destination paths + vars = {'distribution.name':data['name']} + path_tokens = sysconfig.get_paths(vars=vars).items() + #sort tokens to use the longest one first + path_tokens.sort(cmp=lambda x,y: cmp(len(y), len(x)), + key=lambda x: x[1]) + for dest, srcs in (dist.data_files or []): + dest = os.path.join(sys.prefix, dest) + for tok, path in path_tokens: + if dest.startswith(path): + dest = ('{%s}' % tok) + dest[len(path):] + files = [('/ '.join(src.rsplit('/', 1)), dest) + for src in srcs] + data['resources'].extend(files) + continue # 2.2 package_data -> extra_files package_dirs = dist.package_dir or {} for package, extras in dist.package_data.iteritems() or []: diff --git a/distutils2/tests/test_config.py b/distutils2/tests/test_config.py --- a/distutils2/tests/test_config.py +++ b/distutils2/tests/test_config.py @@ -103,7 +103,7 @@ [extension=speed_coconuts] name = one.speed_coconuts sources = c_src/speed_coconuts.c -extra_link_args = `gcc -print-file-name=libgcc.a` -shared +extra_link_args = "`gcc -print-file-name=libgcc.a`" -shared define_macros = HAVE_CAIRO HAVE_GTK2 [extension=fast_taunt] diff --git a/distutils2/tests/test_install.py b/distutils2/tests/test_install.py --- a/distutils2/tests/test_install.py +++ b/distutils2/tests/test_install.py @@ -75,23 +75,6 @@ return (args, kwargs) in self._called_with -def patch(parent, to_patch): - """monkey match a module""" - def wrapper(func): - print func - print dir(func) - old_func = getattr(parent, to_patch) - def wrapped(*args, **kwargs): - parent.__dict__[to_patch] = MagicMock() - try: - out = func(*args, **kwargs) - finally: - setattr(parent, to_patch, old_func) - return out - return wrapped - return wrapper - - def get_installed_dists(dists): """Return a list of fake installed dists. The list is name, version, deps""" @@ -105,12 +88,6 @@ def _get_client(self, server, *args, **kwargs): return Client(server.full_address, *args, **kwargs) - def _patch_run_install(self): - """Patch run install""" - - def _unpatch_run_install(self): - """Unpatch run install for d2 and d1""" - def _get_results(self, output): """return a list of results""" installed = [(o.name, '%s' % o.version) for o in output['install']] diff --git a/docs/design/configfile.rst b/docs/design/configfile.rst new file mode 100644 --- /dev/null +++ b/docs/design/configfile.rst @@ -0,0 +1,132 @@ +.. _setup-config: + +************************************ +Writing the Setup Configuration File +************************************ + +Often, it's not possible to write down everything needed to build a distribution +*a priori*: you may need to get some information from the user, or from the +user's system, in order to proceed. As long as that information is fairly +simple---a list of directories to search for C header files or libraries, for +example---then providing a configuration file, :file:`setup.cfg`, for users to +edit is a cheap and easy way to solicit it. Configuration files also let you +provide default values for any command option, which the installer can then +override either on the command line or by editing the config file. + +The setup configuration file is a useful middle-ground between the setup script +---which, ideally, would be opaque to installers [#]_---and the command line to +the setup script, which is outside of your control and entirely up to the +installer. In fact, :file:`setup.cfg` (and any other Distutils configuration +files present on the target system) are processed after the contents of the +setup script, but before the command line. This has several useful +consequences: + +.. If you have more advanced needs, such as determining which extensions to + build based on what capabilities are present on the target system, then you + need the Distutils auto-configuration facility. This started to appear in + Distutils 0.9 but, as of this writing, isn't mature or stable enough yet + for real-world use. + +* installers can override some of what you put in :file:`setup.py` by editing + :file:`setup.cfg` + +* you can provide non-standard defaults for options that are not easily set in + :file:`setup.py` + +* installers can override anything in :file:`setup.cfg` using the command-line + options to :file:`setup.py` + +The basic syntax of the configuration file is simple:: + + [command] + option=value + ... + +where *command* is one of the Distutils commands (e.g. :command:`build_py`, +:command:`install`), and *option* is one of the options that command supports. +Any number of options can be supplied for each command, and any number of +command sections can be included in the file. Blank lines are ignored, as are +comments, which run from a ``'#'`` character until the end of the line. Long +option values can be split across multiple lines simply by indenting the +continuation lines. + +You can find out the list of options supported by a particular command with the +universal :option:`--help` option, e.g. :: + + > python setup.py --help build_ext + [...] + Options for 'build_ext' command: + --build-lib (-b) directory for compiled extension modules + --build-temp (-t) directory for temporary files (build by-products) + --inplace (-i) ignore build-lib and put compiled extensions into the + source directory alongside your pure Python modules + --include-dirs (-I) list of directories to search for header files + --define (-D) C preprocessor macros to define + --undef (-U) C preprocessor macros to undefine + --swig-opts list of SWIG command-line options + [...] + +.. XXX do we want to support ``setup.py --help metadata``? + +Note that an option spelled :option:`--foo-bar` on the command line is spelled +:option:`foo_bar` in configuration files. + +For example, say you want your extensions to be built "in-place"---that is, you +have an extension :mod:`pkg.ext`, and you want the compiled extension file +(:file:`ext.so` on Unix, say) to be put in the same source directory as your +pure Python modules :mod:`pkg.mod1` and :mod:`pkg.mod2`. You can always use the +:option:`--inplace` option on the command line to ensure this:: + + python setup.py build_ext --inplace + +But this requires that you always specify the :command:`build_ext` command +explicitly, and remember to provide :option:`--inplace`. An easier way is to +"set and forget" this option, by encoding it in :file:`setup.cfg`, the +configuration file for this distribution:: + + [build_ext] + inplace=1 + +This will affect all builds of this module distribution, whether or not you +explicitly specify :command:`build_ext`. If you include :file:`setup.cfg` in +your source distribution, it will also affect end-user builds---which is +probably a bad idea for this option, since always building extensions in-place +would break installation of the module distribution. In certain peculiar cases, +though, modules are built right in their installation directory, so this is +conceivably a useful ability. (Distributing extensions that expect to be built +in their installation directory is almost always a bad idea, though.) + +Another example: certain commands take a lot of options that don't change from +run to run; for example, :command:`bdist_rpm` needs to know everything required +to generate a "spec" file for creating an RPM distribution. Some of this +information comes from the setup script, and some is automatically generated by +the Distutils (such as the list of files installed). But some of it has to be +supplied as options to :command:`bdist_rpm`, which would be very tedious to do +on the command line for every run. Hence, here is a snippet from the Distutils' +own :file:`setup.cfg`:: + + [bdist_rpm] + release = 1 + packager = Greg Ward + doc_files = CHANGES.txt + README.txt + USAGE.txt + doc/ + examples/ + +Note that the :option:`doc_files` option is simply a whitespace-separated string +split across multiple lines for readability. + + +.. seealso:: + + :ref:`inst-config-syntax` in "Installing Python Modules" + More information on the configuration files is available in the manual for + system administrators. + + +.. rubric:: Footnotes + +.. [#] This ideal probably won't be achieved until auto-configuration is fully + supported by the Distutils. + -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 14:49:23 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 14:49:23 +0100 Subject: [Python-checkins] distutils2: fixed bad merge Message-ID: tarek.ziade pushed cc0a674dca07 to distutils2: http://hg.python.org/distutils2/rev/cc0a674dca07 changeset: 967:cc0a674dca07 user: Tarek Ziade date: Sun Jan 30 12:02:03 2011 +0100 summary: fixed bad merge files: distutils2/_backport/shutil.py diff --git a/distutils2/_backport/shutil.py b/distutils2/_backport/shutil.py --- a/distutils2/_backport/shutil.py +++ b/distutils2/_backport/shutil.py @@ -742,6 +742,8 @@ if extract_dir is None: extract_dir = os.getcwd() + func = None + if format is not None: try: format_info = _UNPACK_FORMATS[format] @@ -758,4 +760,7 @@ func = _UNPACK_FORMATS[format][1] kwargs = dict(_UNPACK_FORMATS[format][2]) - raise ValueError('Unknown archive format: %s' % filename) + func(filename, extract_dir, **kwargs) + + if func is None: + raise ValueError('Unknown archive format: %s' % filename) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 15:00:32 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 30 Jan 2011 15:00:32 +0100 (CET) Subject: [Python-checkins] r88264 - python/branches/py3k/Lib/pydoc_data/topics.py Message-ID: <20110130140032.B943FD435@mail.python.org> Author: georg.brandl Date: Sun Jan 30 15:00:32 2011 New Revision: 88264 Log: Update pydoc topics. Modified: python/branches/py3k/Lib/pydoc_data/topics.py Modified: python/branches/py3k/Lib/pydoc_data/topics.py ============================================================================== --- python/branches/py3k/Lib/pydoc_data/topics.py (original) +++ python/branches/py3k/Lib/pydoc_data/topics.py Sun Jan 30 15:00:32 2011 @@ -1,4 +1,4 @@ -# Autogenerated by Sphinx on Sat Jan 15 17:39:45 2011 +# Autogenerated by Sphinx on Sun Jan 30 14:58:50 2011 topics = {'assert': '\nThe ``assert`` statement\n************************\n\nAssert statements are a convenient way to insert debugging assertions\ninto a program:\n\n assert_stmt ::= "assert" expression ["," expression]\n\nThe simple form, ``assert expression``, is equivalent to\n\n if __debug__:\n if not expression: raise AssertionError\n\nThe extended form, ``assert expression1, expression2``, is equivalent\nto\n\n if __debug__:\n if not expression1: raise AssertionError(expression2)\n\nThese equivalences assume that ``__debug__`` and ``AssertionError``\nrefer to the built-in variables with those names. In the current\nimplementation, the built-in variable ``__debug__`` is ``True`` under\nnormal circumstances, ``False`` when optimization is requested\n(command line option -O). The current code generator emits no code\nfor an assert statement when optimization is requested at compile\ntime. Note that it is unnecessary to include the source code for the\nexpression that failed in the error message; it will be displayed as\npart of the stack trace.\n\nAssignments to ``__debug__`` are illegal. The value for the built-in\nvariable is determined when the interpreter starts.\n', 'assignment': '\nAssignment statements\n*********************\n\nAssignment statements are used to (re)bind names to values and to\nmodify attributes or items of mutable objects:\n\n assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)\n target_list ::= target ("," target)* [","]\n target ::= identifier\n | "(" target_list ")"\n | "[" target_list "]"\n | attributeref\n | subscription\n | slicing\n | "*" target\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn assignment statement evaluates the expression list (remember that\nthis can be a single expression or a comma-separated list, the latter\nyielding a tuple) and assigns the single resulting object to each of\nthe target lists, from left to right.\n\nAssignment is defined recursively depending on the form of the target\n(list). When a target is part of a mutable object (an attribute\nreference, subscription or slicing), the mutable object must\nultimately perform the assignment and decide about its validity, and\nmay raise an exception if the assignment is unacceptable. The rules\nobserved by various types and the exceptions raised are given with the\ndefinition of the object types (see section *The standard type\nhierarchy*).\n\nAssignment of an object to a target list, optionally enclosed in\nparentheses or square brackets, is recursively defined as follows.\n\n* If the target list is a single target: The object is assigned to\n that target.\n\n* If the target list is a comma-separated list of targets: The object\n must be an iterable with the same number of items as there are\n targets in the target list, and the items are assigned, from left to\n right, to the corresponding targets. (This rule is relaxed as of\n Python 1.5; in earlier versions, the object had to be a tuple.\n Since strings are sequences, an assignment like ``a, b = "xy"`` is\n now legal as long as the string has the right length.)\n\n * If the target list contains one target prefixed with an asterisk,\n called a "starred" target: The object must be a sequence with at\n least as many items as there are targets in the target list, minus\n one. The first items of the sequence are assigned, from left to\n right, to the targets before the starred target. The final items\n of the sequence are assigned to the targets after the starred\n target. A list of the remaining items in the sequence is then\n assigned to the starred target (the list can be empty).\n\n * Else: The object must be a sequence with the same number of items\n as there are targets in the target list, and the items are\n assigned, from left to right, to the corresponding targets.\n\nAssignment of an object to a single target is recursively defined as\nfollows.\n\n* If the target is an identifier (name):\n\n * If the name does not occur in a ``global`` or ``nonlocal``\n statement in the current code block: the name is bound to the\n object in the current local namespace.\n\n * Otherwise: the name is bound to the object in the global namespace\n or the outer namespace determined by ``nonlocal``, respectively.\n\n The name is rebound if it was already bound. This may cause the\n reference count for the object previously bound to the name to reach\n zero, causing the object to be deallocated and its destructor (if it\n has one) to be called.\n\n* If the target is a target list enclosed in parentheses or in square\n brackets: The object must be an iterable with the same number of\n items as there are targets in the target list, and its items are\n assigned, from left to right, to the corresponding targets.\n\n* If the target is an attribute reference: The primary expression in\n the reference is evaluated. It should yield an object with\n assignable attributes; if this is not the case, ``TypeError`` is\n raised. That object is then asked to assign the assigned object to\n the given attribute; if it cannot perform the assignment, it raises\n an exception (usually but not necessarily ``AttributeError``).\n\n Note: If the object is a class instance and the attribute reference\n occurs on both sides of the assignment operator, the RHS expression,\n ``a.x`` can access either an instance attribute or (if no instance\n attribute exists) a class attribute. The LHS target ``a.x`` is\n always set as an instance attribute, creating it if necessary.\n Thus, the two occurrences of ``a.x`` do not necessarily refer to the\n same attribute: if the RHS expression refers to a class attribute,\n the LHS creates a new instance attribute as the target of the\n assignment:\n\n class Cls:\n x = 3 # class variable\n inst = Cls()\n inst.x = inst.x + 1 # writes inst.x as 4 leaving Cls.x as 3\n\n This description does not necessarily apply to descriptor\n attributes, such as properties created with ``property()``.\n\n* If the target is a subscription: The primary expression in the\n reference is evaluated. It should yield either a mutable sequence\n object (such as a list) or a mapping object (such as a dictionary).\n Next, the subscript expression is evaluated.\n\n If the primary is a mutable sequence object (such as a list), the\n subscript must yield an integer. If it is negative, the sequence\'s\n length is added to it. The resulting value must be a nonnegative\n integer less than the sequence\'s length, and the sequence is asked\n to assign the assigned object to its item with that index. If the\n index is out of range, ``IndexError`` is raised (assignment to a\n subscripted sequence cannot add new items to a list).\n\n If the primary is a mapping object (such as a dictionary), the\n subscript must have a type compatible with the mapping\'s key type,\n and the mapping is then asked to create a key/datum pair which maps\n the subscript to the assigned object. This can either replace an\n existing key/value pair with the same key value, or insert a new\n key/value pair (if no key with the same value existed).\n\n For user-defined objects, the ``__setitem__()`` method is called\n with appropriate arguments.\n\n* If the target is a slicing: The primary expression in the reference\n is evaluated. It should yield a mutable sequence object (such as a\n list). The assigned object should be a sequence object of the same\n type. Next, the lower and upper bound expressions are evaluated,\n insofar they are present; defaults are zero and the sequence\'s\n length. The bounds should evaluate to integers. If either bound is\n negative, the sequence\'s length is added to it. The resulting\n bounds are clipped to lie between zero and the sequence\'s length,\n inclusive. Finally, the sequence object is asked to replace the\n slice with the items of the assigned sequence. The length of the\n slice may be different from the length of the assigned sequence,\n thus changing the length of the target sequence, if the object\n allows it.\n\n**CPython implementation detail:** In the current implementation, the\nsyntax for targets is taken to be the same as for expressions, and\ninvalid syntax is rejected during the code generation phase, causing\nless detailed error messages.\n\nWARNING: Although the definition of assignment implies that overlaps\nbetween the left-hand side and the right-hand side are \'safe\' (for\nexample ``a, b = b, a`` swaps two variables), overlaps *within* the\ncollection of assigned-to variables are not safe! For instance, the\nfollowing program prints ``[0, 2]``:\n\n x = [0, 1]\n i = 0\n i, x[i] = 1, 2\n print(x)\n\nSee also:\n\n **PEP 3132** - Extended Iterable Unpacking\n The specification for the ``*target`` feature.\n\n\nAugmented assignment statements\n===============================\n\nAugmented assignment is the combination, in a single statement, of a\nbinary operation and an assignment statement:\n\n augmented_assignment_stmt ::= augtarget augop (expression_list | yield_expression)\n augtarget ::= identifier | attributeref | subscription | slicing\n augop ::= "+=" | "-=" | "*=" | "/=" | "//=" | "%=" | "**="\n | ">>=" | "<<=" | "&=" | "^=" | "|="\n\n(See section *Primaries* for the syntax definitions for the last three\nsymbols.)\n\nAn augmented assignment evaluates the target (which, unlike normal\nassignment statements, cannot be an unpacking) and the expression\nlist, performs the binary operation specific to the type of assignment\non the two operands, and assigns the result to the original target.\nThe target is only evaluated once.\n\nAn augmented assignment expression like ``x += 1`` can be rewritten as\n``x = x + 1`` to achieve a similar, but not exactly equal effect. In\nthe augmented version, ``x`` is only evaluated once. Also, when\npossible, the actual operation is performed *in-place*, meaning that\nrather than creating a new object and assigning that to the target,\nthe old object is modified instead.\n\nWith the exception of assigning to tuples and multiple targets in a\nsingle statement, the assignment done by augmented assignment\nstatements is handled the same way as normal assignments. Similarly,\nwith the exception of the possible *in-place* behavior, the binary\noperation performed by augmented assignment is the same as the normal\nbinary operations.\n\nFor targets which are attribute references, the same *caveat about\nclass and instance attributes* applies as for regular assignments.\n', 'atom-identifiers': '\nIdentifiers (Names)\n*******************\n\nAn identifier occurring as an atom is a name. See section\n*Identifiers and keywords* for lexical definition and section *Naming\nand binding* for documentation of naming and binding.\n\nWhen the name is bound to an object, evaluation of the atom yields\nthat object. When a name is not bound, an attempt to evaluate it\nraises a ``NameError`` exception.\n\n**Private name mangling:** When an identifier that textually occurs in\na class definition begins with two or more underscore characters and\ndoes not end in two or more underscores, it is considered a *private\nname* of that class. Private names are transformed to a longer form\nbefore code is generated for them. The transformation inserts the\nclass name in front of the name, with leading underscores removed, and\na single underscore inserted in front of the class name. For example,\nthe identifier ``__spam`` occurring in a class named ``Ham`` will be\ntransformed to ``_Ham__spam``. This transformation is independent of\nthe syntactical context in which the identifier is used. If the\ntransformed name is extremely long (longer than 255 characters),\nimplementation defined truncation may happen. If the class name\nconsists only of underscores, no transformation is done.\n', From python-checkins at python.org Sun Jan 30 15:02:36 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 30 Jan 2011 15:02:36 +0100 (CET) Subject: [Python-checkins] r88265 - python/branches/py3k/Doc/tools/sphinxext/susp-ignored.csv Message-ID: <20110130140236.7558FD39B@mail.python.org> Author: georg.brandl Date: Sun Jan 30 15:02:36 2011 New Revision: 88265 Log: Update suspicious ignore file. Modified: python/branches/py3k/Doc/tools/sphinxext/susp-ignored.csv Modified: python/branches/py3k/Doc/tools/sphinxext/susp-ignored.csv ============================================================================== --- python/branches/py3k/Doc/tools/sphinxext/susp-ignored.csv (original) +++ python/branches/py3k/Doc/tools/sphinxext/susp-ignored.csv Sun Jan 30 15:02:36 2011 @@ -365,3 +365,21 @@ howto/logging,,:logger,severity:logger name:message howto/logging,,:message,severity:logger name:message library/logging.handlers,,:port,host:port +documenting/markup,613,`,:ref:`link text ` +library/imaplib,116,:MM,"""DD-Mmm-YYYY HH:MM:SS" +library/imaplib,116,:SS,"""DD-Mmm-YYYY HH:MM:SS" +whatsnew/3.2,573,::,"$ export PYTHONWARNINGS='ignore::RuntimeWarning::,once::UnicodeWarning::'" +whatsnew/3.2,1374,:gz,">>> with tarfile.open(name='myarchive.tar.gz', mode='w:gz') as tf:" +whatsnew/3.2,2061,:directory,${buildout:directory}/downloads/dist +whatsnew/3.2,2061,:location,zope9-location = ${zope9:location} +whatsnew/3.2,2061,:prefix,zope-conf = ${custom:prefix}/etc/zope.conf +whatsnew/3.2,2102,:beef,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,2102,:cafe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,2102,:affe,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,2102,:deaf,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,2102,:feed,>>> urllib.parse.urlparse('http://[dead:beef:cafe:5417:affe:8FA3:deaf:feed]/foo/') +whatsnew/3.2,2102,:beef,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,2102,:cafe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,2102,:affe,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,2102,:deaf,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," +whatsnew/3.2,2102,:feed,"netloc='[dead:beef:cafe:5417:affe:8FA3:deaf:feed]'," From python-checkins at python.org Sun Jan 30 15:03:34 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 30 Jan 2011 15:03:34 +0100 (CET) Subject: [Python-checkins] r88266 - in python/branches/py3k: Include/patchlevel.h Lib/distutils/__init__.py Lib/idlelib/idlever.py Misc/NEWS Misc/RPM/python-3.2.spec README Message-ID: <20110130140334.2D792D39B@mail.python.org> Author: georg.brandl Date: Sun Jan 30 15:03:33 2011 New Revision: 88266 Log: Bump version. Modified: python/branches/py3k/Include/patchlevel.h python/branches/py3k/Lib/distutils/__init__.py python/branches/py3k/Lib/idlelib/idlever.py python/branches/py3k/Misc/NEWS python/branches/py3k/Misc/RPM/python-3.2.spec python/branches/py3k/README Modified: python/branches/py3k/Include/patchlevel.h ============================================================================== --- python/branches/py3k/Include/patchlevel.h (original) +++ python/branches/py3k/Include/patchlevel.h Sun Jan 30 15:03:33 2011 @@ -20,10 +20,10 @@ #define PY_MINOR_VERSION 2 #define PY_MICRO_VERSION 0 #define PY_RELEASE_LEVEL PY_RELEASE_LEVEL_GAMMA -#define PY_RELEASE_SERIAL 1 +#define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.2rc1+" +#define PY_VERSION "3.2rc2" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository) */ Modified: python/branches/py3k/Lib/distutils/__init__.py ============================================================================== --- python/branches/py3k/Lib/distutils/__init__.py (original) +++ python/branches/py3k/Lib/distutils/__init__.py Sun Jan 30 15:03:33 2011 @@ -15,5 +15,5 @@ # Updated automatically by the Python release process. # #--start constants-- -__version__ = "3.2rc1" +__version__ = "3.2rc2" #--end constants-- Modified: python/branches/py3k/Lib/idlelib/idlever.py ============================================================================== --- python/branches/py3k/Lib/idlelib/idlever.py (original) +++ python/branches/py3k/Lib/idlelib/idlever.py Sun Jan 30 15:03:33 2011 @@ -1 +1 @@ -IDLE_VERSION = "3.2rc1" +IDLE_VERSION = "3.2rc2" Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Sun Jan 30 15:03:33 2011 @@ -5,7 +5,7 @@ What's New in Python 3.2 Release Candidate 2? ============================================= -*Release date: XX-Jan-2011* +*Release date: 30-Jan-2011* Core and Builtins ----------------- Modified: python/branches/py3k/Misc/RPM/python-3.2.spec ============================================================================== --- python/branches/py3k/Misc/RPM/python-3.2.spec (original) +++ python/branches/py3k/Misc/RPM/python-3.2.spec Sun Jan 30 15:03:33 2011 @@ -39,7 +39,7 @@ %define name python #--start constants-- -%define version 3.2rc1 +%define version 3.2rc2 %define libvers 3.2 #--end constants-- %define release 1pydotorg Modified: python/branches/py3k/README ============================================================================== --- python/branches/py3k/README (original) +++ python/branches/py3k/README Sun Jan 30 15:03:33 2011 @@ -1,4 +1,4 @@ -This is Python version 3.2, release candidate 1 +This is Python version 3.2, release candidate 2 =============================================== Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 From python-checkins at python.org Sun Jan 30 15:05:04 2011 From: python-checkins at python.org (georg.brandl) Date: Sun, 30 Jan 2011 15:05:04 +0100 (CET) Subject: [Python-checkins] r88267 - python/tags/r32rc2 Message-ID: <20110130140505.21E69EE989@mail.python.org> Author: georg.brandl Date: Sun Jan 30 15:05:04 2011 New Revision: 88267 Log: Tagging release 3.2 rc 2. Added: python/tags/r32rc2/ - copied from r88266, /python/branches/py3k/ From python-checkins at python.org Sun Jan 30 15:05:38 2011 From: python-checkins at python.org (steven.bethard) Date: Sun, 30 Jan 2011 15:05:38 +0100 (CET) Subject: [Python-checkins] r88268 - in python/branches/release27-maint/Lib: argparse.py test/test_argparse.py Message-ID: <20110130140538.61318D435@mail.python.org> Author: steven.bethard Date: Sun Jan 30 15:05:38 2011 New Revision: 88268 Log: #10680: fix mutually exclusive arguments in argument groups. Modified: python/branches/release27-maint/Lib/argparse.py python/branches/release27-maint/Lib/test/test_argparse.py Modified: python/branches/release27-maint/Lib/argparse.py ============================================================================== --- python/branches/release27-maint/Lib/argparse.py (original) +++ python/branches/release27-maint/Lib/argparse.py Sun Jan 30 15:05:38 2011 @@ -1482,6 +1482,7 @@ self._defaults = container._defaults self._has_negative_number_optionals = \ container._has_negative_number_optionals + self._mutually_exclusive_groups = container._mutually_exclusive_groups def _add_action(self, action): action = super(_ArgumentGroup, self)._add_action(action) Modified: python/branches/release27-maint/Lib/test/test_argparse.py ============================================================================== --- python/branches/release27-maint/Lib/test/test_argparse.py (original) +++ python/branches/release27-maint/Lib/test/test_argparse.py Sun Jan 30 15:05:38 2011 @@ -2505,6 +2505,46 @@ ''' +class TestMutuallyExclusiveInGroup(MEMixin, TestCase): + + def get_parser(self, required=None): + parser = ErrorRaisingArgumentParser(prog='PROG') + titled_group = parser.add_argument_group( + title='Titled group', description='Group description') + mutex_group = \ + titled_group.add_mutually_exclusive_group(required=required) + mutex_group.add_argument('--bar', help='bar help') + mutex_group.add_argument('--baz', help='baz help') + return parser + + failures = ['--bar X --baz Y', '--baz X --bar Y'] + successes = [ + ('--bar X', NS(bar='X', baz=None)), + ('--baz Y', NS(bar=None, baz='Y')), + ] + successes_when_not_required = [ + ('', NS(bar=None, baz=None)), + ] + + usage_when_not_required = '''\ + usage: PROG [-h] [--bar BAR | --baz BAZ] + ''' + usage_when_required = '''\ + usage: PROG [-h] (--bar BAR | --baz BAZ) + ''' + help = '''\ + + optional arguments: + -h, --help show this help message and exit + + Titled group: + Group description + + --bar BAR bar help + --baz BAZ baz help + ''' + + class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase): def get_parser(self, required): From python-checkins at python.org Sun Jan 30 15:12:28 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 15:12:28 +0100 Subject: [Python-checkins] distutils2: removing paf file Message-ID: tarek.ziade pushed 7bec701455f1 to distutils2: http://hg.python.org/distutils2/rev/7bec701455f1 changeset: 979:7bec701455f1 tag: tip user: Tarek Ziade date: Sun Jan 30 15:12:22 2011 +0100 summary: removing paf file files: distutils2/tests/test_index_dist.py diff --git a/distutils2/tests/test_index_dist.py b/distutils2/tests/test_index_dist.py --- a/distutils2/tests/test_index_dist.py +++ b/distutils2/tests/test_index_dist.py @@ -166,6 +166,7 @@ there = dist.unpack(here) result = os.listdir(there) self.assertIn('paf', result) + os.remove('paf') def test_hashname(self): # Invalid hashnames raises an exception on assignation -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 15:20:15 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 15:20:15 +0100 Subject: [Python-checkins] distutils2: reintroduced any (used by python2.4) Message-ID: tarek.ziade pushed e7d29219343d to distutils2: http://hg.python.org/distutils2/rev/e7d29219343d changeset: 980:e7d29219343d tag: tip user: Tarek Ziade date: Sun Jan 30 15:20:08 2011 +0100 summary: reintroduced any (used by python2.4) files: distutils2/_backport/__init__.py diff --git a/distutils2/_backport/__init__.py b/distutils2/_backport/__init__.py --- a/distutils2/_backport/__init__.py +++ b/distutils2/_backport/__init__.py @@ -1,2 +1,8 @@ """Things that will land in the Python 3.3 std lib but which we must drag along -with us for now to support 2.x.""" + us for now to support 2.x.""" + +def any(seq): + for elem in seq: + if elem: + return True + return False -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 15:29:35 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 15:29:35 +0100 Subject: [Python-checkins] distutils2: fix mkcfg for python 2.4 (provides/obsoletes/requires) Message-ID: tarek.ziade pushed 93d7c64c7a67 to distutils2: http://hg.python.org/distutils2/rev/93d7c64c7a67 changeset: 981:93d7c64c7a67 tag: tip user: Tarek Ziade date: Sun Jan 30 15:29:30 2011 +0100 summary: fix mkcfg for python 2.4 (provides/obsoletes/requires) files: distutils2/mkcfg.py diff --git a/distutils2/mkcfg.py b/distutils2/mkcfg.py --- a/distutils2/mkcfg.py +++ b/distutils2/mkcfg.py @@ -254,10 +254,12 @@ ('description', 'summary'), ('long_description', 'description'), ('url', 'home_page'), - ('platforms', 'platform'), - ('provides', 'provides-dist'), - ('obsoletes', 'obsoletes-dist'), - ('requires', 'requires-dist'),) + ('platforms', 'platform')) + + if sys.version[:3] >= '2.5': + labels += (('provides', 'provides-dist'), + ('obsoletes', 'obsoletes-dist'), + ('requires', 'requires-dist'),) get = lambda lab: getattr(dist.metadata, lab.replace('-', '_')) data.update((new, get(old)) for (old, new) in labels if get(old)) # 2. retrieves data that requires special processings. @@ -281,7 +283,7 @@ for tok, path in path_tokens: if dest.startswith(path): dest = ('{%s}' % tok) + dest[len(path):] - files = [('/ '.join(src.rsplit('/', 1)), dest) + files = [('/ '.join(src.rsplit('/', 1)), dest) for src in srcs] data['resources'].extend(files) continue -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 17:12:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 17:12:25 +0100 Subject: [Python-checkins] distutils2: hooked the remove code - tests w/ data tree coming up Message-ID: tarek.ziade pushed 76c83ee98558 to distutils2: http://hg.python.org/distutils2/rev/76c83ee98558 changeset: 982:76c83ee98558 user: Tarek Ziade date: Sun Jan 30 17:09:46 2011 +0100 summary: hooked the remove code - tests w/ data tree coming up files: distutils2/_backport/pkgutil.py distutils2/install.py distutils2/run.py diff --git a/distutils2/_backport/pkgutil.py b/distutils2/_backport/pkgutil.py --- a/distutils2/_backport/pkgutil.py +++ b/distutils2/_backport/pkgutil.py @@ -7,6 +7,13 @@ import warnings from csv import reader as csv_reader from types import ModuleType +from stat import ST_SIZE + +try: + from hashlib import md5 +except ImportError: + from md5 import md5 + from distutils2.errors import DistutilsError from distutils2.metadata import DistributionMetadata from distutils2.version import suggest_normalized_version, VersionPredicate @@ -969,6 +976,33 @@ return '%s-%s at %s' % (self.name, self.metadata.version, self.path) def get_installed_files(self, local=False): + + def _md5(path): + f = open(path) + try: + content = f.read() + finally: + f.close() + return md5(content).hexdigest() + + def _size(path): + return os.stat(path)[ST_SIZE] + + path = self.path + if local: + path = path.replace('/', os.sep) + + # XXX What about scripts and data files ? + if os.path.isfile(path): + return [(path, _md5(path), _size(path))] + else: + files = [] + for root, dir, files_ in os.walk(path): + for item in files_: + item = os.path.join(root, item) + files.append((item, _md5(item), _size(item))) + return files + return [] def uses(self, path): diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -334,37 +334,64 @@ def remove(project_name, paths=sys.path): """Removes a single project from the installation""" - dist = get_distribution(project_name, paths=paths) + dist = get_distribution(project_name, use_egg_info=True, paths=paths) if dist is None: - raise DistutilsError('Distribution %s not found' % project_name) + raise DistutilsError('Distribution "%s" not found' % project_name) files = dist.get_installed_files(local=True) rmdirs = [] rmfiles = [] tmp = tempfile.mkdtemp(prefix=project_name + '-uninstall') try: - for file, md5, size in files: - if os.path.isfile(file): - dirname, filename = os.path.split(file) + for file_, md5, size in files: + if os.path.isfile(file_): + dirname, filename = os.path.split(file_) tmpfile = os.path.join(tmp, filename) try: - os.rename(file, tmpfile) + os.rename(file_, tmpfile) finally: - if not os.path.isfile(file): - os.rename(tmpfile, file) - if file not in rmfiles: - rmfiles.append(file) + if not os.path.isfile(file_): + os.rename(tmpfile, file_) + if file_ not in rmfiles: + rmfiles.append(file_) if dirname not in rmdirs: rmdirs.append(dirname) finally: shutil.rmtree(tmp) - for file in rmfiles: - os.remove(file) + logger.info('Removing %r...' % project_name) + file_count = 0 + for file_ in rmfiles: + os.remove(file_) + file_count +=1 + + dir_count = 0 for dirname in rmdirs: - if not os.listdir(dirname): - if bool(os.stat(dirname).st_mode & stat.S_IWUSR): - os.rmdir(dirname) + if not os.path.exists(dirname): + # could + continue + + files_count = 0 + for root, dir, files in os.walk(dirname): + files_count += len(files) + + if files_count > 0: + # XXX Warning + continue + + # empty dirs with only empty dirs + if bool(os.stat(dirname).st_mode & stat.S_IWUSR): + # XXX Add a callable in shutil.rmtree to count + # the number of deleted elements + shutil.rmtree(dirname) + dir_count += 1 + + # removing the top path + # XXX count it ? + shutil.rmtree(dist.path) + + logger.info('Success ! Removed %d files and %d dirs' % \ + (file_count, dir_count)) def install(project): diff --git a/distutils2/run.py b/distutils2/run.py --- a/distutils2/run.py +++ b/distutils2/run.py @@ -11,7 +11,7 @@ from distutils2 import __version__ from distutils2._backport.pkgutil import get_distributions, get_distribution from distutils2.depgraph import generate_graph -from distutils2.install import install +from distutils2.install import install, remove # This is a barebones help message generated displayed when the user # runs the setup script with no arguments at all. More useful help @@ -225,6 +225,10 @@ install(options.install) return 0 + if options.remove is not None: + remove(options.remove) + return 0 + if len(args) == 0: parser.print_help() return 0 -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 17:12:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 17:12:25 +0100 Subject: [Python-checkins] distutils2: Moving from spawn to subprocess.call for posix Message-ID: tarek.ziade pushed eaeb77441b82 to distutils2: http://hg.python.org/distutils2/rev/eaeb77441b82 changeset: 983:eaeb77441b82 parent: 981:93d7c64c7a67 user: Andre Espaze date: Sun Jan 30 16:22:52 2011 +0100 summary: Moving from spawn to subprocess.call for posix files: distutils2/tests/test_util.py distutils2/util.py diff --git a/distutils2/tests/test_util.py b/distutils2/tests/test_util.py --- a/distutils2/tests/test_util.py +++ b/distutils2/tests/test_util.py @@ -414,6 +414,10 @@ @unittest.skipUnless(os.name in ('nt', 'posix'), 'runs only under posix or nt') def test_spawn(self): + # Do not patch subprocess on unix because + # distutils2.util._spawn_posix uses it + if os.name in 'posix': + subprocess.Popen = self.old_popen tmpdir = self.mkdtemp() # creating something executable diff --git a/distutils2/util.py b/distutils2/util.py --- a/distutils2/util.py +++ b/distutils2/util.py @@ -12,6 +12,7 @@ import shutil import tarfile import zipfile +from subprocess import call as sub_call from copy import copy from fnmatch import fnmatchcase from ConfigParser import RawConfigParser @@ -800,65 +801,17 @@ "command '%s' failed with exit status %d" % (cmd[0], rc)) -def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0, env=None): - logger.info(' '.join(cmd)) +def _spawn_posix(cmd, search_path=1, verbose=1, dry_run=0, env=None): + cmd = ' '.join(cmd) + if verbose: + logger.info(cmd) + logger.info(env) if dry_run: return - - if env is None: - exec_fn = search_path and os.execvp or os.execv - else: - exec_fn = search_path and os.execvpe or os.execve - - pid = os.fork() - - if pid == 0: # in the child - try: - if env is None: - exec_fn(cmd[0], cmd) - else: - exec_fn(cmd[0], cmd, env) - except OSError, e: - sys.stderr.write("unable to execute %s: %s\n" % - (cmd[0], e.strerror)) - os._exit(1) - - sys.stderr.write("unable to execute %s for unknown reasons" % cmd[0]) - os._exit(1) - else: # in the parent - # Loop until the child either exits or is terminated by a signal - # (ie. keep waiting if it's merely stopped) - while 1: - try: - pid, status = os.waitpid(pid, 0) - except OSError, exc: - import errno - if exc.errno == errno.EINTR: - continue - raise DistutilsExecError( - "command '%s' failed: %s" % (cmd[0], exc[-1])) - if os.WIFSIGNALED(status): - raise DistutilsExecError( - "command '%s' terminated by signal %d" % \ - (cmd[0], os.WTERMSIG(status))) - - elif os.WIFEXITED(status): - exit_status = os.WEXITSTATUS(status) - if exit_status == 0: - return # hey, it succeeded! - else: - raise DistutilsExecError( - "command '%s' failed with exit status %d" % \ - (cmd[0], exit_status)) - - elif os.WIFSTOPPED(status): - continue - - else: - raise DistutilsExecError( - "unknown error executing '%s': termination status %d" % \ - (cmd[0], status)) - + exit_status = sub_call(cmd, shell=True, env=env) + if exit_status != 0: + msg = "command '%s' failed with exit status %d" + raise DistutilsExecError(msg % (cmd, exit_status)) def find_executable(executable, path=None): """Tries to find 'executable' in the directories listed in 'path'. -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 17:12:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 17:12:25 +0100 Subject: [Python-checkins] distutils2: make sure the dir exists in that case Message-ID: tarek.ziade pushed 22028f4d78bc to distutils2: http://hg.python.org/distutils2/rev/22028f4d78bc changeset: 985:22028f4d78bc tag: tip user: Tarek Ziade date: Sun Jan 30 17:12:16 2011 +0100 summary: make sure the dir exists in that case files: distutils2/install.py diff --git a/distutils2/install.py b/distutils2/install.py --- a/distutils2/install.py +++ b/distutils2/install.py @@ -388,7 +388,8 @@ # removing the top path # XXX count it ? - shutil.rmtree(dist.path) + if os.path.exists(dist.path): + shutil.rmtree(dist.path) logger.info('Success ! Removed %d files and %d dirs' % \ (file_count, dir_count)) -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 17:12:25 2011 From: python-checkins at python.org (tarek.ziade) Date: Sun, 30 Jan 2011 17:12:25 +0100 Subject: [Python-checkins] distutils2: merged Message-ID: tarek.ziade pushed ec6ee4cfb4d3 to distutils2: http://hg.python.org/distutils2/rev/ec6ee4cfb4d3 changeset: 984:ec6ee4cfb4d3 parent: 982:76c83ee98558 parent: 983:eaeb77441b82 user: Tarek Ziade date: Sun Jan 30 17:10:15 2011 +0100 summary: merged files: diff --git a/distutils2/tests/test_util.py b/distutils2/tests/test_util.py --- a/distutils2/tests/test_util.py +++ b/distutils2/tests/test_util.py @@ -414,6 +414,10 @@ @unittest.skipUnless(os.name in ('nt', 'posix'), 'runs only under posix or nt') def test_spawn(self): + # Do not patch subprocess on unix because + # distutils2.util._spawn_posix uses it + if os.name in 'posix': + subprocess.Popen = self.old_popen tmpdir = self.mkdtemp() # creating something executable diff --git a/distutils2/util.py b/distutils2/util.py --- a/distutils2/util.py +++ b/distutils2/util.py @@ -12,6 +12,7 @@ import shutil import tarfile import zipfile +from subprocess import call as sub_call from copy import copy from fnmatch import fnmatchcase from ConfigParser import RawConfigParser @@ -800,65 +801,17 @@ "command '%s' failed with exit status %d" % (cmd[0], rc)) -def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0, env=None): - logger.info(' '.join(cmd)) +def _spawn_posix(cmd, search_path=1, verbose=1, dry_run=0, env=None): + cmd = ' '.join(cmd) + if verbose: + logger.info(cmd) + logger.info(env) if dry_run: return - - if env is None: - exec_fn = search_path and os.execvp or os.execv - else: - exec_fn = search_path and os.execvpe or os.execve - - pid = os.fork() - - if pid == 0: # in the child - try: - if env is None: - exec_fn(cmd[0], cmd) - else: - exec_fn(cmd[0], cmd, env) - except OSError, e: - sys.stderr.write("unable to execute %s: %s\n" % - (cmd[0], e.strerror)) - os._exit(1) - - sys.stderr.write("unable to execute %s for unknown reasons" % cmd[0]) - os._exit(1) - else: # in the parent - # Loop until the child either exits or is terminated by a signal - # (ie. keep waiting if it's merely stopped) - while 1: - try: - pid, status = os.waitpid(pid, 0) - except OSError, exc: - import errno - if exc.errno == errno.EINTR: - continue - raise DistutilsExecError( - "command '%s' failed: %s" % (cmd[0], exc[-1])) - if os.WIFSIGNALED(status): - raise DistutilsExecError( - "command '%s' terminated by signal %d" % \ - (cmd[0], os.WTERMSIG(status))) - - elif os.WIFEXITED(status): - exit_status = os.WEXITSTATUS(status) - if exit_status == 0: - return # hey, it succeeded! - else: - raise DistutilsExecError( - "command '%s' failed with exit status %d" % \ - (cmd[0], exit_status)) - - elif os.WIFSTOPPED(status): - continue - - else: - raise DistutilsExecError( - "unknown error executing '%s': termination status %d" % \ - (cmd[0], status)) - + exit_status = sub_call(cmd, shell=True, env=env) + if exit_status != 0: + msg = "command '%s' failed with exit status %d" + raise DistutilsExecError(msg % (cmd, exit_status)) def find_executable(executable, path=None): """Tries to find 'executable' in the directories listed in 'path'. -- Repository URL: http://hg.python.org/distutils2 From python-checkins at python.org Sun Jan 30 20:40:10 2011 From: python-checkins at python.org (brian.curtin) Date: Sun, 30 Jan 2011 20:40:10 +0100 (CET) Subject: [Python-checkins] r88269 - in python/branches/release31-maint: Lib/idlelib/RemoteObjectBrowser.py Message-ID: <20110130194010.15AC2EE9D5@mail.python.org> Author: brian.curtin Date: Sun Jan 30 20:40:09 2011 New Revision: 88269 Log: Merged revisions 88258 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88258 | georg.brandl | 2011-01-30 02:16:07 -0600 (Sun, 30 Jan 2011) | 3 lines #11069: fix the IDLE Stack Viewer, by not using "list" as a variable name. Original patch by Brian Curtin, reviewed by me. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/idlelib/RemoteObjectBrowser.py Modified: python/branches/release31-maint/Lib/idlelib/RemoteObjectBrowser.py ============================================================================== --- python/branches/release31-maint/Lib/idlelib/RemoteObjectBrowser.py (original) +++ python/branches/release31-maint/Lib/idlelib/RemoteObjectBrowser.py Sun Jan 30 20:40:09 2011 @@ -17,8 +17,8 @@ return value def _GetSubList(self): - list = self.__item._GetSubList() - return list(map(remote_object_tree_item, list)) + sub_list = self.__item._GetSubList() + return list(map(remote_object_tree_item, sub_list)) class StubObjectTreeItem: # Lives in IDLE process @@ -32,5 +32,5 @@ return value def _GetSubList(self): - list = self.sockio.remotecall(self.oid, "_GetSubList", (), {}) - return [StubObjectTreeItem(self.sockio, oid) for oid in list] + sub_list = self.sockio.remotecall(self.oid, "_GetSubList", (), {}) + return [StubObjectTreeItem(self.sockio, oid) for oid in sub_list] From python-checkins at python.org Sun Jan 30 21:30:06 2011 From: python-checkins at python.org (brett.cannon) Date: Sun, 30 Jan 2011 21:30:06 +0100 Subject: [Python-checkins] devguide: Drop the specific mention of my fork of coverage.py. Better for me to jst use Message-ID: brett.cannon pushed 7a810e8d89dd to devguide: http://hg.python.org/devguide/rev/7a810e8d89dd changeset: 222:7a810e8d89dd tag: tip user: Brett Cannon date: Sun Jan 30 12:30:00 2011 -0800 summary: Drop the specific mention of my fork of coverage.py. Better for me to jst use it to push changes upstream instead of having people accidentally rely on it. files: coverage.rst diff --git a/coverage.rst b/coverage.rst --- a/coverage.rst +++ b/coverage.rst @@ -74,12 +74,6 @@ hg clone https://bitbucket.org/ned/coveragepy ln -s coveragepy/coverage -If you are still having issues with generating coverage, a fork of coverage.py -can be found at https://bitbucket.org/brettsky/coverage.py which will always -try to be patched to work against the latest in-development version of Python -(all patches are submitted upstream so this should only be used as a temporary -solution). - Another option is to download the source distribution of coverage.py and copy the ``coverage`` directory into your Python checkout. The other option is to use your checkout -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 31 00:51:24 2011 From: python-checkins at python.org (brett.cannon) Date: Mon, 31 Jan 2011 00:51:24 +0100 Subject: [Python-checkins] devguide: Emphasize even stronger that you do not need to install a checkout build. Message-ID: brett.cannon pushed 9a7b9f4cccd2 to devguide: http://hg.python.org/devguide/rev/9a7b9f4cccd2 changeset: 223:9a7b9f4cccd2 tag: tip user: Brett Cannon date: Sun Jan 30 15:51:17 2011 -0800 summary: Emphasize even stronger that you do not need to install a checkout build. files: setup.rst diff --git a/setup.rst b/setup.rst --- a/setup.rst +++ b/setup.rst @@ -122,7 +122,11 @@ Once CPython is done building you will then have a working build that can be run in-place; ``./python`` on most machines (and what is used in all examples), ``./python.exe`` on OS X (when on a case-insensitive filesystem, -which is the default). +which is the default). There is absolutely no need to install your built copy +of Python! The interpreter will realize it is being run directly out of a +checkout and thus use the files found in the checkout. If you are worried you +might accidentally install your checkout build, you can add +``--prefix=/dev/null`` to the configuration step. .. _issue tracker: http://bugs.python.org -- Repository URL: http://hg.python.org/devguide From python-checkins at python.org Mon Jan 31 01:52:49 2011 From: python-checkins at python.org (ned.deily) Date: Mon, 31 Jan 2011 01:52:49 +0100 (CET) Subject: [Python-checkins] r88270 - in python/branches/release27-maint: Lib/idlelib/EditorWindow.py Misc/NEWS Message-ID: <20110131005249.50464EE9E0@mail.python.org> Author: ned.deily Date: Mon Jan 31 01:52:49 2011 New Revision: 88270 Log: Merged revisions 88232 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88232 | ned.deily | 2011-01-29 10:29:01 -0800 (Sat, 29 Jan 2011) | 5 lines Issue #10940: Workaround an IDLE hang on Mac OS X 10.6 when using the menu accelerators for Open Module, Go to Line, and New Indent Width. The accelerators still work but no longer appear in the menu items. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/idlelib/EditorWindow.py python/branches/release27-maint/Misc/NEWS Modified: python/branches/release27-maint/Lib/idlelib/EditorWindow.py ============================================================================== --- python/branches/release27-maint/Lib/idlelib/EditorWindow.py (original) +++ python/branches/release27-maint/Lib/idlelib/EditorWindow.py Mon Jan 31 01:52:49 2011 @@ -1541,7 +1541,12 @@ def get_accelerator(keydefs, eventname): keylist = keydefs.get(eventname) - if not keylist: + # issue10940: temporary workaround to prevent hang with OS X Cocoa Tk 8.5 + # if not keylist: + if (not keylist) or (macosxSupport.runningAsOSXApp() and eventname in { + "<>", + "<>", + "<>"}): return "" s = keylist[0] s = re.sub(r"-[a-z]\b", lambda m: m.group().upper(), s) Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Mon Jan 31 01:52:49 2011 @@ -37,6 +37,10 @@ Library ------- +- Issue #10940: Workaround an IDLE hang on Mac OS X 10.6 when using the + menu accelerators for Open Module, Go to Line, and New Indent Width. + The accelerators still work but no longer appear in the menu items. + - Issue #10907: Warn OS X 10.6 IDLE users to use ActiveState Tcl/Tk 8.5, rather than the currently problematic Apple-supplied one, when running with the 64-/32-bit installer variant. From python-checkins at python.org Mon Jan 31 05:05:53 2011 From: python-checkins at python.org (eli.bendersky) Date: Mon, 31 Jan 2011 05:05:53 +0100 (CET) Subject: [Python-checkins] r88271 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110131040553.13F2EEE991@mail.python.org> Author: eli.bendersky Date: Mon Jan 31 05:05:52 2011 New Revision: 88271 Log: Fix some grammar and typos Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Mon Jan 31 05:05:52 2011 @@ -88,7 +88,7 @@ positional arguments (not just options), subcommands, required options and other common patterns of specifying and validating options. -This module has already has widespread success in the community as a +This module already has widespread success in the community as a third-party module. Being more fully featured than its predecessor, the :mod:`argparse` module is now the preferred module for command-line processing. The older module is still being kept available because of the substantial amount @@ -328,13 +328,13 @@ * The :mod:`py_compile` and :mod:`compileall` modules have been updated to reflect the new naming convention and target directory. The command-line - invocation of *compileall* has new command-line options include ``-i`` for + invocation of *compileall* has new command-line options: ``-i`` for specifying a list of files and directories to compile, and ``-b`` which causes bytecode files to be written to their legacy location rather than *__pycache__*. * The :mod:`importlib.abc` module has been updated with new :term:`abstract base - classes ` for the loading bytecode files. The obsolete + classes ` for loading bytecode files. The obsolete ABCs, :class:`~importlib.abc.PyLoader` and :class:`~importlib.abc.PyPycLoader`, have been deprecated (instructions on how to stay Python 3.1 compatible are included with the documentation). @@ -391,7 +391,7 @@ The *native strings* are always of type :class:`str` but are restricted to code points between *U+0000* through *U+00FF* which are translatable to bytes using *Latin-1* encoding. These strings are used for the keys and values in the -environ dictionary and for response headers and statuses in the +``environ`` dictionary and for response headers and statuses in the :func:`start_response` function. They must follow :rfc:`2616` with respect to encoding. That is, they must either be *ISO-8859-1* characters or use :rfc:`2047` MIME encoding. @@ -447,7 +447,7 @@ :term:`mapping` objects. This new method makes it possible to use string formatting with any of one of Python's many dictionary-like tools such as :class:`~collections.defaultdict`, :class:`~shelve.Shelf`, - :class:`~configparser.ConfigParser`, or :mod:`dbm`. It also useful with + :class:`~configparser.ConfigParser`, or :mod:`dbm`. It is also useful with custom :class:`dict` subclasses that normalize keys before look-up or that supply a :meth:`__missing__` method for unknown keys:: @@ -2612,6 +2612,6 @@ and :c:func:`PyEval_RestoreThread()`) should be used instead. * Due to security risks, :func:`asyncore.handle_accept` has been deprecated, and - a new functions, :func:`asyncore.handle_accepted` was added to replace it. + a new function, :func:`asyncore.handle_accepted` was added to replace it. (Contributed by Giampaolo Rodola in :issue:`6706`.) From solipsis at pitrou.net Mon Jan 31 05:06:17 2011 From: solipsis at pitrou.net (solipsis at pitrou.net) Date: Mon, 31 Jan 2011 05:06:17 +0100 Subject: [Python-checkins] Daily py3k reference leaks (r88266): sum=-56 Message-ID: py3k results for svn r88266 (hg cset afcd45d7e5d4) -------------------------------------------------- test_pyexpat leaked [0, 0, -56] references, sum=-56 Command line was: ['./python', '-m', 'test.regrtest', '-uall', '-R', '3:3:/home/antoine/py3k/refleaks/reflogRaCDF2', '-x'] From python-checkins at python.org Mon Jan 31 05:10:23 2011 From: python-checkins at python.org (eli.bendersky) Date: Mon, 31 Jan 2011 05:10:23 +0100 (CET) Subject: [Python-checkins] r88272 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110131041023.36FE7EE983@mail.python.org> Author: eli.bendersky Date: Mon Jan 31 05:10:23 2011 New Revision: 88272 Log: Fix PEP-8 violation in argparse usage example (similar examples in argparse.rst do follow PEP-8) Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Mon Jan 31 05:10:23 2011 @@ -100,18 +100,18 @@ import argparse parser = argparse.ArgumentParser( - description = 'Manage servers', # main description for help - epilog = 'Tested on Solaris and Linux') # displayed after help + description='Manage servers', # main description for help + epilog='Tested on Solaris and Linux') # displayed after help parser.add_argument('action', # argument name - choices = ['deploy', 'start', 'stop'], # three allowed values - help = 'action on each target') # help msg + choices=['deploy', 'start', 'stop'], # three allowed values + help='action on each target') # help msg parser.add_argument('targets', - metavar = 'HOSTNAME', # var name used in help msg - nargs = '+', # require one or more targets - help = 'url for target machines') # help msg explanation + metavar='HOSTNAME', # var name used in help msg + nargs='+', # require one or more targets + help='url for target machines') # help msg explanation parser.add_argument('-u', '--user', # -u or --user option - required = True, # make it a required argument - help = 'login as user') + required=True, # make it a required argument + help='login as user') Example of calling the parser on a command string:: From python-checkins at python.org Mon Jan 31 05:21:40 2011 From: python-checkins at python.org (eli.bendersky) Date: Mon, 31 Jan 2011 05:21:40 +0100 (CET) Subject: [Python-checkins] r88273 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110131042140.E8C47EE991@mail.python.org> Author: eli.bendersky Date: Mon Jan 31 05:21:40 2011 New Revision: 88273 Log: Mention new parameter and attributes of the difflib.SequenceMatcher class added in 3.2 (issue 2986) Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Mon Jan 31 05:21:40 2011 @@ -2094,6 +2094,15 @@ (All changes contributed by ?ukasz Langa.) +difflib +------- + +:class:`difflib.SequenceMatcher` has a new parameter in its constructor, +*autojunk*, that allows the user to turn off the automatic junk heuristic the +class uses in its algorithm. Additionally, two new attributes were exposed +to users - *bjunk* and *bpopular*, allowing better understanding of the +heuristics used by the class. + urllib.parse ------------ From raymond.hettinger at gmail.com Mon Jan 31 05:26:31 2011 From: raymond.hettinger at gmail.com (Raymond Hettinger) Date: Sun, 30 Jan 2011 20:26:31 -0800 Subject: [Python-checkins] r88273 - python/branches/py3k/Doc/whatsnew/3.2.rst In-Reply-To: <20110131042140.E8C47EE991@mail.python.org> References: <20110131042140.E8C47EE991@mail.python.org> Message-ID: On Jan 30, 2011, at 8:21 PM, eli.bendersky wrote: Please use the open tracker item and do not edit the document directly. Raymond From python-checkins at python.org Mon Jan 31 07:14:49 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 31 Jan 2011 07:14:49 +0100 (CET) Subject: [Python-checkins] r88274 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110131061449.2A8B6EE997@mail.python.org> Author: raymond.hettinger Date: Mon Jan 31 07:14:48 2011 New Revision: 88274 Log: Fix minor grammar nits. Revert r88272 -- the examples are more readable with spacing. Add todos for difflib and logging. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Mon Jan 31 07:14:48 2011 @@ -88,7 +88,7 @@ positional arguments (not just options), subcommands, required options and other common patterns of specifying and validating options. -This module already has widespread success in the community as a +This module has already had widespread success in the community as a third-party module. Being more fully featured than its predecessor, the :mod:`argparse` module is now the preferred module for command-line processing. The older module is still being kept available because of the substantial amount @@ -100,18 +100,18 @@ import argparse parser = argparse.ArgumentParser( - description='Manage servers', # main description for help - epilog='Tested on Solaris and Linux') # displayed after help + description = 'Manage servers', # main description for help + epilog = 'Tested on Solaris and Linux') # displayed after help parser.add_argument('action', # argument name - choices=['deploy', 'start', 'stop'], # three allowed values - help='action on each target') # help msg + choices = ['deploy', 'start', 'stop'], # three allowed values + help = 'action on each target') # help msg parser.add_argument('targets', - metavar='HOSTNAME', # var name used in help msg - nargs='+', # require one or more targets - help='url for target machines') # help msg explanation + metavar = 'HOSTNAME', # var name used in help msg + nargs = '+', # require one or more targets + help = 'url for target machines') # help msg explanation parser.add_argument('-u', '--user', # -u or --user option - required=True, # make it a required argument - help='login as user') + required = True, # make it a required argument + help = 'login as user') Example of calling the parser on a command string:: @@ -329,7 +329,7 @@ * The :mod:`py_compile` and :mod:`compileall` modules have been updated to reflect the new naming convention and target directory. The command-line invocation of *compileall* has new command-line options: ``-i`` for - specifying a list of files and directories to compile, and ``-b`` which causes + specifying a list of files and directories to compile and ``-b`` which causes bytecode files to be written to their legacy location rather than *__pycache__*. @@ -391,7 +391,7 @@ The *native strings* are always of type :class:`str` but are restricted to code points between *U+0000* through *U+00FF* which are translatable to bytes using *Latin-1* encoding. These strings are used for the keys and values in the -``environ`` dictionary and for response headers and statuses in the +environment dictionary and for response headers and statuses in the :func:`start_response` function. They must follow :rfc:`2616` with respect to encoding. That is, they must either be *ISO-8859-1* characters or use :rfc:`2047` MIME encoding. @@ -1414,7 +1414,7 @@ --- The :mod:`ast` module has a wonderful a general-purpose tool for safely -evaluating strings containing Python expressions using the Python literal +evaluating expression strings using the Python literal syntax. The :func:`ast.literal_eval` function serves as a secure alternative to the builtin :func:`eval` function which is easily abused. Python 3.2 adds :class:`bytes` and :class:`set` literals to the list of supported types: @@ -1881,8 +1881,7 @@ dbm --- -All database modules now support :meth:`get` and :meth:`setdefault` are now -available in all database modules +All database modules now support the :meth:`get` and :meth:`setdefault` methods. (Suggested by Ray Allen in :issue:`9523`.) @@ -2094,14 +2093,8 @@ (All changes contributed by ?ukasz Langa.) -difflib -------- - -:class:`difflib.SequenceMatcher` has a new parameter in its constructor, -*autojunk*, that allows the user to turn off the automatic junk heuristic the -class uses in its algorithm. Additionally, two new attributes were exposed -to users - *bjunk* and *bpopular*, allowing better understanding of the -heuristics used by the class. +.. XXX show a difflib example +.. XXX add entry for logging changes other than the dict config pep urllib.parse ------------ @@ -2460,13 +2453,13 @@ function declaration, which was kept for backwards compatibility reasons, is now removed -- the macro was introduced in 1997 (:issue:`8276`). -* The is a new function :c:func:`PyLong_AsLongLongAndOverflow` which +* There is a new function :c:func:`PyLong_AsLongLongAndOverflow` which is analogous to :c:func:`PyLong_AsLongAndOverflow`. They both serve to convert Python :class:`int` into a native fixed-width type while providing detection of cases where the conversion won't fit (:issue:`7767`). -* The :c:func:`PyUnicode_CompareWithASCIIString` now returns *not equal* - if the Python string is *NUL* terminated. +* The :c:func:`PyUnicode_CompareWithASCIIString` function now returns *not + equal* if the Python string is *NUL* terminated. * There is a new function :c:func:`PyErr_NewExceptionWithDoc` that is like :c:func:`PyErr_NewException` but allows a docstring to be specified. @@ -2621,6 +2614,6 @@ and :c:func:`PyEval_RestoreThread()`) should be used instead. * Due to security risks, :func:`asyncore.handle_accept` has been deprecated, and - a new function, :func:`asyncore.handle_accepted` was added to replace it. + a new function, :func:`asyncore.handle_accepted`, was added to replace it. (Contributed by Giampaolo Rodola in :issue:`6706`.) From python-checkins at python.org Mon Jan 31 07:34:47 2011 From: python-checkins at python.org (raymond.hettinger) Date: Mon, 31 Jan 2011 07:34:47 +0100 (CET) Subject: [Python-checkins] r88275 - python/branches/py3k/Doc/whatsnew/3.2.rst Message-ID: <20110131063447.7A849EE999@mail.python.org> Author: raymond.hettinger Date: Mon Jan 31 07:34:47 2011 New Revision: 88275 Log: Recommend use of the tracker during the RC phase or just before a beta. Modified: python/branches/py3k/Doc/whatsnew/3.2.rst Modified: python/branches/py3k/Doc/whatsnew/3.2.rst ============================================================================== --- python/branches/py3k/Doc/whatsnew/3.2.rst (original) +++ python/branches/py3k/Doc/whatsnew/3.2.rst Mon Jan 31 07:34:47 2011 @@ -11,7 +11,10 @@ * Anyone can add text to this document. Do not spend very much time on the wording of your changes, because your text will probably - get rewritten. + get rewritten. (Note, during release candidate phase or just before + a beta release, please use the tracker instead -- this helps avoid + merge conflicts. If you must add a suggested entry directly, + please put it in an XXX comment and the maintainer will take notice). * The maintainer will go through Misc/NEWS periodically and add changes; it's therefore more important to add your changes to From python-checkins at python.org Mon Jan 31 11:39:57 2011 From: python-checkins at python.org (georg.brandl) Date: Mon, 31 Jan 2011 11:39:57 +0100 (CET) Subject: [Python-checkins] r88276 - in python/branches/py3k: Include/patchlevel.h Misc/NEWS Message-ID: <20110131103957.A420AEE9C5@mail.python.org> Author: georg.brandl Date: Mon Jan 31 11:39:57 2011 New Revision: 88276 Log: Post-release updates. Modified: python/branches/py3k/Include/patchlevel.h python/branches/py3k/Misc/NEWS Modified: python/branches/py3k/Include/patchlevel.h ============================================================================== --- python/branches/py3k/Include/patchlevel.h (original) +++ python/branches/py3k/Include/patchlevel.h Mon Jan 31 11:39:57 2011 @@ -23,7 +23,7 @@ #define PY_RELEASE_SERIAL 2 /* Version as a string */ -#define PY_VERSION "3.2rc2" +#define PY_VERSION "3.2rc2+" /*--end constants--*/ /* Subversion Revision number of this file (not of the repository) */ Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 31 11:39:57 2011 @@ -2,6 +2,18 @@ Python News +++++++++++ +What's New in Python 3.2? +========================= + +*Release date: XX-Feb-2011* + +Core and Builtins +----------------- + +Library +------- + + What's New in Python 3.2 Release Candidate 2? ============================================= From python-checkins at python.org Mon Jan 31 20:27:55 2011 From: python-checkins at python.org (alexander.belopolsky) Date: Mon, 31 Jan 2011 20:27:55 +0100 (CET) Subject: [Python-checkins] r88280 - python/branches/py3k/Lib/struct.py Message-ID: <20110131192755.6E628EE98A@mail.python.org> Author: alexander.belopolsky Date: Mon Jan 31 20:27:55 2011 New Revision: 88280 Log: Issue #11081: Fixed struct.__all__. Reviewed by Georg Brandl. Modified: python/branches/py3k/Lib/struct.py Modified: python/branches/py3k/Lib/struct.py ============================================================================== --- python/branches/py3k/Lib/struct.py (original) +++ python/branches/py3k/Lib/struct.py Mon Jan 31 20:27:55 2011 @@ -1,6 +1,6 @@ __all__ = [ # Functions - 'calcsize', 'pack', 'unpack', 'unpack', 'unpack_from', + 'calcsize', 'pack', 'pack_into', 'unpack', 'unpack_from', # Classes 'Struct', From python-checkins at python.org Mon Jan 31 20:35:03 2011 From: python-checkins at python.org (brian.curtin) Date: Mon, 31 Jan 2011 20:35:03 +0100 (CET) Subject: [Python-checkins] r88281 - python/branches/py3k/Doc/library/threading.rst Message-ID: <20110131193503.1F3C0EE9AD@mail.python.org> Author: brian.curtin Date: Mon Jan 31 20:35:02 2011 New Revision: 88281 Log: #11083 typo: RuntimeException -> RuntimeError Modified: python/branches/py3k/Doc/library/threading.rst Modified: python/branches/py3k/Doc/library/threading.rst ============================================================================== --- python/branches/py3k/Doc/library/threading.rst (original) +++ python/branches/py3k/Doc/library/threading.rst Mon Jan 31 20:35:02 2011 @@ -284,7 +284,7 @@ It must be called at most once per thread object. It arranges for the object's :meth:`run` method to be invoked in a separate thread of control. - This method will raise a :exc:`RuntimeException` if called more than once + This method will raise a :exc:`RuntimeError` if called more than once on the same thread object. .. method:: run() From python-checkins at python.org Mon Jan 31 20:41:53 2011 From: python-checkins at python.org (brian.curtin) Date: Mon, 31 Jan 2011 20:41:53 +0100 (CET) Subject: [Python-checkins] r88282 - in python/branches/release31-maint: Doc/library/threading.rst Message-ID: <20110131194153.9EACBEE98A@mail.python.org> Author: brian.curtin Date: Mon Jan 31 20:41:53 2011 New Revision: 88282 Log: Merged revisions 88281 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88281 | brian.curtin | 2011-01-31 13:35:02 -0600 (Mon, 31 Jan 2011) | 2 lines #11083 typo: RuntimeException -> RuntimeError ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Doc/library/threading.rst Modified: python/branches/release31-maint/Doc/library/threading.rst ============================================================================== --- python/branches/release31-maint/Doc/library/threading.rst (original) +++ python/branches/release31-maint/Doc/library/threading.rst Mon Jan 31 20:41:53 2011 @@ -268,7 +268,7 @@ It must be called at most once per thread object. It arranges for the object's :meth:`run` method to be invoked in a separate thread of control. - This method will raise a :exc:`RuntimeException` if called more than once + This method will raise a :exc:`RuntimeError` if called more than once on the same thread object. .. method:: run() From python-checkins at python.org Mon Jan 31 20:55:14 2011 From: python-checkins at python.org (brian.curtin) Date: Mon, 31 Jan 2011 20:55:14 +0100 (CET) Subject: [Python-checkins] r88283 - in python/branches/release27-maint: Doc/library/threading.rst Message-ID: <20110131195514.BBF7DEE983@mail.python.org> Author: brian.curtin Date: Mon Jan 31 20:55:14 2011 New Revision: 88283 Log: Merged revisions 88281 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88281 | brian.curtin | 2011-01-31 13:35:02 -0600 (Mon, 31 Jan 2011) | 2 lines #11083 typo: RuntimeException -> RuntimeError ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Doc/library/threading.rst Modified: python/branches/release27-maint/Doc/library/threading.rst ============================================================================== --- python/branches/release27-maint/Doc/library/threading.rst (original) +++ python/branches/release27-maint/Doc/library/threading.rst Mon Jan 31 20:55:14 2011 @@ -290,7 +290,7 @@ It must be called at most once per thread object. It arranges for the object's :meth:`run` method to be invoked in a separate thread of control. - This method will raise a :exc:`RuntimeException` if called more than once + This method will raise a :exc:`RuntimeError` if called more than once on the same thread object. .. method:: run() From python-checkins at python.org Mon Jan 31 22:08:58 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 31 Jan 2011 22:08:58 +0100 (CET) Subject: [Python-checkins] r88284 - in python/branches/py3k: Lib/ctypes/test/test_callbacks.py Misc/ACKS Misc/NEWS Modules/_ctypes/_ctypes_test.c Modules/_ctypes/libffi_msvc/ffi.c Message-ID: <20110131210858.15D9CEE9A7@mail.python.org> Author: antoine.pitrou Date: Mon Jan 31 22:08:57 2011 New Revision: 88284 Log: Issue #8275: Fix passing of callback arguments with ctypes under Win64. Patch by Stan Mihai. Ok'ed by Georg. Modified: python/branches/py3k/Lib/ctypes/test/test_callbacks.py python/branches/py3k/Misc/ACKS python/branches/py3k/Misc/NEWS python/branches/py3k/Modules/_ctypes/_ctypes_test.c python/branches/py3k/Modules/_ctypes/libffi_msvc/ffi.c Modified: python/branches/py3k/Lib/ctypes/test/test_callbacks.py ============================================================================== --- python/branches/py3k/Lib/ctypes/test/test_callbacks.py (original) +++ python/branches/py3k/Lib/ctypes/test/test_callbacks.py Mon Jan 31 22:08:57 2011 @@ -200,6 +200,42 @@ windll.user32.EnumWindows(EnumWindowsCallbackFunc, 0) + def test_callback_register_int(self): + # Issue #8275: buggy handling of callback args under Win64 + # NOTE: should be run on release builds as well + dll = CDLL(_ctypes_test.__file__) + CALLBACK = CFUNCTYPE(c_int, c_int, c_int, c_int, c_int, c_int) + # All this function does is call the callback with its args squared + func = dll._testfunc_cbk_reg_int + func.argtypes = (c_int, c_int, c_int, c_int, c_int, CALLBACK) + func.restype = c_int + + def callback(a, b, c, d, e): + return a + b + c + d + e + + result = func(2, 3, 4, 5, 6, CALLBACK(callback)) + self.assertEqual(result, callback(2*2, 3*3, 4*4, 5*5, 6*6)) + + def test_callback_register_double(self): + # Issue #8275: buggy handling of callback args under Win64 + # NOTE: should be run on release builds as well + dll = CDLL(_ctypes_test.__file__) + CALLBACK = CFUNCTYPE(c_double, c_double, c_double, c_double, + c_double, c_double) + # All this function does is call the callback with its args squared + func = dll._testfunc_cbk_reg_double + func.argtypes = (c_double, c_double, c_double, + c_double, c_double, CALLBACK) + func.restype = c_double + + def callback(a, b, c, d, e): + return a + b + c + d + e + + result = func(1.1, 2.2, 3.3, 4.4, 5.5, CALLBACK(callback)) + self.assertEqual(result, + callback(1.1*1.1, 2.2*2.2, 3.3*3.3, 4.4*4.4, 5.5*5.5)) + + ################################################################ if __name__ == '__main__': Modified: python/branches/py3k/Misc/ACKS ============================================================================== --- python/branches/py3k/Misc/ACKS (original) +++ python/branches/py3k/Misc/ACKS Mon Jan 31 22:08:57 2011 @@ -574,6 +574,7 @@ Mike Meyer Steven Miale Trent Mick +Stan Mihai Aristotelis Mikropoulos Damien Miller Chad Miller Modified: python/branches/py3k/Misc/NEWS ============================================================================== --- python/branches/py3k/Misc/NEWS (original) +++ python/branches/py3k/Misc/NEWS Mon Jan 31 22:08:57 2011 @@ -13,6 +13,9 @@ Library ------- +- Issue #8275: Fix passing of callback arguments with ctypes under Win64. + Patch by Stan Mihai. + What's New in Python 3.2 Release Candidate 2? ============================================= Modified: python/branches/py3k/Modules/_ctypes/_ctypes_test.c ============================================================================== --- python/branches/py3k/Modules/_ctypes/_ctypes_test.c (original) +++ python/branches/py3k/Modules/_ctypes/_ctypes_test.c Mon Jan 31 22:08:57 2011 @@ -12,6 +12,20 @@ /* some functions handy for testing */ +EXPORT(int) +_testfunc_cbk_reg_int(int a, int b, int c, int d, int e, + int (*func)(int, int, int, int, int)) +{ + return func(a*a, b*b, c*c, d*d, e*e); +} + +EXPORT(double) +_testfunc_cbk_reg_double(double a, double b, double c, double d, double e, + double (*func)(double, double, double, double, double)) +{ + return func(a*a, b*b, c*c, d*d, e*e); +} + EXPORT(void)testfunc_array(int values[4]) { printf("testfunc_array %d %d %d %d\n", Modified: python/branches/py3k/Modules/_ctypes/libffi_msvc/ffi.c ============================================================================== --- python/branches/py3k/Modules/_ctypes/libffi_msvc/ffi.c (original) +++ python/branches/py3k/Modules/_ctypes/libffi_msvc/ffi.c Mon Jan 31 22:08:57 2011 @@ -380,7 +380,7 @@ short bytes; char *tramp; #ifdef _WIN64 - int mask; + int mask = 0; #endif FFI_ASSERT (cif->abi == FFI_SYSV); From python-checkins at python.org Mon Jan 31 22:36:33 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 31 Jan 2011 22:36:33 +0100 (CET) Subject: [Python-checkins] r88285 - in python/branches/release31-maint: Lib/ctypes/test/test_callbacks.py Misc/ACKS Misc/NEWS Modules/_ctypes/_ctypes_test.c Modules/_ctypes/libffi_msvc/ffi.c Message-ID: <20110131213633.4BBE6F322@mail.python.org> Author: antoine.pitrou Date: Mon Jan 31 22:36:33 2011 New Revision: 88285 Log: Merged revisions 88284 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88284 | antoine.pitrou | 2011-01-31 22:08:57 +0100 (lun., 31 janv. 2011) | 4 lines Issue #8275: Fix passing of callback arguments with ctypes under Win64. Patch by Stan Mihai. Ok'ed by Georg. ........ Modified: python/branches/release31-maint/ (props changed) python/branches/release31-maint/Lib/ctypes/test/test_callbacks.py python/branches/release31-maint/Misc/ACKS python/branches/release31-maint/Misc/NEWS python/branches/release31-maint/Modules/_ctypes/_ctypes_test.c python/branches/release31-maint/Modules/_ctypes/libffi_msvc/ffi.c Modified: python/branches/release31-maint/Lib/ctypes/test/test_callbacks.py ============================================================================== --- python/branches/release31-maint/Lib/ctypes/test/test_callbacks.py (original) +++ python/branches/release31-maint/Lib/ctypes/test/test_callbacks.py Mon Jan 31 22:36:33 2011 @@ -166,6 +166,42 @@ self.assertLess(diff, 0.01, "%s not less than 0.01" % diff) + def test_callback_register_int(self): + # Issue #8275: buggy handling of callback args under Win64 + # NOTE: should be run on release builds as well + dll = CDLL(_ctypes_test.__file__) + CALLBACK = CFUNCTYPE(c_int, c_int, c_int, c_int, c_int, c_int) + # All this function does is call the callback with its args squared + func = dll._testfunc_cbk_reg_int + func.argtypes = (c_int, c_int, c_int, c_int, c_int, CALLBACK) + func.restype = c_int + + def callback(a, b, c, d, e): + return a + b + c + d + e + + result = func(2, 3, 4, 5, 6, CALLBACK(callback)) + self.assertEqual(result, callback(2*2, 3*3, 4*4, 5*5, 6*6)) + + def test_callback_register_double(self): + # Issue #8275: buggy handling of callback args under Win64 + # NOTE: should be run on release builds as well + dll = CDLL(_ctypes_test.__file__) + CALLBACK = CFUNCTYPE(c_double, c_double, c_double, c_double, + c_double, c_double) + # All this function does is call the callback with its args squared + func = dll._testfunc_cbk_reg_double + func.argtypes = (c_double, c_double, c_double, + c_double, c_double, CALLBACK) + func.restype = c_double + + def callback(a, b, c, d, e): + return a + b + c + d + e + + result = func(1.1, 2.2, 3.3, 4.4, 5.5, CALLBACK(callback)) + self.assertEqual(result, + callback(1.1*1.1, 2.2*2.2, 3.3*3.3, 4.4*4.4, 5.5*5.5)) + + ################################################################ if __name__ == '__main__': Modified: python/branches/release31-maint/Misc/ACKS ============================================================================== --- python/branches/release31-maint/Misc/ACKS (original) +++ python/branches/release31-maint/Misc/ACKS Mon Jan 31 22:36:33 2011 @@ -536,6 +536,7 @@ Mike Meyer Steven Miale Trent Mick +Stan Mihai Aristotelis Mikropoulos Damien Miller Chad Miller Modified: python/branches/release31-maint/Misc/NEWS ============================================================================== --- python/branches/release31-maint/Misc/NEWS (original) +++ python/branches/release31-maint/Misc/NEWS Mon Jan 31 22:36:33 2011 @@ -37,6 +37,9 @@ Library ------- +- Issue #8275: Fix passing of callback arguments with ctypes under Win64. + Patch by Stan Mihai. + - Issue #11053: Fix IDLE "Syntax Error" windows to behave as in 2.x, preventing a confusing hung appearance on OS X with the windows obscured. Modified: python/branches/release31-maint/Modules/_ctypes/_ctypes_test.c ============================================================================== --- python/branches/release31-maint/Modules/_ctypes/_ctypes_test.c (original) +++ python/branches/release31-maint/Modules/_ctypes/_ctypes_test.c Mon Jan 31 22:36:33 2011 @@ -12,6 +12,20 @@ /* some functions handy for testing */ +EXPORT(int) +_testfunc_cbk_reg_int(int a, int b, int c, int d, int e, + int (*func)(int, int, int, int, int)) +{ + return func(a*a, b*b, c*c, d*d, e*e); +} + +EXPORT(double) +_testfunc_cbk_reg_double(double a, double b, double c, double d, double e, + double (*func)(double, double, double, double, double)) +{ + return func(a*a, b*b, c*c, d*d, e*e); +} + EXPORT(void)testfunc_array(int values[4]) { printf("testfunc_array %d %d %d %d\n", Modified: python/branches/release31-maint/Modules/_ctypes/libffi_msvc/ffi.c ============================================================================== --- python/branches/release31-maint/Modules/_ctypes/libffi_msvc/ffi.c (original) +++ python/branches/release31-maint/Modules/_ctypes/libffi_msvc/ffi.c Mon Jan 31 22:36:33 2011 @@ -379,7 +379,7 @@ short bytes; char *tramp; #ifdef _WIN64 - int mask; + int mask = 0; #endif FFI_ASSERT (cif->abi == FFI_SYSV); From python-checkins at python.org Mon Jan 31 22:47:45 2011 From: python-checkins at python.org (antoine.pitrou) Date: Mon, 31 Jan 2011 22:47:45 +0100 (CET) Subject: [Python-checkins] r88286 - in python/branches/release27-maint: Lib/ctypes/test/test_callbacks.py Misc/ACKS Misc/NEWS Modules/_ctypes/_ctypes_test.c Modules/_ctypes/libffi_msvc/ffi.c Message-ID: <20110131214745.CCAD7EE9B8@mail.python.org> Author: antoine.pitrou Date: Mon Jan 31 22:47:45 2011 New Revision: 88286 Log: Merged revisions 88284 via svnmerge from svn+ssh://pythondev at svn.python.org/python/branches/py3k ........ r88284 | antoine.pitrou | 2011-01-31 22:08:57 +0100 (lun., 31 janv. 2011) | 4 lines Issue #8275: Fix passing of callback arguments with ctypes under Win64. Patch by Stan Mihai. Ok'ed by Georg. ........ Modified: python/branches/release27-maint/ (props changed) python/branches/release27-maint/Lib/ctypes/test/test_callbacks.py python/branches/release27-maint/Misc/ACKS python/branches/release27-maint/Misc/NEWS python/branches/release27-maint/Modules/_ctypes/_ctypes_test.c python/branches/release27-maint/Modules/_ctypes/libffi_msvc/ffi.c Modified: python/branches/release27-maint/Lib/ctypes/test/test_callbacks.py ============================================================================== --- python/branches/release27-maint/Lib/ctypes/test/test_callbacks.py (original) +++ python/branches/release27-maint/Lib/ctypes/test/test_callbacks.py Mon Jan 31 22:47:45 2011 @@ -206,6 +206,42 @@ windll.user32.EnumWindows(EnumWindowsCallbackFunc, 0) + def test_callback_register_int(self): + # Issue #8275: buggy handling of callback args under Win64 + # NOTE: should be run on release builds as well + dll = CDLL(_ctypes_test.__file__) + CALLBACK = CFUNCTYPE(c_int, c_int, c_int, c_int, c_int, c_int) + # All this function does is call the callback with its args squared + func = dll._testfunc_cbk_reg_int + func.argtypes = (c_int, c_int, c_int, c_int, c_int, CALLBACK) + func.restype = c_int + + def callback(a, b, c, d, e): + return a + b + c + d + e + + result = func(2, 3, 4, 5, 6, CALLBACK(callback)) + self.assertEqual(result, callback(2*2, 3*3, 4*4, 5*5, 6*6)) + + def test_callback_register_double(self): + # Issue #8275: buggy handling of callback args under Win64 + # NOTE: should be run on release builds as well + dll = CDLL(_ctypes_test.__file__) + CALLBACK = CFUNCTYPE(c_double, c_double, c_double, c_double, + c_double, c_double) + # All this function does is call the callback with its args squared + func = dll._testfunc_cbk_reg_double + func.argtypes = (c_double, c_double, c_double, + c_double, c_double, CALLBACK) + func.restype = c_double + + def callback(a, b, c, d, e): + return a + b + c + d + e + + result = func(1.1, 2.2, 3.3, 4.4, 5.5, CALLBACK(callback)) + self.assertEqual(result, + callback(1.1*1.1, 2.2*2.2, 3.3*3.3, 4.4*4.4, 5.5*5.5)) + + ################################################################ if __name__ == '__main__': Modified: python/branches/release27-maint/Misc/ACKS ============================================================================== --- python/branches/release27-maint/Misc/ACKS (original) +++ python/branches/release27-maint/Misc/ACKS Mon Jan 31 22:47:45 2011 @@ -539,6 +539,7 @@ Mike Meyer Steven Miale Trent Mick +Stan Mihai Aristotelis Mikropoulos Damien Miller Chad Miller Modified: python/branches/release27-maint/Misc/NEWS ============================================================================== --- python/branches/release27-maint/Misc/NEWS (original) +++ python/branches/release27-maint/Misc/NEWS Mon Jan 31 22:47:45 2011 @@ -37,6 +37,9 @@ Library ------- +- Issue #8275: Fix passing of callback arguments with ctypes under Win64. + Patch by Stan Mihai. + - Issue #10940: Workaround an IDLE hang on Mac OS X 10.6 when using the menu accelerators for Open Module, Go to Line, and New Indent Width. The accelerators still work but no longer appear in the menu items. Modified: python/branches/release27-maint/Modules/_ctypes/_ctypes_test.c ============================================================================== --- python/branches/release27-maint/Modules/_ctypes/_ctypes_test.c (original) +++ python/branches/release27-maint/Modules/_ctypes/_ctypes_test.c Mon Jan 31 22:47:45 2011 @@ -25,6 +25,20 @@ /* some functions handy for testing */ +EXPORT(int) +_testfunc_cbk_reg_int(int a, int b, int c, int d, int e, + int (*func)(int, int, int, int, int)) +{ + return func(a*a, b*b, c*c, d*d, e*e); +} + +EXPORT(double) +_testfunc_cbk_reg_double(double a, double b, double c, double d, double e, + double (*func)(double, double, double, double, double)) +{ + return func(a*a, b*b, c*c, d*d, e*e); +} + EXPORT(void)testfunc_array(int values[4]) { printf("testfunc_array %d %d %d %d\n", Modified: python/branches/release27-maint/Modules/_ctypes/libffi_msvc/ffi.c ============================================================================== --- python/branches/release27-maint/Modules/_ctypes/libffi_msvc/ffi.c (original) +++ python/branches/release27-maint/Modules/_ctypes/libffi_msvc/ffi.c Mon Jan 31 22:47:45 2011 @@ -380,7 +380,7 @@ short bytes; char *tramp; #ifdef _WIN64 - int mask; + int mask = 0; #endif FFI_ASSERT (cif->abi == FFI_SYSV);